v / thirdparty / libgc
Raw file | 31367 loc (31366 sloc) | 968.61 KB | Latest commit hash 775c4c34b
1/*
2 * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
3 * Copyright (c) 1996 by Silicon Graphics. All rights reserved.
4 * Copyright (c) 1998 by Fergus Henderson. All rights reserved.
5 * Copyright (c) 2000-2009 by Hewlett-Packard Development Company.
6 * All rights reserved.
7 * Copyright (c) 2009-2018 Ivan Maidanski
8 *
9 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
10 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
11 *
12 * Permission is hereby granted to use or copy this program
13 * for any purpose, provided the above notices are retained on all copies.
14 * Permission to modify the code and to distribute modified code is granted,
15 * provided the above notices are retained, and a notice that the code was
16 * modified is included with the above copyright notice.
17 */
18
19#ifndef __cplusplus
20#define GC_INNER STATIC
21#define GC_EXTERN GC_INNER
22#endif
23#ifndef GC_DBG_MLC_H
24#define GC_DBG_MLC_H
25#ifndef GC_PRIVATE_H
26#define GC_PRIVATE_H
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30#if !defined(GC_BUILD) && !defined(NOT_GCBUILD)
31#define GC_BUILD
32#endif
33#if (defined(__linux__) || defined(__GLIBC__) || defined(__GNU__) \
34 || (defined(__CYGWIN__) && (defined(GC_THREADS) || !defined(USE_MMAP)))) \
35 && !defined(_GNU_SOURCE)
36#define _GNU_SOURCE 1
37#endif
38#if defined(__INTERIX) && !defined(_ALL_SOURCE)
39#define _ALL_SOURCE 1
40#endif
41#if (defined(DGUX) && defined(GC_THREADS) || defined(DGUX386_THREADS) \
42 || defined(GC_DGUX386_THREADS)) && !defined(_USING_POSIX4A_DRAFT10)
43#define _USING_POSIX4A_DRAFT10 1
44#endif
45#if defined(__MINGW32__) && !defined(__MINGW_EXCPT_DEFINE_PSDK) \
46 && defined(__i386__) && defined(GC_EXTERN)
47#define __MINGW_EXCPT_DEFINE_PSDK 1
48#endif
49#if defined(NO_DEBUGGING) && !defined(GC_ASSERTIONS) && !defined(NDEBUG)
50#define NDEBUG 1
51#endif
52#ifndef GC_H
53#ifndef GC_H
54#define GC_H
55#if (defined(WIN64) && !defined(_WIN64)) && defined(_MSC_VER)
56#pragma message("Warning: Expecting _WIN64 for x64 targets! Notice the leading underscore!")
57#endif
58#if defined(GC_H)
59#define GC_TMP_VERSION_MAJOR 8
60#define GC_TMP_VERSION_MINOR 2
61#define GC_TMP_VERSION_MICRO 0
62#ifdef GC_VERSION_MAJOR
63#if GC_TMP_VERSION_MAJOR != GC_VERSION_MAJOR \
64 || GC_TMP_VERSION_MINOR != GC_VERSION_MINOR \
65 || GC_TMP_VERSION_MICRO != GC_VERSION_MICRO
66#error Inconsistent version info. Check README.md, include/gc_version.h and configure.ac.
67#endif
68#else
69#define GC_VERSION_MAJOR GC_TMP_VERSION_MAJOR
70#define GC_VERSION_MINOR GC_TMP_VERSION_MINOR
71#define GC_VERSION_MICRO GC_TMP_VERSION_MICRO
72#endif
73#endif
74#if defined(GC_H)
75#if defined(__GNUC__) && defined(__GNUC_MINOR__)
76#define GC_GNUC_PREREQ(major, minor) \
77 ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((major) << 16) + (minor))
78#else
79#define GC_GNUC_PREREQ(major, minor) 0
80#endif
81#if defined(SOLARIS_THREADS) || defined(_SOLARIS_THREADS) \
82 || defined(_SOLARIS_PTHREADS) || defined(GC_SOLARIS_PTHREADS)
83#ifndef GC_SOLARIS_THREADS
84#define GC_SOLARIS_THREADS
85#endif
86#endif
87#if defined(IRIX_THREADS)
88#define GC_IRIX_THREADS
89#endif
90#if defined(DGUX_THREADS) && !defined(GC_DGUX386_THREADS)
91#define GC_DGUX386_THREADS
92#endif
93#if defined(AIX_THREADS)
94#define GC_AIX_THREADS
95#endif
96#if defined(HPUX_THREADS)
97#define GC_HPUX_THREADS
98#endif
99#if defined(OSF1_THREADS)
100#define GC_OSF1_THREADS
101#endif
102#if defined(LINUX_THREADS)
103#define GC_LINUX_THREADS
104#endif
105#if defined(WIN32_THREADS)
106#define GC_WIN32_THREADS
107#endif
108#if defined(RTEMS_THREADS)
109#define GC_RTEMS_PTHREADS
110#endif
111#if defined(USE_LD_WRAP)
112#define GC_USE_LD_WRAP
113#endif
114#if defined(GC_WIN32_PTHREADS) && !defined(GC_WIN32_THREADS)
115#define GC_WIN32_THREADS
116#endif
117#if defined(GC_AIX_THREADS) || defined(GC_DARWIN_THREADS) \
118 || defined(GC_DGUX386_THREADS) || defined(GC_FREEBSD_THREADS) \
119 || defined(GC_HPUX_THREADS) \
120 || defined(GC_IRIX_THREADS) || defined(GC_LINUX_THREADS) \
121 || defined(GC_NETBSD_THREADS) || defined(GC_OPENBSD_THREADS) \
122 || defined(GC_OSF1_THREADS) || defined(GC_SOLARIS_THREADS) \
123 || defined(GC_WIN32_THREADS) || defined(GC_RTEMS_PTHREADS)
124#ifndef GC_THREADS
125#define GC_THREADS
126#endif
127#elif defined(GC_THREADS)
128#if defined(__linux__)
129#define GC_LINUX_THREADS
130#elif defined(__OpenBSD__)
131#define GC_OPENBSD_THREADS
132#elif defined(_PA_RISC1_1) || defined(_PA_RISC2_0) || defined(hppa) \
133 || defined(__HPPA) || (defined(__ia64) && defined(_HPUX_SOURCE))
134#define GC_HPUX_THREADS
135#elif defined(__HAIKU__)
136#define GC_HAIKU_THREADS
137#elif (defined(__DragonFly__) || defined(__FreeBSD_kernel__) \
138 || defined(__FreeBSD__)) && !defined(GC_NO_FREEBSD)
139#define GC_FREEBSD_THREADS
140#elif defined(__NetBSD__)
141#define GC_NETBSD_THREADS
142#elif defined(__alpha) || defined(__alpha__)
143#define GC_OSF1_THREADS
144#elif (defined(mips) || defined(__mips) || defined(_mips)) \
145 && !(defined(nec_ews) || defined(_nec_ews) \
146 || defined(ultrix) || defined(__ultrix))
147#define GC_IRIX_THREADS
148#elif defined(__sparc) \
149 || ((defined(sun) || defined(__sun)) \
150 && (defined(i386) || defined(__i386__) \
151 || defined(__amd64) || defined(__amd64__)))
152#define GC_SOLARIS_THREADS
153#elif defined(__APPLE__) && defined(__MACH__)
154#define GC_DARWIN_THREADS
155#endif
156#if defined(DGUX) && (defined(i386) || defined(__i386__))
157#define GC_DGUX386_THREADS
158#endif
159#if defined(_AIX)
160#define GC_AIX_THREADS
161#endif
162#if (defined(_WIN32) || defined(_MSC_VER) || defined(__BORLANDC__) \
163 || defined(__CYGWIN32__) || defined(__CYGWIN__) || defined(__CEGCC__) \
164 || defined(_WIN32_WCE) || defined(__MINGW32__)) \
165 && !defined(GC_WIN32_THREADS)
166#define GC_WIN32_THREADS
167#endif
168#if defined(__rtems__) && (defined(i386) || defined(__i386__))
169#define GC_RTEMS_PTHREADS
170#endif
171#endif
172#undef GC_PTHREADS
173#if (!defined(GC_WIN32_THREADS) || defined(GC_WIN32_PTHREADS) \
174 || defined(__CYGWIN32__) || defined(__CYGWIN__)) && defined(GC_THREADS) \
175 && !defined(NN_PLATFORM_CTR) && !defined(NN_BUILD_TARGET_PLATFORM_NX)
176#define GC_PTHREADS
177#endif
178#if !defined(_PTHREADS) && defined(GC_NETBSD_THREADS)
179#define _PTHREADS
180#endif
181#if defined(GC_DGUX386_THREADS) && !defined(_POSIX4A_DRAFT10_SOURCE)
182#define _POSIX4A_DRAFT10_SOURCE 1
183#endif
184#if !defined(_REENTRANT) && defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS)
185#define _REENTRANT 1
186#endif
187#define __GC
188#if !defined(_WIN32_WCE) || defined(__GNUC__)
189#include <stddef.h>
190#if defined(__MINGW32__) && !defined(_WIN32_WCE)
191#include <stdint.h>
192#endif
193#else
194#include <stdlib.h>
195#ifndef _PTRDIFF_T_DEFINED
196#define _PTRDIFF_T_DEFINED
197 typedef long ptrdiff_t;
198#endif
199#endif
200#if !defined(GC_NOT_DLL) && !defined(GC_DLL) \
201 && ((defined(_DLL) && !defined(__GNUC__)) \
202 || (defined(DLL_EXPORT) && defined(GC_BUILD)))
203#define GC_DLL
204#endif
205#if defined(GC_DLL) && !defined(GC_API)
206#if defined(__CEGCC__)
207#if defined(GC_BUILD)
208#define GC_API __declspec(dllexport)
209#else
210#define GC_API __declspec(dllimport)
211#endif
212#elif defined(__MINGW32__)
213#if defined(__cplusplus) && defined(GC_BUILD)
214#define GC_API extern __declspec(dllexport)
215#elif defined(GC_BUILD) || defined(__MINGW32_DELAY_LOAD__)
216#define GC_API __declspec(dllexport)
217#else
218#define GC_API extern __declspec(dllimport)
219#endif
220#elif defined(_MSC_VER) || defined(__DMC__) || defined(__BORLANDC__) \
221 || defined(__CYGWIN__)
222#ifdef GC_BUILD
223#define GC_API extern __declspec(dllexport)
224#else
225#define GC_API __declspec(dllimport)
226#endif
227#elif defined(__WATCOMC__)
228#ifdef GC_BUILD
229#define GC_API extern __declspec(dllexport)
230#else
231#define GC_API extern __declspec(dllimport)
232#endif
233#elif defined(__SYMBIAN32__)
234#ifdef GC_BUILD
235#define GC_API extern EXPORT_C
236#else
237#define GC_API extern IMPORT_C
238#endif
239#elif defined(__GNUC__)
240#if defined(GC_BUILD) && !defined(GC_NO_VISIBILITY) \
241 && (GC_GNUC_PREREQ(4, 0) || defined(GC_VISIBILITY_HIDDEN_SET))
242#define GC_API extern __attribute__((__visibility__("default")))
243#endif
244#endif
245#endif
246#ifndef GC_API
247#define GC_API extern
248#endif
249#ifndef GC_CALL
250#define GC_CALL
251#endif
252#ifndef GC_CALLBACK
253#define GC_CALLBACK GC_CALL
254#endif
255#ifndef GC_ATTR_MALLOC
256#ifdef GC_OOM_FUNC_RETURNS_ALIAS
257#define GC_ATTR_MALLOC
258#elif GC_GNUC_PREREQ(3, 1)
259#define GC_ATTR_MALLOC __attribute__((__malloc__))
260#elif defined(_MSC_VER) && (_MSC_VER >= 1900) && !defined(__EDG__)
261#define GC_ATTR_MALLOC \
262 __declspec(allocator) __declspec(noalias) __declspec(restrict)
263#elif defined(_MSC_VER) && _MSC_VER >= 1400
264#define GC_ATTR_MALLOC __declspec(noalias) __declspec(restrict)
265#else
266#define GC_ATTR_MALLOC
267#endif
268#endif
269#ifndef GC_ATTR_ALLOC_SIZE
270#undef GC_ATTR_CALLOC_SIZE
271#ifdef __clang__
272#if __has_attribute(__alloc_size__)
273#define GC_ATTR_ALLOC_SIZE(argnum) __attribute__((__alloc_size__(argnum)))
274#define GC_ATTR_CALLOC_SIZE(n, s) __attribute__((__alloc_size__(n, s)))
275#else
276#define GC_ATTR_ALLOC_SIZE(argnum)
277#endif
278#elif GC_GNUC_PREREQ(4, 3) && !defined(__ICC)
279#define GC_ATTR_ALLOC_SIZE(argnum) __attribute__((__alloc_size__(argnum)))
280#define GC_ATTR_CALLOC_SIZE(n, s) __attribute__((__alloc_size__(n, s)))
281#else
282#define GC_ATTR_ALLOC_SIZE(argnum)
283#endif
284#endif
285#ifndef GC_ATTR_CALLOC_SIZE
286#define GC_ATTR_CALLOC_SIZE(n, s)
287#endif
288#ifndef GC_ATTR_NONNULL
289#if GC_GNUC_PREREQ(4, 0)
290#define GC_ATTR_NONNULL(argnum) __attribute__((__nonnull__(argnum)))
291#else
292#define GC_ATTR_NONNULL(argnum)
293#endif
294#endif
295#ifndef GC_ATTR_CONST
296#if GC_GNUC_PREREQ(4, 0)
297#define GC_ATTR_CONST __attribute__((__const__))
298#else
299#define GC_ATTR_CONST
300#endif
301#endif
302#ifndef GC_ATTR_DEPRECATED
303#ifdef GC_BUILD
304#undef GC_ATTR_DEPRECATED
305#define GC_ATTR_DEPRECATED
306#elif GC_GNUC_PREREQ(4, 0)
307#define GC_ATTR_DEPRECATED __attribute__((__deprecated__))
308#elif defined(_MSC_VER) && _MSC_VER >= 1200
309#define GC_ATTR_DEPRECATED __declspec(deprecated)
310#else
311#define GC_ATTR_DEPRECATED
312#endif
313#endif
314#if defined(__sgi) && !defined(__GNUC__) && _COMPILER_VERSION >= 720
315#define GC_ADD_CALLER
316#define GC_RETURN_ADDR (GC_word)__return_address
317#endif
318#if defined(__linux__) || defined(__GLIBC__)
319#if !defined(__native_client__)
320#include <features.h>
321#endif
322#if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2) \
323 && !defined(__ia64__) \
324 && !defined(GC_MISSING_EXECINFO_H) \
325 && !defined(GC_HAVE_BUILTIN_BACKTRACE)
326#define GC_HAVE_BUILTIN_BACKTRACE
327#endif
328#if defined(__i386__) || defined(__amd64__) || defined(__x86_64__)
329#define GC_CAN_SAVE_CALL_STACKS
330#endif
331#endif
332#if defined(_MSC_VER) && _MSC_VER >= 1200 \
333 && !defined(_AMD64_) && !defined(_M_X64) && !defined(_WIN32_WCE) \
334 && !defined(GC_HAVE_NO_BUILTIN_BACKTRACE) \
335 && !defined(GC_HAVE_BUILTIN_BACKTRACE)
336#define GC_HAVE_BUILTIN_BACKTRACE
337#endif
338#if defined(GC_HAVE_BUILTIN_BACKTRACE) && !defined(GC_CAN_SAVE_CALL_STACKS)
339#define GC_CAN_SAVE_CALL_STACKS
340#endif
341#if defined(__sparc__)
342#define GC_CAN_SAVE_CALL_STACKS
343#endif
344#if (defined(__linux__) || defined(__DragonFly__) || defined(__FreeBSD__) \
345 || defined(__FreeBSD_kernel__) || defined(__HAIKU__) \
346 || defined(__NetBSD__) || defined(__OpenBSD__) \
347 || defined(HOST_ANDROID) || defined(__ANDROID__)) \
348 && !defined(GC_CAN_SAVE_CALL_STACKS)
349#define GC_ADD_CALLER
350#if GC_GNUC_PREREQ(2, 95)
351#define GC_RETURN_ADDR (GC_word)__builtin_return_address(0)
352#if GC_GNUC_PREREQ(4, 0) && (defined(__i386__) || defined(__amd64__) \
353 || defined(__x86_64__) ) \
354 && !defined(GC_NO_RETURN_ADDR_PARENT)
355#define GC_HAVE_RETURN_ADDR_PARENT
356#define GC_RETURN_ADDR_PARENT \
357 (GC_word)__builtin_extract_return_addr(__builtin_return_address(1))
358#endif
359#else
360#define GC_RETURN_ADDR 0
361#endif
362#endif
363#ifdef GC_PTHREADS
364#if (defined(GC_DARWIN_THREADS) || defined(GC_WIN32_PTHREADS) \
365 || defined(__native_client__) || defined(GC_RTEMS_PTHREADS)) \
366 && !defined(GC_NO_DLOPEN)
367#define GC_NO_DLOPEN
368#endif
369#if (defined(GC_DARWIN_THREADS) || defined(GC_WIN32_PTHREADS) \
370 || defined(GC_OPENBSD_THREADS) || defined(__native_client__)) \
371 && !defined(GC_NO_PTHREAD_SIGMASK)
372#define GC_NO_PTHREAD_SIGMASK
373#endif
374#if defined(__native_client__)
375#ifndef GC_PTHREAD_CREATE_CONST
376#define GC_PTHREAD_CREATE_CONST
377#endif
378#ifndef GC_HAVE_PTHREAD_EXIT
379#define GC_HAVE_PTHREAD_EXIT
380#define GC_PTHREAD_EXIT_ATTRIBUTE
381#endif
382#endif
383#if !defined(GC_HAVE_PTHREAD_EXIT) \
384 && !defined(HOST_ANDROID) && !defined(__ANDROID__) \
385 && (defined(GC_LINUX_THREADS) || defined(GC_SOLARIS_THREADS))
386#define GC_HAVE_PTHREAD_EXIT
387#if GC_GNUC_PREREQ(2, 7)
388#define GC_PTHREAD_EXIT_ATTRIBUTE __attribute__((__noreturn__))
389#elif defined(__NORETURN)
390#define GC_PTHREAD_EXIT_ATTRIBUTE __NORETURN
391#else
392#define GC_PTHREAD_EXIT_ATTRIBUTE
393#endif
394#endif
395#if (!defined(GC_HAVE_PTHREAD_EXIT) || defined(__native_client__)) \
396 && !defined(GC_NO_PTHREAD_CANCEL)
397#define GC_NO_PTHREAD_CANCEL
398#endif
399#endif
400#ifdef __cplusplus
401#ifndef GC_ATTR_EXPLICIT
402#if __cplusplus >= 201103L && !defined(__clang__) || _MSVC_LANG >= 201103L \
403 || defined(CPPCHECK)
404#define GC_ATTR_EXPLICIT explicit
405#else
406#define GC_ATTR_EXPLICIT
407#endif
408#endif
409#ifndef GC_NOEXCEPT
410#if defined(__DMC__) || (defined(__BORLANDC__) \
411 && (defined(_RWSTD_NO_EXCEPTIONS) || defined(_RWSTD_NO_EX_SPEC))) \
412 || (defined(_MSC_VER) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS) \
413 || (defined(__WATCOMC__) && !defined(_CPPUNWIND))
414#define GC_NOEXCEPT
415#ifndef GC_NEW_ABORTS_ON_OOM
416#define GC_NEW_ABORTS_ON_OOM
417#endif
418#elif __cplusplus >= 201103L || _MSVC_LANG >= 201103L
419#define GC_NOEXCEPT noexcept
420#else
421#define GC_NOEXCEPT throw()
422#endif
423#endif
424#endif
425#endif
426#ifdef __cplusplus
427 extern "C" {
428#endif
429typedef void * GC_PTR;
430#ifdef _WIN64
431#if defined(__int64) && !defined(CPPCHECK)
432 typedef unsigned __int64 GC_word;
433 typedef __int64 GC_signed_word;
434#else
435 typedef unsigned long long GC_word;
436 typedef long long GC_signed_word;
437#endif
438#else
439 typedef unsigned long GC_word;
440 typedef long GC_signed_word;
441#endif
442GC_API unsigned GC_CALL GC_get_version(void);
443GC_API GC_ATTR_DEPRECATED GC_word GC_gc_no;
444GC_API GC_word GC_CALL GC_get_gc_no(void);
445#ifdef GC_THREADS
446 GC_API GC_ATTR_DEPRECATED int GC_parallel;
447 GC_API int GC_CALL GC_get_parallel(void);
448 GC_API void GC_CALL GC_set_markers_count(unsigned);
449#endif
450typedef void * (GC_CALLBACK * GC_oom_func)(size_t );
451GC_API GC_ATTR_DEPRECATED GC_oom_func GC_oom_fn;
452GC_API void GC_CALL GC_set_oom_fn(GC_oom_func) GC_ATTR_NONNULL(1);
453GC_API GC_oom_func GC_CALL GC_get_oom_fn(void);
454typedef void (GC_CALLBACK * GC_on_heap_resize_proc)(GC_word );
455GC_API GC_ATTR_DEPRECATED GC_on_heap_resize_proc GC_on_heap_resize;
456GC_API void GC_CALL GC_set_on_heap_resize(GC_on_heap_resize_proc);
457GC_API GC_on_heap_resize_proc GC_CALL GC_get_on_heap_resize(void);
458typedef enum {
459 GC_EVENT_START ,
460 GC_EVENT_MARK_START,
461 GC_EVENT_MARK_END,
462 GC_EVENT_RECLAIM_START,
463 GC_EVENT_RECLAIM_END,
464 GC_EVENT_END ,
465 GC_EVENT_PRE_STOP_WORLD ,
466 GC_EVENT_POST_STOP_WORLD ,
467 GC_EVENT_PRE_START_WORLD ,
468 GC_EVENT_POST_START_WORLD ,
469 GC_EVENT_THREAD_SUSPENDED,
470 GC_EVENT_THREAD_UNSUSPENDED
471} GC_EventType;
472typedef void (GC_CALLBACK * GC_on_collection_event_proc)(GC_EventType);
473GC_API void GC_CALL GC_set_on_collection_event(GC_on_collection_event_proc);
474GC_API GC_on_collection_event_proc GC_CALL GC_get_on_collection_event(void);
475#if defined(GC_THREADS) || (defined(GC_BUILD) && defined(NN_PLATFORM_CTR))
476 typedef void (GC_CALLBACK * GC_on_thread_event_proc)(GC_EventType,
477 void * );
478 GC_API void GC_CALL GC_set_on_thread_event(GC_on_thread_event_proc);
479 GC_API GC_on_thread_event_proc GC_CALL GC_get_on_thread_event(void);
480#endif
481GC_API GC_ATTR_DEPRECATED int GC_find_leak;
482GC_API void GC_CALL GC_set_find_leak(int);
483GC_API int GC_CALL GC_get_find_leak(void);
484GC_API GC_ATTR_DEPRECATED int GC_all_interior_pointers;
485GC_API void GC_CALL GC_set_all_interior_pointers(int);
486GC_API int GC_CALL GC_get_all_interior_pointers(void);
487GC_API GC_ATTR_DEPRECATED int GC_finalize_on_demand;
488GC_API void GC_CALL GC_set_finalize_on_demand(int);
489GC_API int GC_CALL GC_get_finalize_on_demand(void);
490GC_API GC_ATTR_DEPRECATED int GC_java_finalization;
491GC_API void GC_CALL GC_set_java_finalization(int);
492GC_API int GC_CALL GC_get_java_finalization(void);
493typedef void (GC_CALLBACK * GC_finalizer_notifier_proc)(void);
494GC_API GC_ATTR_DEPRECATED GC_finalizer_notifier_proc GC_finalizer_notifier;
495GC_API void GC_CALL GC_set_finalizer_notifier(GC_finalizer_notifier_proc);
496GC_API GC_finalizer_notifier_proc GC_CALL GC_get_finalizer_notifier(void);
497GC_API
498#ifndef GC_DONT_GC
499 GC_ATTR_DEPRECATED
500#endif
501 int GC_dont_gc;
502GC_API GC_ATTR_DEPRECATED int GC_dont_expand;
503GC_API void GC_CALL GC_set_dont_expand(int);
504GC_API int GC_CALL GC_get_dont_expand(void);
505GC_API GC_ATTR_DEPRECATED int GC_use_entire_heap;
506GC_API GC_ATTR_DEPRECATED int GC_full_freq;
507GC_API void GC_CALL GC_set_full_freq(int);
508GC_API int GC_CALL GC_get_full_freq(void);
509GC_API GC_ATTR_DEPRECATED GC_word GC_non_gc_bytes;
510GC_API void GC_CALL GC_set_non_gc_bytes(GC_word);
511GC_API GC_word GC_CALL GC_get_non_gc_bytes(void);
512GC_API GC_ATTR_DEPRECATED int GC_no_dls;
513GC_API void GC_CALL GC_set_no_dls(int);
514GC_API int GC_CALL GC_get_no_dls(void);
515GC_API GC_ATTR_DEPRECATED GC_word GC_free_space_divisor;
516GC_API void GC_CALL GC_set_free_space_divisor(GC_word);
517GC_API GC_word GC_CALL GC_get_free_space_divisor(void);
518GC_API GC_ATTR_DEPRECATED GC_word GC_max_retries;
519GC_API void GC_CALL GC_set_max_retries(GC_word);
520GC_API GC_word GC_CALL GC_get_max_retries(void);
521GC_API GC_ATTR_DEPRECATED char *GC_stackbottom;
522GC_API GC_ATTR_DEPRECATED int GC_dont_precollect;
523GC_API void GC_CALL GC_set_dont_precollect(int);
524GC_API int GC_CALL GC_get_dont_precollect(void);
525GC_API GC_ATTR_DEPRECATED unsigned long GC_time_limit;
526#define GC_TIME_UNLIMITED 999999
527GC_API void GC_CALL GC_set_time_limit(unsigned long);
528GC_API unsigned long GC_CALL GC_get_time_limit(void);
529struct GC_timeval_s {
530 unsigned long tv_ms;
531 unsigned long tv_nsec;
532};
533GC_API void GC_CALL GC_set_time_limit_tv(struct GC_timeval_s);
534GC_API struct GC_timeval_s GC_CALL GC_get_time_limit_tv(void);
535GC_API void GC_CALL GC_set_allocd_bytes_per_finalizer(GC_word);
536GC_API GC_word GC_CALL GC_get_allocd_bytes_per_finalizer(void);
537GC_API void GC_CALL GC_start_performance_measurement(void);
538GC_API unsigned long GC_CALL GC_get_full_gc_total_time(void);
539GC_API void GC_CALL GC_set_pages_executable(int);
540GC_API int GC_CALL GC_get_pages_executable(void);
541GC_API void GC_CALL GC_set_min_bytes_allocd(size_t);
542GC_API size_t GC_CALL GC_get_min_bytes_allocd(void);
543GC_API void GC_CALL GC_set_rate(int);
544GC_API int GC_CALL GC_get_rate(void);
545GC_API void GC_CALL GC_set_max_prior_attempts(int);
546GC_API int GC_CALL GC_get_max_prior_attempts(void);
547GC_API void GC_CALL GC_set_disable_automatic_collection(int);
548GC_API int GC_CALL GC_get_disable_automatic_collection(void);
549GC_API void GC_CALL GC_set_handle_fork(int);
550GC_API void GC_CALL GC_atfork_prepare(void);
551GC_API void GC_CALL GC_atfork_parent(void);
552GC_API void GC_CALL GC_atfork_child(void);
553GC_API void GC_CALL GC_init(void);
554GC_API int GC_CALL GC_is_init_called(void);
555GC_API void GC_CALL GC_deinit(void);
556GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
557 GC_malloc(size_t );
558GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
559 GC_malloc_atomic(size_t );
560GC_API GC_ATTR_MALLOC char * GC_CALL GC_strdup(const char *);
561GC_API GC_ATTR_MALLOC char * GC_CALL
562 GC_strndup(const char *, size_t) GC_ATTR_NONNULL(1);
563GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
564 GC_malloc_uncollectable(size_t );
565GC_API GC_ATTR_DEPRECATED void * GC_CALL GC_malloc_stubborn(size_t);
566GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(2) void * GC_CALL
567 GC_memalign(size_t , size_t );
568GC_API int GC_CALL GC_posix_memalign(void ** , size_t ,
569 size_t ) GC_ATTR_NONNULL(1);
570GC_API void GC_CALL GC_free(void *);
571#define GC_MALLOC_STUBBORN(sz) GC_MALLOC(sz)
572#define GC_NEW_STUBBORN(t) GC_NEW(t)
573#define GC_CHANGE_STUBBORN(p) GC_change_stubborn(p)
574GC_API GC_ATTR_DEPRECATED void GC_CALL GC_change_stubborn(const void *);
575GC_API void GC_CALL GC_end_stubborn_change(const void *) GC_ATTR_NONNULL(1);
576GC_API void * GC_CALL GC_base(void * );
577GC_API int GC_CALL GC_is_heap_ptr(const void *);
578GC_API size_t GC_CALL GC_size(const void * ) GC_ATTR_NONNULL(1);
579GC_API void * GC_CALL GC_realloc(void * ,
580 size_t )
581 GC_ATTR_ALLOC_SIZE(2);
582GC_API int GC_CALL GC_expand_hp(size_t );
583GC_API void GC_CALL GC_set_max_heap_size(GC_word );
584GC_API void GC_CALL GC_exclude_static_roots(void * ,
585 void * );
586GC_API void GC_CALL GC_clear_exclusion_table(void);
587GC_API void GC_CALL GC_clear_roots(void);
588GC_API void GC_CALL GC_add_roots(void * ,
589 void * );
590GC_API void GC_CALL GC_remove_roots(void * ,
591 void * );
592GC_API void GC_CALL GC_register_displacement(size_t );
593GC_API void GC_CALL GC_debug_register_displacement(size_t );
594GC_API void GC_CALL GC_gcollect(void);
595GC_API void GC_CALL GC_gcollect_and_unmap(void);
596typedef int (GC_CALLBACK * GC_stop_func)(void);
597GC_API int GC_CALL GC_try_to_collect(GC_stop_func )
598 GC_ATTR_NONNULL(1);
599GC_API void GC_CALL GC_set_stop_func(GC_stop_func )
600 GC_ATTR_NONNULL(1);
601GC_API GC_stop_func GC_CALL GC_get_stop_func(void);
602GC_API size_t GC_CALL GC_get_heap_size(void);
603GC_API size_t GC_CALL GC_get_free_bytes(void);
604GC_API size_t GC_CALL GC_get_unmapped_bytes(void);
605GC_API size_t GC_CALL GC_get_bytes_since_gc(void);
606GC_API size_t GC_CALL GC_get_expl_freed_bytes_since_gc(void);
607GC_API size_t GC_CALL GC_get_total_bytes(void);
608GC_API size_t GC_CALL GC_get_obtained_from_os_bytes(void);
609GC_API void GC_CALL GC_get_heap_usage_safe(GC_word * ,
610 GC_word * ,
611 GC_word * ,
612 GC_word * ,
613 GC_word * );
614struct GC_prof_stats_s {
615 GC_word heapsize_full;
616 GC_word free_bytes_full;
617 GC_word unmapped_bytes;
618 GC_word bytes_allocd_since_gc;
619 GC_word allocd_bytes_before_gc;
620 GC_word non_gc_bytes;
621 GC_word gc_no;
622 GC_word markers_m1;
623 GC_word bytes_reclaimed_since_gc;
624 GC_word reclaimed_bytes_before_gc;
625 GC_word expl_freed_bytes_since_gc;
626 GC_word obtained_from_os_bytes;
627};
628GC_API size_t GC_CALL GC_get_prof_stats(struct GC_prof_stats_s *,
629 size_t );
630#ifdef GC_THREADS
631 GC_API size_t GC_CALL GC_get_prof_stats_unsafe(struct GC_prof_stats_s *,
632 size_t );
633#endif
634GC_API size_t GC_CALL GC_get_size_map_at(int i);
635GC_API size_t GC_CALL GC_get_memory_use(void);
636GC_API void GC_CALL GC_disable(void);
637GC_API int GC_CALL GC_is_disabled(void);
638GC_API void GC_CALL GC_enable(void);
639GC_API void GC_CALL GC_set_manual_vdb_allowed(int);
640GC_API int GC_CALL GC_get_manual_vdb_allowed(void);
641GC_API void GC_CALL GC_enable_incremental(void);
642GC_API int GC_CALL GC_is_incremental_mode(void);
643#define GC_PROTECTS_POINTER_HEAP 1
644#define GC_PROTECTS_PTRFREE_HEAP 2
645#define GC_PROTECTS_STATIC_DATA 4
646#define GC_PROTECTS_STACK 8
647#define GC_PROTECTS_NONE 0
648GC_API int GC_CALL GC_incremental_protection_needs(void);
649GC_API void GC_CALL GC_start_incremental_collection(void);
650GC_API int GC_CALL GC_collect_a_little(void);
651GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
652 GC_malloc_ignore_off_page(size_t );
653GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
654 GC_malloc_atomic_ignore_off_page(size_t );
655#ifdef GC_ADD_CALLER
656#define GC_EXTRAS GC_RETURN_ADDR, __FILE__, __LINE__
657#define GC_EXTRA_PARAMS GC_word ra, const char * s, int i
658#else
659#define GC_EXTRAS __FILE__, __LINE__
660#define GC_EXTRA_PARAMS const char * s, int i
661#endif
662GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
663 GC_malloc_atomic_uncollectable(size_t );
664GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
665 GC_debug_malloc_atomic_uncollectable(size_t, GC_EXTRA_PARAMS);
666GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
667 GC_debug_malloc(size_t , GC_EXTRA_PARAMS);
668GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
669 GC_debug_malloc_atomic(size_t , GC_EXTRA_PARAMS);
670GC_API GC_ATTR_MALLOC char * GC_CALL
671 GC_debug_strdup(const char *, GC_EXTRA_PARAMS);
672GC_API GC_ATTR_MALLOC char * GC_CALL
673 GC_debug_strndup(const char *, size_t, GC_EXTRA_PARAMS)
674 GC_ATTR_NONNULL(1);
675GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
676 GC_debug_malloc_uncollectable(size_t ,
677 GC_EXTRA_PARAMS);
678GC_API GC_ATTR_DEPRECATED void * GC_CALL
679 GC_debug_malloc_stubborn(size_t , GC_EXTRA_PARAMS);
680GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
681 GC_debug_malloc_ignore_off_page(size_t ,
682 GC_EXTRA_PARAMS);
683GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
684 GC_debug_malloc_atomic_ignore_off_page(size_t ,
685 GC_EXTRA_PARAMS);
686GC_API void GC_CALL GC_debug_free(void *);
687GC_API void * GC_CALL GC_debug_realloc(void * ,
688 size_t , GC_EXTRA_PARAMS)
689 GC_ATTR_ALLOC_SIZE(2);
690GC_API GC_ATTR_DEPRECATED void GC_CALL GC_debug_change_stubborn(const void *);
691GC_API void GC_CALL GC_debug_end_stubborn_change(const void *)
692 GC_ATTR_NONNULL(1);
693GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
694 GC_debug_malloc_replacement(size_t );
695GC_API GC_ATTR_ALLOC_SIZE(2) void * GC_CALL
696 GC_debug_realloc_replacement(void * ,
697 size_t );
698#ifdef GC_DEBUG_REPLACEMENT
699#define GC_MALLOC(sz) GC_debug_malloc_replacement(sz)
700#define GC_REALLOC(old, sz) GC_debug_realloc_replacement(old, sz)
701#elif defined(GC_DEBUG)
702#define GC_MALLOC(sz) GC_debug_malloc(sz, GC_EXTRAS)
703#define GC_REALLOC(old, sz) GC_debug_realloc(old, sz, GC_EXTRAS)
704#else
705#define GC_MALLOC(sz) GC_malloc(sz)
706#define GC_REALLOC(old, sz) GC_realloc(old, sz)
707#endif
708#ifdef GC_DEBUG
709#define GC_MALLOC_ATOMIC(sz) GC_debug_malloc_atomic(sz, GC_EXTRAS)
710#define GC_STRDUP(s) GC_debug_strdup(s, GC_EXTRAS)
711#define GC_STRNDUP(s, sz) GC_debug_strndup(s, sz, GC_EXTRAS)
712#define GC_MALLOC_ATOMIC_UNCOLLECTABLE(sz) \
713 GC_debug_malloc_atomic_uncollectable(sz, GC_EXTRAS)
714#define GC_MALLOC_UNCOLLECTABLE(sz) \
715 GC_debug_malloc_uncollectable(sz, GC_EXTRAS)
716#define GC_MALLOC_IGNORE_OFF_PAGE(sz) \
717 GC_debug_malloc_ignore_off_page(sz, GC_EXTRAS)
718#define GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(sz) \
719 GC_debug_malloc_atomic_ignore_off_page(sz, GC_EXTRAS)
720#define GC_FREE(p) GC_debug_free(p)
721#define GC_REGISTER_FINALIZER(p, f, d, of, od) \
722 GC_debug_register_finalizer(p, f, d, of, od)
723#define GC_REGISTER_FINALIZER_IGNORE_SELF(p, f, d, of, od) \
724 GC_debug_register_finalizer_ignore_self(p, f, d, of, od)
725#define GC_REGISTER_FINALIZER_NO_ORDER(p, f, d, of, od) \
726 GC_debug_register_finalizer_no_order(p, f, d, of, od)
727#define GC_REGISTER_FINALIZER_UNREACHABLE(p, f, d, of, od) \
728 GC_debug_register_finalizer_unreachable(p, f, d, of, od)
729#define GC_END_STUBBORN_CHANGE(p) GC_debug_end_stubborn_change(p)
730#define GC_PTR_STORE_AND_DIRTY(p, q) GC_debug_ptr_store_and_dirty(p, q)
731#define GC_GENERAL_REGISTER_DISAPPEARING_LINK(link, obj) \
732 GC_general_register_disappearing_link(link, \
733 GC_base(( void *)(obj)))
734#define GC_REGISTER_LONG_LINK(link, obj) \
735 GC_register_long_link(link, GC_base(( void *)(obj)))
736#define GC_REGISTER_DISPLACEMENT(n) GC_debug_register_displacement(n)
737#else
738#define GC_MALLOC_ATOMIC(sz) GC_malloc_atomic(sz)
739#define GC_STRDUP(s) GC_strdup(s)
740#define GC_STRNDUP(s, sz) GC_strndup(s, sz)
741#define GC_MALLOC_ATOMIC_UNCOLLECTABLE(sz) GC_malloc_atomic_uncollectable(sz)
742#define GC_MALLOC_UNCOLLECTABLE(sz) GC_malloc_uncollectable(sz)
743#define GC_MALLOC_IGNORE_OFF_PAGE(sz) \
744 GC_malloc_ignore_off_page(sz)
745#define GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(sz) \
746 GC_malloc_atomic_ignore_off_page(sz)
747#define GC_FREE(p) GC_free(p)
748#define GC_REGISTER_FINALIZER(p, f, d, of, od) \
749 GC_register_finalizer(p, f, d, of, od)
750#define GC_REGISTER_FINALIZER_IGNORE_SELF(p, f, d, of, od) \
751 GC_register_finalizer_ignore_self(p, f, d, of, od)
752#define GC_REGISTER_FINALIZER_NO_ORDER(p, f, d, of, od) \
753 GC_register_finalizer_no_order(p, f, d, of, od)
754#define GC_REGISTER_FINALIZER_UNREACHABLE(p, f, d, of, od) \
755 GC_register_finalizer_unreachable(p, f, d, of, od)
756#define GC_END_STUBBORN_CHANGE(p) GC_end_stubborn_change(p)
757#define GC_PTR_STORE_AND_DIRTY(p, q) GC_ptr_store_and_dirty(p, q)
758#define GC_GENERAL_REGISTER_DISAPPEARING_LINK(link, obj) \
759 GC_general_register_disappearing_link(link, obj)
760#define GC_REGISTER_LONG_LINK(link, obj) \
761 GC_register_long_link(link, obj)
762#define GC_REGISTER_DISPLACEMENT(n) GC_register_displacement(n)
763#endif
764#define GC_NEW(t) ((t*)GC_MALLOC(sizeof(t)))
765#define GC_NEW_ATOMIC(t) ((t*)GC_MALLOC_ATOMIC(sizeof(t)))
766#define GC_NEW_UNCOLLECTABLE(t) ((t*)GC_MALLOC_UNCOLLECTABLE(sizeof(t)))
767#ifdef GC_REQUIRE_WCSDUP
768 GC_API GC_ATTR_MALLOC wchar_t * GC_CALL
769 GC_wcsdup(const wchar_t *) GC_ATTR_NONNULL(1);
770 GC_API GC_ATTR_MALLOC wchar_t * GC_CALL
771 GC_debug_wcsdup(const wchar_t *, GC_EXTRA_PARAMS) GC_ATTR_NONNULL(1);
772#ifdef GC_DEBUG
773#define GC_WCSDUP(s) GC_debug_wcsdup(s, GC_EXTRAS)
774#else
775#define GC_WCSDUP(s) GC_wcsdup(s)
776#endif
777#endif
778typedef void (GC_CALLBACK * GC_finalization_proc)(void * ,
779 void * );
780GC_API void GC_CALL GC_register_finalizer(void * ,
781 GC_finalization_proc , void * ,
782 GC_finalization_proc * , void ** )
783 GC_ATTR_NONNULL(1);
784GC_API void GC_CALL GC_debug_register_finalizer(void * ,
785 GC_finalization_proc , void * ,
786 GC_finalization_proc * , void ** )
787 GC_ATTR_NONNULL(1);
788GC_API void GC_CALL GC_register_finalizer_ignore_self(void * ,
789 GC_finalization_proc , void * ,
790 GC_finalization_proc * , void ** )
791 GC_ATTR_NONNULL(1);
792GC_API void GC_CALL GC_debug_register_finalizer_ignore_self(void * ,
793 GC_finalization_proc , void * ,
794 GC_finalization_proc * , void ** )
795 GC_ATTR_NONNULL(1);
796GC_API void GC_CALL GC_register_finalizer_no_order(void * ,
797 GC_finalization_proc , void * ,
798 GC_finalization_proc * , void ** )
799 GC_ATTR_NONNULL(1);
800GC_API void GC_CALL GC_debug_register_finalizer_no_order(void * ,
801 GC_finalization_proc , void * ,
802 GC_finalization_proc * , void ** )
803 GC_ATTR_NONNULL(1);
804GC_API void GC_CALL GC_register_finalizer_unreachable(void * ,
805 GC_finalization_proc , void * ,
806 GC_finalization_proc * , void ** )
807 GC_ATTR_NONNULL(1);
808GC_API void GC_CALL GC_debug_register_finalizer_unreachable(void * ,
809 GC_finalization_proc , void * ,
810 GC_finalization_proc * , void ** )
811 GC_ATTR_NONNULL(1);
812#define GC_NO_MEMORY 2
813GC_API int GC_CALL GC_register_disappearing_link(void ** )
814 GC_ATTR_NONNULL(1);
815GC_API int GC_CALL GC_general_register_disappearing_link(void ** ,
816 const void * )
817 GC_ATTR_NONNULL(1) GC_ATTR_NONNULL(2);
818GC_API int GC_CALL GC_move_disappearing_link(void ** ,
819 void ** )
820 GC_ATTR_NONNULL(2);
821GC_API int GC_CALL GC_unregister_disappearing_link(void ** );
822GC_API int GC_CALL GC_register_long_link(void ** ,
823 const void * )
824 GC_ATTR_NONNULL(1) GC_ATTR_NONNULL(2);
825GC_API int GC_CALL GC_move_long_link(void ** ,
826 void ** )
827 GC_ATTR_NONNULL(2);
828GC_API int GC_CALL GC_unregister_long_link(void ** );
829typedef enum {
830 GC_TOGGLE_REF_DROP,
831 GC_TOGGLE_REF_STRONG,
832 GC_TOGGLE_REF_WEAK
833} GC_ToggleRefStatus;
834typedef GC_ToggleRefStatus (GC_CALLBACK *GC_toggleref_func)(void * );
835GC_API void GC_CALL GC_set_toggleref_func(GC_toggleref_func);
836GC_API GC_toggleref_func GC_CALL GC_get_toggleref_func(void);
837GC_API int GC_CALL GC_toggleref_add(void * , int )
838 GC_ATTR_NONNULL(1);
839typedef void (GC_CALLBACK * GC_await_finalize_proc)(void * );
840GC_API void GC_CALL GC_set_await_finalize_proc(GC_await_finalize_proc);
841GC_API GC_await_finalize_proc GC_CALL GC_get_await_finalize_proc(void);
842GC_API int GC_CALL GC_should_invoke_finalizers(void);
843GC_API int GC_CALL GC_invoke_finalizers(void);
844#if defined(__GNUC__) && !defined(__INTEL_COMPILER)
845#define GC_reachable_here(ptr) \
846 __asm__ __volatile__(" " : : "X"(ptr) : "memory")
847#else
848 GC_API void GC_CALL GC_noop1(GC_word);
849#ifdef LINT2
850#define GC_reachable_here(ptr) GC_noop1(~(GC_word)(ptr)^(~(GC_word)0))
851#else
852#define GC_reachable_here(ptr) GC_noop1((GC_word)(ptr))
853#endif
854#endif
855typedef void (GC_CALLBACK * GC_warn_proc)(char * ,
856 GC_word );
857GC_API void GC_CALL GC_set_warn_proc(GC_warn_proc ) GC_ATTR_NONNULL(1);
858GC_API GC_warn_proc GC_CALL GC_get_warn_proc(void);
859GC_API void GC_CALLBACK GC_ignore_warn_proc(char *, GC_word);
860GC_API void GC_CALL GC_set_log_fd(int);
861typedef void (GC_CALLBACK * GC_abort_func)(const char * );
862GC_API void GC_CALL GC_set_abort_func(GC_abort_func) GC_ATTR_NONNULL(1);
863GC_API GC_abort_func GC_CALL GC_get_abort_func(void);
864GC_API void GC_CALL GC_abort_on_oom(void);
865typedef GC_word GC_hidden_pointer;
866#define GC_HIDE_POINTER(p) (~(GC_hidden_pointer)(p))
867#define GC_REVEAL_POINTER(p) ((void *)GC_HIDE_POINTER(p))
868#if defined(I_HIDE_POINTERS) || defined(GC_I_HIDE_POINTERS)
869#define HIDE_POINTER(p) GC_HIDE_POINTER(p)
870#define REVEAL_POINTER(p) GC_REVEAL_POINTER(p)
871#endif
872#ifdef GC_THREADS
873 GC_API void GC_CALL GC_alloc_lock(void);
874 GC_API void GC_CALL GC_alloc_unlock(void);
875#else
876#define GC_alloc_lock() (void)0
877#define GC_alloc_unlock() (void)0
878#endif
879typedef void * (GC_CALLBACK * GC_fn_type)(void * );
880GC_API void * GC_CALL GC_call_with_alloc_lock(GC_fn_type ,
881 void * ) GC_ATTR_NONNULL(1);
882struct GC_stack_base {
883 void * mem_base;
884#if defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
885 void * reg_base;
886#endif
887};
888typedef void * (GC_CALLBACK * GC_stack_base_func)(
889 struct GC_stack_base * , void * );
890GC_API void * GC_CALL GC_call_with_stack_base(GC_stack_base_func ,
891 void * ) GC_ATTR_NONNULL(1);
892#define GC_SUCCESS 0
893#define GC_DUPLICATE 1
894#define GC_NO_THREADS 2
895#define GC_UNIMPLEMENTED 3
896#define GC_NOT_FOUND 4
897#if defined(GC_DARWIN_THREADS) || defined(GC_WIN32_THREADS)
898 GC_API void GC_CALL GC_use_threads_discovery(void);
899#endif
900#ifdef GC_THREADS
901 GC_API void GC_CALL GC_set_suspend_signal(int);
902 GC_API void GC_CALL GC_set_thr_restart_signal(int);
903 GC_API int GC_CALL GC_get_suspend_signal(void);
904 GC_API int GC_CALL GC_get_thr_restart_signal(void);
905 GC_API void GC_CALL GC_start_mark_threads(void);
906 GC_API void GC_CALL GC_allow_register_threads(void);
907 GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *)
908 GC_ATTR_NONNULL(1);
909 GC_API int GC_CALL GC_thread_is_registered(void);
910 GC_API void GC_CALL GC_register_altstack(void * ,
911 GC_word ,
912 void * ,
913 GC_word );
914 GC_API int GC_CALL GC_unregister_my_thread(void);
915 GC_API void GC_CALL GC_stop_world_external(void);
916 GC_API void GC_CALL GC_start_world_external(void);
917#endif
918GC_API void * GC_CALL GC_do_blocking(GC_fn_type ,
919 void * ) GC_ATTR_NONNULL(1);
920GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type ,
921 void * ) GC_ATTR_NONNULL(1);
922GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *)
923 GC_ATTR_NONNULL(1);
924GC_API void * GC_CALL GC_get_my_stackbottom(struct GC_stack_base *)
925 GC_ATTR_NONNULL(1);
926GC_API void GC_CALL GC_set_stackbottom(void * ,
927 const struct GC_stack_base *)
928 GC_ATTR_NONNULL(2);
929GC_API void * GC_CALL GC_same_obj(void * , void * );
930GC_API void * GC_CALL GC_pre_incr(void **, ptrdiff_t )
931 GC_ATTR_NONNULL(1);
932GC_API void * GC_CALL GC_post_incr(void **, ptrdiff_t )
933 GC_ATTR_NONNULL(1);
934GC_API void * GC_CALL GC_is_visible(void * );
935GC_API void * GC_CALL GC_is_valid_displacement(void * );
936GC_API void GC_CALL GC_dump(void);
937GC_API void GC_CALL GC_dump_named(const char * );
938GC_API void GC_CALL GC_dump_regions(void);
939GC_API void GC_CALL GC_dump_finalization(void);
940#if defined(GC_DEBUG) && defined(__GNUC__)
941#define GC_PTR_ADD3(x, n, type_of_result) \
942 ((type_of_result)GC_same_obj((x)+(n), (x)))
943#define GC_PRE_INCR3(x, n, type_of_result) \
944 ((type_of_result)GC_pre_incr((void **)(&(x)), (n)*sizeof(*x)))
945#define GC_POST_INCR3(x, n, type_of_result) \
946 ((type_of_result)GC_post_incr((void **)(&(x)), (n)*sizeof(*x)))
947#define GC_PTR_ADD(x, n) GC_PTR_ADD3(x, n, __typeof__(x))
948#define GC_PRE_INCR(x, n) GC_PRE_INCR3(x, n, __typeof__(x))
949#define GC_POST_INCR(x) GC_POST_INCR3(x, 1, __typeof__(x))
950#define GC_POST_DECR(x) GC_POST_INCR3(x, -1, __typeof__(x))
951#else
952#define GC_PTR_ADD(x, n) ((x)+(n))
953#define GC_PRE_INCR(x, n) ((x) += (n))
954#define GC_POST_INCR(x) ((x)++)
955#define GC_POST_DECR(x) ((x)--)
956#endif
957#ifdef GC_DEBUG
958#define GC_PTR_STORE(p, q) \
959 (*(void **)GC_is_visible((void *)(p)) = \
960 GC_is_valid_displacement((void *)(q)))
961#else
962#define GC_PTR_STORE(p, q) (*(void **)(p) = (void *)(q))
963#endif
964GC_API void GC_CALL GC_ptr_store_and_dirty(void * ,
965 const void * );
966GC_API void GC_CALL GC_debug_ptr_store_and_dirty(void * ,
967 const void * );
968GC_API void (GC_CALLBACK * GC_same_obj_print_proc)(void * ,
969 void * );
970GC_API void (GC_CALLBACK * GC_is_valid_displacement_print_proc)(void *);
971GC_API void (GC_CALLBACK * GC_is_visible_print_proc)(void *);
972#ifdef GC_PTHREADS
973#ifdef __cplusplus
974 }
975#endif
976#ifndef GC_PTHREAD_REDIRECTS_H
977#define GC_PTHREAD_REDIRECTS_H
978#if defined(GC_H) && defined(GC_PTHREADS)
979#ifndef GC_PTHREAD_REDIRECTS_ONLY
980#include <pthread.h>
981#ifndef GC_NO_DLOPEN
982#include <dlfcn.h>
983#endif
984#ifndef GC_NO_PTHREAD_SIGMASK
985#include <signal.h>
986#endif
987#ifdef __cplusplus
988 extern "C" {
989#endif
990#ifndef GC_SUSPEND_THREAD_ID
991#define GC_SUSPEND_THREAD_ID pthread_t
992#endif
993#ifndef GC_NO_DLOPEN
994 GC_API void *GC_dlopen(const char * , int );
995#endif
996#ifndef GC_NO_PTHREAD_SIGMASK
997#if defined(GC_PTHREAD_SIGMASK_NEEDED) \
998 || defined(_BSD_SOURCE) || defined(_GNU_SOURCE) \
999 || (_POSIX_C_SOURCE >= 199506L) || (_XOPEN_SOURCE >= 500)
1000 GC_API int GC_pthread_sigmask(int , const sigset_t *,
1001 sigset_t * );
1002#endif
1003#endif
1004#ifndef GC_PTHREAD_CREATE_CONST
1005#define GC_PTHREAD_CREATE_CONST const
1006#endif
1007 GC_API int GC_pthread_create(pthread_t *,
1008 GC_PTHREAD_CREATE_CONST pthread_attr_t *,
1009 void *(*)(void *), void * );
1010 GC_API int GC_pthread_join(pthread_t, void ** );
1011 GC_API int GC_pthread_detach(pthread_t);
1012#ifndef GC_NO_PTHREAD_CANCEL
1013 GC_API int GC_pthread_cancel(pthread_t);
1014#endif
1015#if defined(GC_HAVE_PTHREAD_EXIT) && !defined(GC_PTHREAD_EXIT_DECLARED)
1016#define GC_PTHREAD_EXIT_DECLARED
1017 GC_API void GC_pthread_exit(void *) GC_PTHREAD_EXIT_ATTRIBUTE;
1018#endif
1019#ifdef __cplusplus
1020 }
1021#endif
1022#endif
1023#if !defined(GC_NO_THREAD_REDIRECTS) && !defined(GC_USE_LD_WRAP)
1024#undef pthread_create
1025#undef pthread_join
1026#undef pthread_detach
1027#define pthread_create GC_pthread_create
1028#define pthread_join GC_pthread_join
1029#define pthread_detach GC_pthread_detach
1030#ifndef GC_NO_PTHREAD_SIGMASK
1031#undef pthread_sigmask
1032#define pthread_sigmask GC_pthread_sigmask
1033#endif
1034#ifndef GC_NO_DLOPEN
1035#undef dlopen
1036#define dlopen GC_dlopen
1037#endif
1038#ifndef GC_NO_PTHREAD_CANCEL
1039#undef pthread_cancel
1040#define pthread_cancel GC_pthread_cancel
1041#endif
1042#ifdef GC_HAVE_PTHREAD_EXIT
1043#undef pthread_exit
1044#define pthread_exit GC_pthread_exit
1045#endif
1046#endif
1047#endif
1048#endif
1049#ifdef __cplusplus
1050 extern "C" {
1051#endif
1052#endif
1053GC_API GC_ATTR_MALLOC void * GC_CALL GC_malloc_many(size_t );
1054#define GC_NEXT(p) (*(void * *)(p))
1055typedef int (GC_CALLBACK * GC_has_static_roots_func)(
1056 const char * ,
1057 void * ,
1058 size_t );
1059GC_API void GC_CALL GC_register_has_static_roots_callback(
1060 GC_has_static_roots_func);
1061#if !defined(CPPCHECK) && !defined(GC_WINDOWS_H_INCLUDED) && defined(WINAPI)
1062#define GC_WINDOWS_H_INCLUDED
1063#endif
1064#if defined(GC_WIN32_THREADS) \
1065 && (!defined(GC_PTHREADS) || defined(GC_BUILD) \
1066 || defined(GC_WINDOWS_H_INCLUDED))
1067#if (!defined(GC_NO_THREAD_DECLS) || defined(GC_BUILD)) \
1068 && !defined(GC_DONT_INCL_WINDOWS_H)
1069#ifdef __cplusplus
1070 }
1071#endif
1072#if !defined(_WIN32_WCE) && !defined(__CEGCC__)
1073#include <process.h>
1074#endif
1075#if defined(GC_BUILD) || !defined(GC_DONT_INCLUDE_WINDOWS_H)
1076#include <windows.h>
1077#define GC_WINDOWS_H_INCLUDED
1078#endif
1079#ifdef __cplusplus
1080 extern "C" {
1081#endif
1082#ifdef GC_UNDERSCORE_STDCALL
1083#define GC_CreateThread _GC_CreateThread
1084#define GC_ExitThread _GC_ExitThread
1085#endif
1086#ifndef DECLSPEC_NORETURN
1087#ifdef GC_WINDOWS_H_INCLUDED
1088#define DECLSPEC_NORETURN
1089#else
1090#define DECLSPEC_NORETURN __declspec(noreturn)
1091#endif
1092#endif
1093#if !defined(_UINTPTR_T) && !defined(_UINTPTR_T_DEFINED) \
1094 && !defined(UINTPTR_MAX)
1095 typedef GC_word GC_uintptr_t;
1096#else
1097 typedef uintptr_t GC_uintptr_t;
1098#endif
1099#ifdef _WIN64
1100#define GC_WIN32_SIZE_T GC_uintptr_t
1101#elif defined(GC_WINDOWS_H_INCLUDED)
1102#define GC_WIN32_SIZE_T DWORD
1103#else
1104#define GC_WIN32_SIZE_T unsigned long
1105#endif
1106#ifdef GC_INSIDE_DLL
1107#ifdef GC_UNDERSCORE_STDCALL
1108#define GC_DllMain _GC_DllMain
1109#endif
1110#ifdef GC_WINDOWS_H_INCLUDED
1111 GC_API BOOL WINAPI GC_DllMain(HINSTANCE ,
1112 ULONG ,
1113 LPVOID );
1114#else
1115 GC_API int __stdcall GC_DllMain(void *, unsigned long, void *);
1116#endif
1117#endif
1118#ifdef GC_WINDOWS_H_INCLUDED
1119 GC_API HANDLE WINAPI GC_CreateThread(
1120 LPSECURITY_ATTRIBUTES ,
1121 GC_WIN32_SIZE_T ,
1122 LPTHREAD_START_ROUTINE ,
1123 LPVOID , DWORD ,
1124 LPDWORD );
1125 GC_API DECLSPEC_NORETURN void WINAPI GC_ExitThread(
1126 DWORD );
1127#else
1128 struct _SECURITY_ATTRIBUTES;
1129 GC_API void *__stdcall GC_CreateThread(struct _SECURITY_ATTRIBUTES *,
1130 GC_WIN32_SIZE_T,
1131 unsigned long (__stdcall *)(void *),
1132 void *, unsigned long, unsigned long *);
1133 GC_API DECLSPEC_NORETURN void __stdcall GC_ExitThread(unsigned long);
1134#endif
1135#if !defined(_WIN32_WCE) && !defined(__CEGCC__)
1136 GC_API GC_uintptr_t GC_CALL GC_beginthreadex(
1137 void * , unsigned ,
1138 unsigned (__stdcall *)(void *),
1139 void * , unsigned ,
1140 unsigned * );
1141 GC_API void GC_CALL GC_endthreadex(unsigned );
1142#endif
1143#endif
1144#ifdef GC_WINMAIN_REDIRECT
1145#define WinMain GC_WinMain
1146#endif
1147#define GC_use_DllMain GC_use_threads_discovery
1148#ifndef GC_NO_THREAD_REDIRECTS
1149#define CreateThread GC_CreateThread
1150#define ExitThread GC_ExitThread
1151#undef _beginthreadex
1152#define _beginthreadex GC_beginthreadex
1153#undef _endthreadex
1154#define _endthreadex GC_endthreadex
1155#endif
1156#endif
1157GC_API void GC_CALL GC_set_force_unmap_on_gcollect(int);
1158GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void);
1159#if defined(__CYGWIN32__) || defined(__CYGWIN__)
1160#ifdef __x86_64__
1161 extern int __data_start__[], __data_end__[];
1162 extern int __bss_start__[], __bss_end__[];
1163#define GC_DATASTART ((GC_word)__data_start__ < (GC_word)__bss_start__ \
1164 ? (void *)__data_start__ : (void *)__bss_start__)
1165#define GC_DATAEND ((GC_word)__data_end__ > (GC_word)__bss_end__ \
1166 ? (void *)__data_end__ : (void *)__bss_end__)
1167#else
1168 extern int _data_start__[], _data_end__[], _bss_start__[], _bss_end__[];
1169#define GC_DATASTART ((GC_word)_data_start__ < (GC_word)_bss_start__ \
1170 ? (void *)_data_start__ : (void *)_bss_start__)
1171#define GC_DATAEND ((GC_word)_data_end__ > (GC_word)_bss_end__ \
1172 ? (void *)_data_end__ : (void *)_bss_end__)
1173#endif
1174#define GC_INIT_CONF_ROOTS GC_add_roots(GC_DATASTART, GC_DATAEND); \
1175 GC_gcollect()
1176#elif defined(_AIX)
1177 extern int _data[], _end[];
1178#define GC_DATASTART ((void *)_data)
1179#define GC_DATAEND ((void *)_end)
1180#define GC_INIT_CONF_ROOTS GC_add_roots(GC_DATASTART, GC_DATAEND)
1181#elif (defined(HOST_ANDROID) || defined(__ANDROID__)) \
1182 && defined(IGNORE_DYNAMIC_LOADING)
1183#pragma weak __dso_handle
1184 extern int __dso_handle[];
1185 GC_API void * GC_CALL GC_find_limit(void * , int );
1186#define GC_INIT_CONF_ROOTS (void)(__dso_handle != 0 \
1187 ? (GC_add_roots(__dso_handle, \
1188 GC_find_limit(__dso_handle, \
1189 1 )), 0) : 0)
1190#else
1191#define GC_INIT_CONF_ROOTS
1192#endif
1193#ifdef GC_DONT_EXPAND
1194#define GC_INIT_CONF_DONT_EXPAND GC_set_dont_expand(1)
1195#else
1196#define GC_INIT_CONF_DONT_EXPAND
1197#endif
1198#ifdef GC_FORCE_UNMAP_ON_GCOLLECT
1199#define GC_INIT_CONF_FORCE_UNMAP_ON_GCOLLECT \
1200 GC_set_force_unmap_on_gcollect(1)
1201#else
1202#define GC_INIT_CONF_FORCE_UNMAP_ON_GCOLLECT
1203#endif
1204#ifdef GC_DONT_GC
1205#define GC_INIT_CONF_MAX_RETRIES (void)(GC_dont_gc = 1)
1206#elif defined(GC_MAX_RETRIES) && !defined(CPPCHECK)
1207#define GC_INIT_CONF_MAX_RETRIES GC_set_max_retries(GC_MAX_RETRIES)
1208#else
1209#define GC_INIT_CONF_MAX_RETRIES
1210#endif
1211#if defined(GC_ALLOCD_BYTES_PER_FINALIZER) && !defined(CPPCHECK)
1212#define GC_INIT_CONF_ALLOCD_BYTES_PER_FINALIZER \
1213 GC_set_allocd_bytes_per_finalizer(GC_ALLOCD_BYTES_PER_FINALIZER)
1214#else
1215#define GC_INIT_CONF_ALLOCD_BYTES_PER_FINALIZER
1216#endif
1217#if defined(GC_FREE_SPACE_DIVISOR) && !defined(CPPCHECK)
1218#define GC_INIT_CONF_FREE_SPACE_DIVISOR \
1219 GC_set_free_space_divisor(GC_FREE_SPACE_DIVISOR)
1220#else
1221#define GC_INIT_CONF_FREE_SPACE_DIVISOR
1222#endif
1223#if defined(GC_FULL_FREQ) && !defined(CPPCHECK)
1224#define GC_INIT_CONF_FULL_FREQ GC_set_full_freq(GC_FULL_FREQ)
1225#else
1226#define GC_INIT_CONF_FULL_FREQ
1227#endif
1228#if defined(GC_TIME_LIMIT) && !defined(CPPCHECK)
1229#define GC_INIT_CONF_TIME_LIMIT GC_set_time_limit(GC_TIME_LIMIT)
1230#else
1231#define GC_INIT_CONF_TIME_LIMIT
1232#endif
1233#if defined(GC_MARKERS) && defined(GC_THREADS) && !defined(CPPCHECK)
1234#define GC_INIT_CONF_MARKERS GC_set_markers_count(GC_MARKERS)
1235#else
1236#define GC_INIT_CONF_MARKERS
1237#endif
1238#if defined(GC_SIG_SUSPEND) && defined(GC_THREADS) && !defined(CPPCHECK)
1239#define GC_INIT_CONF_SUSPEND_SIGNAL GC_set_suspend_signal(GC_SIG_SUSPEND)
1240#else
1241#define GC_INIT_CONF_SUSPEND_SIGNAL
1242#endif
1243#if defined(GC_SIG_THR_RESTART) && defined(GC_THREADS) && !defined(CPPCHECK)
1244#define GC_INIT_CONF_THR_RESTART_SIGNAL \
1245 GC_set_thr_restart_signal(GC_SIG_THR_RESTART)
1246#else
1247#define GC_INIT_CONF_THR_RESTART_SIGNAL
1248#endif
1249#if defined(GC_MAXIMUM_HEAP_SIZE) && !defined(CPPCHECK)
1250#define GC_INIT_CONF_MAXIMUM_HEAP_SIZE \
1251 GC_set_max_heap_size(GC_MAXIMUM_HEAP_SIZE)
1252#else
1253#define GC_INIT_CONF_MAXIMUM_HEAP_SIZE
1254#endif
1255#ifdef GC_IGNORE_WARN
1256#define GC_INIT_CONF_IGNORE_WARN GC_set_warn_proc(GC_ignore_warn_proc)
1257#else
1258#define GC_INIT_CONF_IGNORE_WARN
1259#endif
1260#if defined(GC_INITIAL_HEAP_SIZE) && !defined(CPPCHECK)
1261#define GC_INIT_CONF_INITIAL_HEAP_SIZE \
1262 { size_t heap_size = GC_get_heap_size(); \
1263 if (heap_size < (GC_INITIAL_HEAP_SIZE)) \
1264 (void)GC_expand_hp((GC_INITIAL_HEAP_SIZE) - heap_size); }
1265#else
1266#define GC_INIT_CONF_INITIAL_HEAP_SIZE
1267#endif
1268#define GC_INIT() { GC_INIT_CONF_DONT_EXPAND; \
1269 GC_INIT_CONF_FORCE_UNMAP_ON_GCOLLECT; \
1270 GC_INIT_CONF_MAX_RETRIES; \
1271 GC_INIT_CONF_ALLOCD_BYTES_PER_FINALIZER; \
1272 GC_INIT_CONF_FREE_SPACE_DIVISOR; \
1273 GC_INIT_CONF_FULL_FREQ; \
1274 GC_INIT_CONF_TIME_LIMIT; \
1275 GC_INIT_CONF_MARKERS; \
1276 GC_INIT_CONF_SUSPEND_SIGNAL; \
1277 GC_INIT_CONF_THR_RESTART_SIGNAL; \
1278 GC_INIT_CONF_MAXIMUM_HEAP_SIZE; \
1279 GC_init(); \
1280 GC_INIT_CONF_ROOTS; \
1281 GC_INIT_CONF_IGNORE_WARN; \
1282 GC_INIT_CONF_INITIAL_HEAP_SIZE; }
1283GC_API void GC_CALL GC_win32_free_heap(void);
1284#if defined(__SYMBIAN32__)
1285 void GC_init_global_static_roots(void);
1286#endif
1287#if defined(_AMIGA) && !defined(GC_AMIGA_MAKINGLIB)
1288 void *GC_amiga_realloc(void *, size_t);
1289#define GC_realloc(a,b) GC_amiga_realloc(a,b)
1290 void GC_amiga_set_toany(void (*)(void));
1291 extern int GC_amiga_free_space_divisor_inc;
1292 extern void *(*GC_amiga_allocwrapper_do)(size_t, void *(GC_CALL *)(size_t));
1293#define GC_malloc(a) \
1294 (*GC_amiga_allocwrapper_do)(a,GC_malloc)
1295#define GC_malloc_atomic(a) \
1296 (*GC_amiga_allocwrapper_do)(a,GC_malloc_atomic)
1297#define GC_malloc_uncollectable(a) \
1298 (*GC_amiga_allocwrapper_do)(a,GC_malloc_uncollectable)
1299#define GC_malloc_atomic_uncollectable(a) \
1300 (*GC_amiga_allocwrapper_do)(a,GC_malloc_atomic_uncollectable)
1301#define GC_malloc_ignore_off_page(a) \
1302 (*GC_amiga_allocwrapper_do)(a,GC_malloc_ignore_off_page)
1303#define GC_malloc_atomic_ignore_off_page(a) \
1304 (*GC_amiga_allocwrapper_do)(a,GC_malloc_atomic_ignore_off_page)
1305#endif
1306#ifdef __cplusplus
1307 }
1308#endif
1309#endif
1310#endif
1311#include <stdlib.h>
1312#if !defined(sony_news)
1313#include <stddef.h>
1314#endif
1315#ifdef DGUX
1316#include <sys/types.h>
1317#include <sys/time.h>
1318#include <sys/resource.h>
1319#endif
1320#ifdef BSD_TIME
1321#include <sys/types.h>
1322#include <sys/time.h>
1323#include <sys/resource.h>
1324#endif
1325#ifdef PARALLEL_MARK
1326#define AO_REQUIRE_CAS
1327#if !defined(__GNUC__) && !defined(AO_ASSUME_WINDOWS98)
1328#define AO_ASSUME_WINDOWS98
1329#endif
1330#endif
1331#ifndef GC_TINY_FL_H
1332#define GC_TINY_FL_H
1333#ifndef GC_GRANULE_BYTES
1334#if defined(__LP64__) || defined (_LP64) || defined(_WIN64) \
1335 || defined(__s390x__) \
1336 || (defined(__x86_64__) && !defined(__ILP32__)) \
1337 || defined(__alpha__) || defined(__powerpc64__) \
1338 || defined(__arch64__)
1339#define GC_GRANULE_BYTES 16
1340#define GC_GRANULE_WORDS 2
1341#else
1342#define GC_GRANULE_BYTES 8
1343#define GC_GRANULE_WORDS 2
1344#endif
1345#endif
1346#if GC_GRANULE_WORDS == 2
1347#define GC_WORDS_TO_GRANULES(n) ((n)>>1)
1348#else
1349#define GC_WORDS_TO_GRANULES(n) ((n)*sizeof(void *)/GC_GRANULE_BYTES)
1350#endif
1351#ifndef GC_TINY_FREELISTS
1352#if GC_GRANULE_BYTES == 16
1353#define GC_TINY_FREELISTS 25
1354#else
1355#define GC_TINY_FREELISTS 33
1356#endif
1357#endif
1358#define GC_RAW_BYTES_FROM_INDEX(i) ((i) * GC_GRANULE_BYTES)
1359#endif
1360#ifndef GC_MARK_H
1361#define GC_MARK_H
1362#ifndef GC_H
1363#endif
1364#ifdef __cplusplus
1365 extern "C" {
1366#endif
1367#define GC_PROC_BYTES 100
1368#if defined(GC_BUILD) || defined(NOT_GCBUILD)
1369 struct GC_ms_entry;
1370#else
1371 struct GC_ms_entry { void *opaque; };
1372#endif
1373typedef struct GC_ms_entry * (*GC_mark_proc)(GC_word * ,
1374 struct GC_ms_entry * ,
1375 struct GC_ms_entry * ,
1376 GC_word );
1377#define GC_LOG_MAX_MARK_PROCS 6
1378#define GC_MAX_MARK_PROCS (1 << GC_LOG_MAX_MARK_PROCS)
1379#define GC_RESERVED_MARK_PROCS 8
1380#define GC_GCJ_RESERVED_MARK_PROC_INDEX 0
1381#define GC_DS_TAG_BITS 2
1382#define GC_DS_TAGS ((1 << GC_DS_TAG_BITS) - 1)
1383#define GC_DS_LENGTH 0
1384#define GC_DS_BITMAP 1
1385#define GC_DS_PROC 2
1386#define GC_MAKE_PROC(proc_index, env) \
1387 (((((env) << GC_LOG_MAX_MARK_PROCS) \
1388 | (proc_index)) << GC_DS_TAG_BITS) | GC_DS_PROC)
1389#define GC_DS_PER_OBJECT 3
1390#define GC_INDIR_PER_OBJ_BIAS 0x10
1391GC_API void * GC_least_plausible_heap_addr;
1392GC_API void * GC_greatest_plausible_heap_addr;
1393GC_API struct GC_ms_entry * GC_CALL GC_mark_and_push(void * ,
1394 struct GC_ms_entry * ,
1395 struct GC_ms_entry * ,
1396 void ** );
1397#define GC_MARK_AND_PUSH(obj, msp, lim, src) \
1398 ((GC_word)(obj) >= (GC_word)GC_least_plausible_heap_addr && \
1399 (GC_word)(obj) <= (GC_word)GC_greatest_plausible_heap_addr ? \
1400 GC_mark_and_push(obj, msp, lim, src) : (msp))
1401GC_API GC_ATTR_CONST size_t GC_CALL GC_get_debug_header_size(void);
1402#define GC_USR_PTR_FROM_BASE(p) \
1403 ((void *)((char *)(p) + GC_get_debug_header_size()))
1404GC_API GC_ATTR_DEPRECATED
1405#ifdef GC_BUILD
1406 const
1407#endif
1408 size_t GC_debug_header_size;
1409GC_API void ** GC_CALL GC_new_free_list(void);
1410GC_API void ** GC_CALL GC_new_free_list_inner(void);
1411GC_API unsigned GC_CALL GC_new_kind(void ** ,
1412 GC_word ,
1413 int ,
1414 int ) GC_ATTR_NONNULL(1);
1415GC_API unsigned GC_CALL GC_new_kind_inner(void ** ,
1416 GC_word ,
1417 int ,
1418 int ) GC_ATTR_NONNULL(1);
1419GC_API unsigned GC_CALL GC_new_proc(GC_mark_proc);
1420GC_API unsigned GC_CALL GC_new_proc_inner(GC_mark_proc);
1421GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL GC_generic_malloc(
1422 size_t ,
1423 int );
1424GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
1425 GC_generic_malloc_ignore_off_page(
1426 size_t , int );
1427GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
1428 GC_generic_malloc_uncollectable(
1429 size_t , int );
1430GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
1431 GC_generic_or_special_malloc(
1432 size_t , int );
1433GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
1434 GC_debug_generic_or_special_malloc(
1435 size_t , int ,
1436 GC_EXTRA_PARAMS);
1437#ifdef GC_DEBUG
1438#define GC_GENERIC_OR_SPECIAL_MALLOC(sz, knd) \
1439 GC_debug_generic_or_special_malloc(sz, knd, GC_EXTRAS)
1440#else
1441#define GC_GENERIC_OR_SPECIAL_MALLOC(sz, knd) \
1442 GC_generic_or_special_malloc(sz, knd)
1443#endif
1444GC_API int GC_CALL GC_get_kind_and_size(const void *, size_t * )
1445 GC_ATTR_NONNULL(1);
1446typedef void (GC_CALLBACK * GC_describe_type_fn)(void * ,
1447 char * );
1448#define GC_TYPE_DESCR_LEN 40
1449GC_API void GC_CALL GC_register_describe_type_fn(int ,
1450 GC_describe_type_fn);
1451GC_API void * GC_CALL GC_clear_stack(void *);
1452typedef void (GC_CALLBACK * GC_start_callback_proc)(void);
1453GC_API void GC_CALL GC_set_start_callback(GC_start_callback_proc);
1454GC_API GC_start_callback_proc GC_CALL GC_get_start_callback(void);
1455GC_API int GC_CALL GC_is_marked(const void *) GC_ATTR_NONNULL(1);
1456GC_API void GC_CALL GC_clear_mark_bit(const void *) GC_ATTR_NONNULL(1);
1457GC_API void GC_CALL GC_set_mark_bit(const void *) GC_ATTR_NONNULL(1);
1458GC_API void GC_CALL GC_push_all(void * , void * );
1459GC_API void GC_CALL GC_push_all_eager(void * , void * );
1460GC_API void GC_CALL GC_push_conditional(void * , void * ,
1461 int );
1462GC_API void GC_CALL GC_push_finalizer_structures(void);
1463typedef void (GC_CALLBACK * GC_push_other_roots_proc)(void);
1464GC_API void GC_CALL GC_set_push_other_roots(GC_push_other_roots_proc);
1465GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void);
1466typedef void (GC_CALLBACK *GC_reachable_object_proc)(void * ,
1467 size_t ,
1468 void * );
1469GC_API void GC_CALL GC_enumerate_reachable_objects_inner(
1470 GC_reachable_object_proc,
1471 void * ) GC_ATTR_NONNULL(1);
1472GC_API int GC_CALL GC_is_tmp_root(void *);
1473GC_API void GC_CALL GC_print_trace(GC_word );
1474GC_API void GC_CALL GC_print_trace_inner(GC_word );
1475#ifdef __cplusplus
1476 }
1477#endif
1478#endif
1479typedef GC_word word;
1480typedef GC_signed_word signed_word;
1481typedef unsigned int unsigned32;
1482typedef int GC_bool;
1483#define TRUE 1
1484#define FALSE 0
1485#ifndef PTR_T_DEFINED
1486 typedef char * ptr_t;
1487#define PTR_T_DEFINED
1488#endif
1489#ifndef SIZE_MAX
1490#include <limits.h>
1491#endif
1492#if defined(SIZE_MAX) && !defined(CPPCHECK)
1493#define GC_SIZE_MAX ((size_t)SIZE_MAX)
1494#else
1495#define GC_SIZE_MAX (~(size_t)0)
1496#endif
1497#if GC_GNUC_PREREQ(3, 0) && !defined(LINT2)
1498#define EXPECT(expr, outcome) __builtin_expect(expr,outcome)
1499#else
1500#define EXPECT(expr, outcome) (expr)
1501#endif
1502#define SIZET_SAT_ADD(a, b) \
1503 (EXPECT((a) < GC_SIZE_MAX - (b), TRUE) ? (a) + (b) : GC_SIZE_MAX)
1504#ifndef GCCONFIG_H
1505#define GCCONFIG_H
1506#ifdef CPPCHECK
1507#undef CLOCKS_PER_SEC
1508#undef FIXUP_POINTER
1509#undef POINTER_MASK
1510#undef POINTER_SHIFT
1511#undef REDIRECT_REALLOC
1512#undef _MAX_PATH
1513#endif
1514#ifndef PTR_T_DEFINED
1515 typedef char * ptr_t;
1516#define PTR_T_DEFINED
1517#endif
1518#if !defined(sony_news)
1519#include <stddef.h>
1520#endif
1521#ifdef __cplusplus
1522#define EXTERN_C_BEGIN extern "C" {
1523#define EXTERN_C_END }
1524#else
1525#define EXTERN_C_BEGIN
1526#define EXTERN_C_END
1527#endif
1528EXTERN_C_BEGIN
1529#if defined(__clang__) && defined(__clang_major__)
1530#define GC_CLANG_PREREQ(major, minor) \
1531 ((__clang_major__ << 16) + __clang_minor__ >= ((major) << 16) + (minor))
1532#define GC_CLANG_PREREQ_FULL(major, minor, patchlevel) \
1533 (GC_CLANG_PREREQ(major, (minor) + 1) \
1534 || (__clang_major__ == (major) && __clang_minor__ == (minor) \
1535 && __clang_patchlevel__ >= (patchlevel)))
1536#else
1537#define GC_CLANG_PREREQ(major, minor) 0
1538#define GC_CLANG_PREREQ_FULL(major, minor, patchlevel) 0
1539#endif
1540#ifdef LINT2
1541#define COVERT_DATAFLOW(w) (~(GC_word)(w)^(~(GC_word)0))
1542#else
1543#define COVERT_DATAFLOW(w) ((GC_word)(w))
1544#endif
1545#if defined(__ANDROID__) && !defined(HOST_ANDROID)
1546#define HOST_ANDROID 1
1547#endif
1548#if defined(TIZEN) && !defined(HOST_TIZEN)
1549#define HOST_TIZEN 1
1550#endif
1551#if defined(__SYMBIAN32__) && !defined(SYMBIAN)
1552#define SYMBIAN
1553#ifdef __WINS__
1554#pragma data_seg(".data2")
1555#endif
1556#endif
1557#if (defined(linux) || defined(__linux__) || defined(HOST_ANDROID)) \
1558 && !defined(LINUX) && !defined(__native_client__)
1559#define LINUX
1560#endif
1561#if defined(__NetBSD__)
1562#define NETBSD
1563#endif
1564#if defined(__OpenBSD__)
1565#define OPENBSD
1566#endif
1567#if (defined(__FreeBSD__) || defined(__DragonFly__) \
1568 || defined(__FreeBSD_kernel__)) && !defined(FREEBSD) \
1569 && !defined(GC_NO_FREEBSD)
1570#define FREEBSD
1571#endif
1572#if defined(macosx) || (defined(__APPLE__) && defined(__MACH__))
1573#define DARWIN
1574 EXTERN_C_END
1575#include <TargetConditionals.h>
1576 EXTERN_C_BEGIN
1577#endif
1578#if defined(__native_client__)
1579#define NACL
1580#if !defined(__portable_native_client__) && !defined(__arm__)
1581#define I386
1582#define mach_type_known
1583#else
1584#endif
1585#endif
1586#if defined(__aarch64__)
1587#define AARCH64
1588#if !defined(LINUX) && !defined(DARWIN) && !defined(FREEBSD) \
1589 && !defined(NETBSD) && !defined(NN_BUILD_TARGET_PLATFORM_NX) \
1590 && !defined(OPENBSD)
1591#define NOSYS
1592#define mach_type_known
1593#endif
1594#endif
1595#if defined(__arm) || defined(__arm__) || defined(__thumb__)
1596#define ARM32
1597#if defined(NACL)
1598#define mach_type_known
1599#elif !defined(LINUX) && !defined(NETBSD) && !defined(FREEBSD) \
1600 && !defined(OPENBSD) && !defined(DARWIN) && !defined(_WIN32) \
1601 && !defined(__CEGCC__) && !defined(NN_PLATFORM_CTR) \
1602 && !defined(GC_NO_NOSYS) && !defined(SN_TARGET_PSP2) \
1603 && !defined(SYMBIAN)
1604#define NOSYS
1605#define mach_type_known
1606#endif
1607#endif
1608#if defined(sun) && defined(mc68000) && !defined(CPPCHECK)
1609#error SUNOS4 no longer supported
1610#endif
1611#if defined(hp9000s300) && !defined(CPPCHECK)
1612#error M68K based HP machines no longer supported
1613#endif
1614#if defined(OPENBSD) && defined(m68k)
1615#define M68K
1616#define mach_type_known
1617#endif
1618#if defined(OPENBSD) && defined(__sparc__)
1619#define SPARC
1620#define mach_type_known
1621#endif
1622#if defined(OPENBSD) && defined(__arm__)
1623#define ARM32
1624#define mach_type_known
1625#endif
1626#if defined(OPENBSD) && defined(__aarch64__)
1627#define AARCH64
1628#define mach_type_known
1629#endif
1630#if defined(OPENBSD) && defined(__sh__)
1631#define SH
1632#define mach_type_known
1633#endif
1634#if defined(NETBSD) && (defined(m68k) || defined(__m68k__))
1635#define M68K
1636#define mach_type_known
1637#endif
1638#if defined(NETBSD) && defined(__powerpc__)
1639#define POWERPC
1640#define mach_type_known
1641#endif
1642#if defined(NETBSD) && (defined(__arm32__) || defined(__arm__))
1643#define ARM32
1644#define mach_type_known
1645#endif
1646#if defined(NETBSD) && defined(__aarch64__)
1647#define AARCH64
1648#define mach_type_known
1649#endif
1650#if defined(NETBSD) && defined(__sh__)
1651#define SH
1652#define mach_type_known
1653#endif
1654#if defined(vax) || defined(__vax__)
1655#define VAX
1656#ifdef ultrix
1657#define ULTRIX
1658#else
1659#define BSD
1660#endif
1661#define mach_type_known
1662#endif
1663#if defined(NETBSD) && defined(__vax__)
1664#define VAX
1665#define mach_type_known
1666#endif
1667#if defined(mips) || defined(__mips) || defined(_mips)
1668#define MIPS
1669#if defined(nec_ews) || defined(_nec_ews)
1670#define EWS4800
1671#endif
1672#if !defined(LINUX) && !defined(EWS4800) && !defined(NETBSD) \
1673 && !defined(OPENBSD)
1674#if defined(ultrix) || defined(__ultrix)
1675#define ULTRIX
1676#else
1677#define IRIX5
1678#endif
1679#endif
1680#if defined(NETBSD) && defined(__MIPSEL__)
1681#undef ULTRIX
1682#endif
1683#define mach_type_known
1684#endif
1685#if defined(__QNX__)
1686#define I386
1687#define mach_type_known
1688#endif
1689#if defined(__NIOS2__) || defined(__NIOS2) || defined(__nios2__)
1690#define NIOS2
1691#define mach_type_known
1692#endif
1693#if defined(__or1k__)
1694#define OR1K
1695#define mach_type_known
1696#endif
1697#if defined(DGUX) && (defined(i386) || defined(__i386__))
1698#define I386
1699#ifndef _USING_DGUX
1700#define _USING_DGUX
1701#endif
1702#define mach_type_known
1703#endif
1704#if defined(sequent) && (defined(i386) || defined(__i386__))
1705#define I386
1706#define SEQUENT
1707#define mach_type_known
1708#endif
1709#if (defined(sun) || defined(__sun)) && (defined(i386) || defined(__i386__))
1710#define I386
1711#define SOLARIS
1712#define mach_type_known
1713#endif
1714#if (defined(sun) || defined(__sun)) && defined(__amd64)
1715#define X86_64
1716#define SOLARIS
1717#define mach_type_known
1718#endif
1719#if (defined(__OS2__) || defined(__EMX__)) && defined(__32BIT__)
1720#define I386
1721#define OS2
1722#define mach_type_known
1723#endif
1724#if defined(ibm032) && !defined(CPPCHECK)
1725#error IBM PC/RT no longer supported
1726#endif
1727#if (defined(sun) || defined(__sun)) && (defined(sparc) || defined(__sparc))
1728 EXTERN_C_END
1729#include <errno.h>
1730 EXTERN_C_BEGIN
1731#define SPARC
1732#define SOLARIS
1733#define mach_type_known
1734#elif defined(sparc) && defined(unix) && !defined(sun) && !defined(linux) \
1735 && !defined(FREEBSD) && !defined(NETBSD) && !defined(OPENBSD)
1736#define SPARC
1737#define DRSNX
1738#define mach_type_known
1739#endif
1740#if defined(_IBMR2)
1741#define POWERPC
1742#define AIX
1743#define mach_type_known
1744#endif
1745#if defined(NETBSD) && defined(__sparc__)
1746#define SPARC
1747#define mach_type_known
1748#endif
1749#if defined(_M_XENIX) && defined(_M_SYSV) && defined(_M_I386)
1750#define I386
1751#if defined(_SCO_ELF)
1752#define SCO_ELF
1753#else
1754#define SCO
1755#endif
1756#define mach_type_known
1757#endif
1758#if defined(_AUX_SOURCE) && !defined(CPPCHECK)
1759#error A/UX no longer supported
1760#endif
1761#if defined(_PA_RISC1_0) || defined(_PA_RISC1_1) || defined(_PA_RISC2_0) \
1762 || defined(hppa) || defined(__hppa__)
1763#define HP_PA
1764#if !defined(LINUX) && !defined(HPUX) && !defined(OPENBSD)
1765#define HPUX
1766#endif
1767#define mach_type_known
1768#endif
1769#if defined(__ia64) && (defined(_HPUX_SOURCE) || defined(__HP_aCC))
1770#define IA64
1771#ifndef HPUX
1772#define HPUX
1773#endif
1774#define mach_type_known
1775#endif
1776#if (defined(__BEOS__) || defined(__HAIKU__)) && defined(_X86_)
1777#define I386
1778#define HAIKU
1779#define mach_type_known
1780#endif
1781#if defined(__HAIKU__) && (defined(__amd64__) || defined(__x86_64__))
1782#define X86_64
1783#define HAIKU
1784#define mach_type_known
1785#endif
1786#if defined(OPENBSD) && defined(__amd64__)
1787#define X86_64
1788#define mach_type_known
1789#endif
1790#if defined(LINUX) && (defined(i386) || defined(__i386__))
1791#define I386
1792#define mach_type_known
1793#endif
1794#if defined(LINUX) && defined(__x86_64__)
1795#define X86_64
1796#define mach_type_known
1797#endif
1798#if defined(LINUX) && (defined(__ia64__) || defined(__ia64))
1799#define IA64
1800#define mach_type_known
1801#endif
1802#if defined(LINUX) && defined(__aarch64__)
1803#define AARCH64
1804#define mach_type_known
1805#endif
1806#if defined(LINUX) && (defined(__arm) || defined(__arm__))
1807#define ARM32
1808#define mach_type_known
1809#endif
1810#if defined(LINUX) && defined(__cris__)
1811#ifndef CRIS
1812#define CRIS
1813#endif
1814#define mach_type_known
1815#endif
1816#if defined(LINUX) && defined(__loongarch__)
1817#define LOONGARCH
1818#define mach_type_known
1819#endif
1820#if defined(LINUX) && (defined(powerpc) || defined(__powerpc__) \
1821 || defined(powerpc64) || defined(__powerpc64__))
1822#define POWERPC
1823#define mach_type_known
1824#endif
1825#if defined(LINUX) && defined(__mc68000__)
1826#define M68K
1827#define mach_type_known
1828#endif
1829#if defined(LINUX) && (defined(sparc) || defined(__sparc__))
1830#define SPARC
1831#define mach_type_known
1832#endif
1833#if defined(LINUX) && defined(__sh__)
1834#define SH
1835#define mach_type_known
1836#endif
1837#if defined(LINUX) && defined(__avr32__)
1838#define AVR32
1839#define mach_type_known
1840#endif
1841#if defined(LINUX) && defined(__m32r__)
1842#define M32R
1843#define mach_type_known
1844#endif
1845#if defined(__alpha) || defined(__alpha__)
1846#define ALPHA
1847#if !defined(LINUX) && !defined(NETBSD) && !defined(OPENBSD) \
1848 && !defined(FREEBSD)
1849#define OSF1
1850#endif
1851#define mach_type_known
1852#endif
1853#if defined(_AMIGA) && !defined(AMIGA)
1854#define AMIGA
1855#endif
1856#ifdef AMIGA
1857#define M68K
1858#define mach_type_known
1859#endif
1860#if defined(THINK_C) \
1861 || (defined(__MWERKS__) && !defined(__powerc) && !defined(SYMBIAN))
1862#define M68K
1863#define MACOS
1864#define mach_type_known
1865#endif
1866#if defined(__MWERKS__) && defined(__powerc) && !defined(__MACH__) \
1867 && !defined(SYMBIAN)
1868#define POWERPC
1869#define MACOS
1870#define mach_type_known
1871#endif
1872#if defined(OPENBSD) && defined(__powerpc__)
1873#define POWERPC
1874#define mach_type_known
1875#endif
1876#if defined(DARWIN)
1877#if defined(__ppc__) || defined(__ppc64__)
1878#define POWERPC
1879#define mach_type_known
1880#elif defined(__x86_64__) || defined(__x86_64)
1881#define X86_64
1882#define mach_type_known
1883#elif defined(__i386__)
1884#define I386
1885#define mach_type_known
1886#elif defined(__arm__)
1887#define ARM32
1888#define mach_type_known
1889#elif defined(__aarch64__)
1890#define AARCH64
1891#define mach_type_known
1892#endif
1893#endif
1894#if defined(__rtems__) && (defined(i386) || defined(__i386__))
1895#define I386
1896#define RTEMS
1897#define mach_type_known
1898#endif
1899#if defined(NeXT) && defined(mc68000)
1900#define M68K
1901#define NEXT
1902#define mach_type_known
1903#endif
1904#if defined(NeXT) && (defined(i386) || defined(__i386__))
1905#define I386
1906#define NEXT
1907#define mach_type_known
1908#endif
1909#if defined(OPENBSD) && (defined(i386) || defined(__i386__))
1910#define I386
1911#define mach_type_known
1912#endif
1913#if defined(NETBSD) && (defined(i386) || defined(__i386__))
1914#define I386
1915#define mach_type_known
1916#endif
1917#if defined(NETBSD) && defined(__x86_64__)
1918#define X86_64
1919#define mach_type_known
1920#endif
1921#if defined(FREEBSD) && (defined(i386) || defined(__i386__))
1922#define I386
1923#define mach_type_known
1924#endif
1925#if defined(FREEBSD) && (defined(__amd64__) || defined(__x86_64__))
1926#define X86_64
1927#define mach_type_known
1928#endif
1929#if defined(FREEBSD) && defined(__sparc__)
1930#define SPARC
1931#define mach_type_known
1932#endif
1933#if defined(FREEBSD) && (defined(powerpc) || defined(__powerpc__))
1934#define POWERPC
1935#define mach_type_known
1936#endif
1937#if defined(FREEBSD) && defined(__arm__)
1938#define ARM32
1939#define mach_type_known
1940#endif
1941#if defined(FREEBSD) && defined(__aarch64__)
1942#define AARCH64
1943#define mach_type_known
1944#endif
1945#if defined(FREEBSD) && (defined(mips) || defined(__mips) || defined(_mips))
1946#define MIPS
1947#define mach_type_known
1948#endif
1949#if defined(bsdi) && (defined(i386) || defined(__i386__))
1950#define I386
1951#define BSDI
1952#define mach_type_known
1953#endif
1954#if !defined(mach_type_known) && defined(__386BSD__)
1955#define I386
1956#define THREE86BSD
1957#define mach_type_known
1958#endif
1959#if defined(_CX_UX) && defined(_M88K)
1960#define M88K
1961#define CX_UX
1962#define mach_type_known
1963#endif
1964#if defined(DGUX) && defined(m88k)
1965#define M88K
1966#define mach_type_known
1967#endif
1968#if defined(_WIN32_WCE) || defined(__CEGCC__) || defined(__MINGW32CE__)
1969#if defined(SH3) || defined(SH4)
1970#define SH
1971#endif
1972#if defined(x86) || defined(__i386__)
1973#define I386
1974#endif
1975#if defined(_M_ARM) || defined(ARM) || defined(_ARM_)
1976#define ARM32
1977#endif
1978#define MSWINCE
1979#define mach_type_known
1980#else
1981#if ((defined(_MSDOS) || defined(_MSC_VER)) && (_M_IX86 >= 300)) \
1982 || (defined(_WIN32) && !defined(__CYGWIN32__) && !defined(__CYGWIN__) \
1983 && !defined(__INTERIX) && !defined(SYMBIAN))
1984#if defined(__LP64__) || defined(_M_X64)
1985#define X86_64
1986#elif defined(_M_ARM)
1987#define ARM32
1988#elif defined(_M_ARM64)
1989#define AARCH64
1990#else
1991#define I386
1992#endif
1993#ifdef _XBOX_ONE
1994#define MSWIN_XBOX1
1995#else
1996#ifndef MSWIN32
1997#define MSWIN32
1998#endif
1999#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
2000#define MSWINRT_FLAVOR
2001#endif
2002#endif
2003#define mach_type_known
2004#endif
2005#if defined(_MSC_VER) && defined(_M_IA64)
2006#define IA64
2007#define MSWIN32
2008#endif
2009#endif
2010#if defined(__DJGPP__)
2011#define I386
2012#ifndef DJGPP
2013#define DJGPP
2014#endif
2015#define mach_type_known
2016#endif
2017#if defined(__CYGWIN32__) || defined(__CYGWIN__)
2018#if defined(__LP64__)
2019#define X86_64
2020#else
2021#define I386
2022#endif
2023#define CYGWIN32
2024#define mach_type_known
2025#endif
2026#if defined(__INTERIX)
2027#define I386
2028#define INTERIX
2029#define mach_type_known
2030#endif
2031#if defined(__MINGW32__) && !defined(mach_type_known)
2032#define I386
2033#define MSWIN32
2034#define mach_type_known
2035#endif
2036#if defined(__BORLANDC__)
2037#define I386
2038#define MSWIN32
2039#define mach_type_known
2040#endif
2041#if defined(_UTS) && !defined(mach_type_known)
2042#define S370
2043#define UTS4
2044#define mach_type_known
2045#endif
2046#if defined(__pj__) && !defined(CPPCHECK)
2047#error PicoJava no longer supported
2048#endif
2049#if defined(__embedded__) && defined(PPC)
2050#define POWERPC
2051#define NOSYS
2052#define mach_type_known
2053#endif
2054#if defined(__WATCOMC__) && defined(__386__)
2055#define I386
2056#if !defined(OS2) && !defined(MSWIN32) && !defined(DOS4GW)
2057#if defined(__OS2__)
2058#define OS2
2059#else
2060#if defined(__WINDOWS_386__) || defined(__NT__)
2061#define MSWIN32
2062#else
2063#define DOS4GW
2064#endif
2065#endif
2066#endif
2067#define mach_type_known
2068#endif
2069#if defined(__s390__) && defined(LINUX)
2070#define S390
2071#define mach_type_known
2072#endif
2073#if defined(__GNU__)
2074#if defined(__i386__)
2075#define HURD
2076#define I386
2077#define mach_type_known
2078#endif
2079#endif
2080#if defined(__TANDEM)
2081#define MIPS
2082#define NONSTOP
2083#define mach_type_known
2084#endif
2085#if defined(__arc__) && defined(LINUX)
2086#define ARC
2087#define mach_type_known
2088#endif
2089#if defined(__hexagon__) && defined(LINUX)
2090#define HEXAGON
2091#define mach_type_known
2092#endif
2093#if defined(__tile__) && defined(LINUX)
2094#ifdef __tilegx__
2095#define TILEGX
2096#else
2097#define TILEPRO
2098#endif
2099#define mach_type_known
2100#endif
2101#if defined(__riscv) && (defined(FREEBSD) || defined(LINUX))
2102#define RISCV
2103#define mach_type_known
2104#endif
2105#if defined(SN_TARGET_PSP2)
2106#define mach_type_known
2107#endif
2108#if defined(NN_PLATFORM_CTR)
2109#define mach_type_known
2110#endif
2111#if defined(NN_BUILD_TARGET_PLATFORM_NX)
2112#define NINTENDO_SWITCH
2113#define mach_type_known
2114#endif
2115#if defined(SYMBIAN)
2116#define mach_type_known
2117#endif
2118#if defined(__EMSCRIPTEN__)
2119#define EMSCRIPTEN
2120#define I386
2121#define mach_type_known
2122#endif
2123#if !defined(mach_type_known) && !defined(CPPCHECK)
2124#error The collector has not been ported to this machine/OS combination
2125#endif
2126#if GC_GNUC_PREREQ(2, 8) \
2127 && !GC_GNUC_PREREQ(11, 0) \
2128 && !defined(__INTEL_COMPILER) && !defined(__PATHCC__) \
2129 && !defined(__FUJITSU) \
2130 && !(defined(POWERPC) && defined(DARWIN)) \
2131 && !defined(RTEMS) \
2132 && !defined(__ARMCC_VERSION) \
2133 && (!defined(__clang__) \
2134 || GC_CLANG_PREREQ(8, 0) )
2135#define HAVE_BUILTIN_UNWIND_INIT
2136#endif
2137#ifdef CYGWIN32
2138#define OS_TYPE "CYGWIN32"
2139#define RETRY_GET_THREAD_CONTEXT
2140#ifdef USE_WINALLOC
2141#define GWW_VDB
2142#elif defined(USE_MMAP)
2143#define USE_MMAP_ANON
2144#endif
2145#endif
2146#ifdef DARWIN
2147#define OS_TYPE "DARWIN"
2148#define DYNAMIC_LOADING
2149#define DATASTART ((ptr_t)get_etext())
2150#define DATAEND ((ptr_t)get_end())
2151#define USE_MMAP_ANON
2152 EXTERN_C_END
2153#include <unistd.h>
2154 EXTERN_C_BEGIN
2155#define GETPAGESIZE() (unsigned)getpagesize()
2156#define NO_PTHREAD_TRYLOCK
2157#endif
2158#ifdef FREEBSD
2159#define OS_TYPE "FREEBSD"
2160#define FREEBSD_STACKBOTTOM
2161#ifdef __ELF__
2162#define DYNAMIC_LOADING
2163#endif
2164#if !defined(ALPHA) && !defined(SPARC)
2165 extern char etext[];
2166#define DATASTART GC_FreeBSDGetDataStart(0x1000, (ptr_t)etext)
2167#define DATASTART_USES_BSDGETDATASTART
2168#ifndef GC_FREEBSD_THREADS
2169#define MPROTECT_VDB
2170#endif
2171#endif
2172#endif
2173#ifdef HAIKU
2174#define OS_TYPE "HAIKU"
2175#define DYNAMIC_LOADING
2176#define MPROTECT_VDB
2177 EXTERN_C_END
2178#include <OS.h>
2179 EXTERN_C_BEGIN
2180#define GETPAGESIZE() (unsigned)B_PAGE_SIZE
2181#endif
2182#ifdef HPUX
2183#define OS_TYPE "HPUX"
2184 extern int __data_start[];
2185#define DATASTART ((ptr_t)(__data_start))
2186#ifdef USE_MMAP
2187#define USE_MMAP_ANON
2188#endif
2189#define DYNAMIC_LOADING
2190 EXTERN_C_END
2191#include <unistd.h>
2192 EXTERN_C_BEGIN
2193#define GETPAGESIZE() (unsigned)sysconf(_SC_PAGE_SIZE)
2194#endif
2195#ifdef LINUX
2196#define OS_TYPE "LINUX"
2197 EXTERN_C_END
2198#include <features.h>
2199 EXTERN_C_BEGIN
2200#define COUNT_UNMAPPED_REGIONS
2201#if !defined(MIPS) && !defined(POWERPC)
2202#define LINUX_STACKBOTTOM
2203#endif
2204#if defined(__ELF__) && !defined(IA64)
2205#define DYNAMIC_LOADING
2206#endif
2207#if defined(__ELF__) && !defined(ARC) && !defined(RISCV) \
2208 && !defined(S390) && !defined(TILEGX) && !defined(TILEPRO)
2209 extern int _end[];
2210#define DATAEND ((ptr_t)(_end))
2211#endif
2212#endif
2213#ifdef MACOS
2214#define OS_TYPE "MACOS"
2215#ifndef __LOWMEM__
2216 EXTERN_C_END
2217#include <LowMem.h>
2218 EXTERN_C_BEGIN
2219#endif
2220#define STACKBOTTOM ((ptr_t)LMGetCurStackBase())
2221#define DATAEND
2222#endif
2223#ifdef MSWIN32
2224#define OS_TYPE "MSWIN32"
2225#define DATAEND
2226#define GWW_VDB
2227#endif
2228#ifdef MSWINCE
2229#define OS_TYPE "MSWINCE"
2230#define DATAEND
2231#endif
2232#ifdef NETBSD
2233#define OS_TYPE "NETBSD"
2234#define HEURISTIC2
2235#ifdef __ELF__
2236 extern ptr_t GC_data_start;
2237#define DATASTART GC_data_start
2238#define DYNAMIC_LOADING
2239#elif !defined(MIPS)
2240 extern char etext[];
2241#define DATASTART ((ptr_t)(etext))
2242#endif
2243#endif
2244#ifdef NEXT
2245#define OS_TYPE "NEXT"
2246#define DATASTART ((ptr_t)get_etext())
2247#define DATASTART_IS_FUNC
2248#define DATAEND
2249#endif
2250#ifdef OPENBSD
2251#define OS_TYPE "OPENBSD"
2252#if !defined(M68K)
2253#ifndef GC_OPENBSD_THREADS
2254#define HEURISTIC2
2255#endif
2256 extern int __data_start[];
2257#define DATASTART ((ptr_t)__data_start)
2258 extern int _end[];
2259#define DATAEND ((ptr_t)(&_end))
2260#define DYNAMIC_LOADING
2261#endif
2262#endif
2263#ifdef SOLARIS
2264#define OS_TYPE "SOLARIS"
2265 extern int _etext[], _end[];
2266 ptr_t GC_SysVGetDataStart(size_t, ptr_t);
2267#define DATASTART_IS_FUNC
2268#define DATAEND ((ptr_t)(_end))
2269#if !defined(USE_MMAP) && defined(REDIRECT_MALLOC)
2270#define USE_MMAP 1
2271#endif
2272#ifdef USE_MMAP
2273#define HEAP_START (ptr_t)0x40000000
2274#else
2275#define HEAP_START DATAEND
2276#endif
2277#ifndef GC_THREADS
2278#define MPROTECT_VDB
2279#endif
2280#define DYNAMIC_LOADING
2281 EXTERN_C_END
2282#include <sys/vmparam.h>
2283#include <unistd.h>
2284 EXTERN_C_BEGIN
2285#ifdef USERLIMIT
2286#define STACKBOTTOM ((ptr_t)USRSTACK)
2287#else
2288#define HEURISTIC2
2289#endif
2290#endif
2291#define STACK_GRAN 0x1000000
2292#ifdef SYMBIAN
2293#define MACH_TYPE "SYMBIAN"
2294#define OS_TYPE "SYMBIAN"
2295#define CPP_WORDSZ 32
2296#define ALIGNMENT 4
2297#define DATASTART (ptr_t)ALIGNMENT
2298#define DATAEND (ptr_t)ALIGNMENT
2299#endif
2300#ifdef M68K
2301#define MACH_TYPE "M68K"
2302#define ALIGNMENT 2
2303#ifdef OPENBSD
2304#define HEURISTIC2
2305#ifdef __ELF__
2306 extern ptr_t GC_data_start;
2307#define DATASTART GC_data_start
2308#define DYNAMIC_LOADING
2309#else
2310 extern char etext[];
2311#define DATASTART ((ptr_t)(etext))
2312#endif
2313#endif
2314#ifdef NETBSD
2315#endif
2316#ifdef LINUX
2317#if !defined(REDIRECT_MALLOC)
2318#define MPROTECT_VDB
2319#endif
2320#ifdef __ELF__
2321#if defined(__GLIBC__) && __GLIBC__ >= 2
2322#define SEARCH_FOR_DATA_START
2323#else
2324 extern char **__environ;
2325#define DATASTART ((ptr_t)(&__environ))
2326#endif
2327#else
2328 extern int etext[];
2329#define DATASTART ((ptr_t)((((word)(etext)) + 0xfff) & ~0xfff))
2330#endif
2331#endif
2332#ifdef AMIGA
2333#define OS_TYPE "AMIGA"
2334#define DATAEND
2335#define GETPAGESIZE() 4096
2336#endif
2337#ifdef MACOS
2338#define GETPAGESIZE() 4096
2339#endif
2340#ifdef NEXT
2341#define STACKBOTTOM ((ptr_t)0x4000000)
2342#endif
2343#endif
2344#ifdef POWERPC
2345#define MACH_TYPE "POWERPC"
2346#ifdef MACOS
2347#define ALIGNMENT 2
2348#endif
2349#ifdef LINUX
2350#if defined(__powerpc64__)
2351#define ALIGNMENT 8
2352#define CPP_WORDSZ 64
2353#ifndef HBLKSIZE
2354#define HBLKSIZE 4096
2355#endif
2356#else
2357#define ALIGNMENT 4
2358#endif
2359#if defined(__bg__)
2360#define HEURISTIC2
2361#define NO_PTHREAD_GETATTR_NP
2362#else
2363#define LINUX_STACKBOTTOM
2364#endif
2365#define SEARCH_FOR_DATA_START
2366#if !defined(REDIRECT_MALLOC)
2367#define MPROTECT_VDB
2368#endif
2369#ifndef SOFT_VDB
2370#define SOFT_VDB
2371#endif
2372#endif
2373#ifdef DARWIN
2374#if defined(__ppc64__)
2375#define ALIGNMENT 8
2376#define CPP_WORDSZ 64
2377#define STACKBOTTOM ((ptr_t)0x7fff5fc00000)
2378#define CACHE_LINE_SIZE 64
2379#ifndef HBLKSIZE
2380#define HBLKSIZE 4096
2381#endif
2382#else
2383#define ALIGNMENT 4
2384#define STACKBOTTOM ((ptr_t)0xc0000000)
2385#endif
2386#define MPROTECT_VDB
2387#if defined(USE_PPC_PREFETCH) && defined(__GNUC__)
2388#define PREFETCH(x) \
2389 __asm__ __volatile__ ("dcbt 0,%0" : : "r" ((const void *) (x)))
2390#define GC_PREFETCH_FOR_WRITE(x) \
2391 __asm__ __volatile__ ("dcbtst 0,%0" : : "r" ((const void *) (x)))
2392#endif
2393#endif
2394#ifdef OPENBSD
2395#if defined(__powerpc64__)
2396#define ALIGNMENT 8
2397#define CPP_WORDSZ 64
2398#else
2399#define ALIGNMENT 4
2400#endif
2401#endif
2402#ifdef FREEBSD
2403#if defined(__powerpc64__)
2404#define ALIGNMENT 8
2405#define CPP_WORDSZ 64
2406#ifndef HBLKSIZE
2407#define HBLKSIZE 4096
2408#endif
2409#else
2410#define ALIGNMENT 4
2411#endif
2412#define SIG_SUSPEND SIGUSR1
2413#define SIG_THR_RESTART SIGUSR2
2414#endif
2415#ifdef NETBSD
2416#define ALIGNMENT 4
2417#endif
2418#ifdef SN_TARGET_PS3
2419#define OS_TYPE "SN_TARGET_PS3"
2420#define NO_GETENV
2421#define CPP_WORDSZ 32
2422#define ALIGNMENT 4
2423 extern int _end[];
2424 extern int __bss_start;
2425#define DATASTART ((ptr_t)(__bss_start))
2426#define DATAEND ((ptr_t)(_end))
2427#define STACKBOTTOM ((ptr_t)ps3_get_stack_bottom())
2428#define NO_PTHREAD_TRYLOCK
2429#endif
2430#ifdef AIX
2431#define OS_TYPE "AIX"
2432#undef ALIGNMENT
2433#undef IA64
2434#ifdef __64BIT__
2435#define ALIGNMENT 8
2436#define CPP_WORDSZ 64
2437#define STACKBOTTOM ((ptr_t)0x1000000000000000)
2438#else
2439#define ALIGNMENT 4
2440#define CPP_WORDSZ 32
2441#define STACKBOTTOM ((ptr_t)((ulong)&errno))
2442#endif
2443#define USE_MMAP_ANON
2444 extern int _data[], _end[];
2445#define DATASTART ((ptr_t)((ulong)_data))
2446#define DATAEND ((ptr_t)((ulong)_end))
2447 extern int errno;
2448#define DYNAMIC_LOADING
2449#endif
2450#ifdef NOSYS
2451#define OS_TYPE "NOSYS"
2452#define ALIGNMENT 4
2453 extern void __end[], __dso_handle[];
2454#define DATASTART ((ptr_t)__dso_handle)
2455#define DATAEND ((ptr_t)(__end))
2456#undef STACK_GRAN
2457#define STACK_GRAN 0x10000000
2458#define HEURISTIC1
2459#endif
2460#endif
2461#ifdef NACL
2462#define OS_TYPE "NACL"
2463#if defined(__GLIBC__)
2464#define DYNAMIC_LOADING
2465#endif
2466#define DATASTART ((ptr_t)0x10020000)
2467 extern int _end[];
2468#define DATAEND ((ptr_t)_end)
2469#undef STACK_GRAN
2470#define STACK_GRAN 0x10000
2471#define HEURISTIC1
2472#define NO_PTHREAD_GETATTR_NP
2473#define USE_MMAP_ANON
2474#define GETPAGESIZE() 65536
2475#define MAX_NACL_GC_THREADS 1024
2476#endif
2477#ifdef VAX
2478#define MACH_TYPE "VAX"
2479#define ALIGNMENT 4
2480 extern char etext[];
2481#define DATASTART ((ptr_t)(etext))
2482#ifdef BSD
2483#define OS_TYPE "BSD"
2484#define HEURISTIC1
2485#endif
2486#ifdef ULTRIX
2487#define OS_TYPE "ULTRIX"
2488#define STACKBOTTOM ((ptr_t)0x7fffc800)
2489#endif
2490#endif
2491#ifdef SPARC
2492#define MACH_TYPE "SPARC"
2493#if defined(__arch64__) || defined(__sparcv9)
2494#define ALIGNMENT 8
2495#define CPP_WORDSZ 64
2496#define ELF_CLASS ELFCLASS64
2497#else
2498#define ALIGNMENT 4
2499#define CPP_WORDSZ 32
2500#endif
2501#ifdef SOLARIS
2502#define DATASTART GC_SysVGetDataStart(0x10000, (ptr_t)_etext)
2503#define PROC_VDB
2504#define GETPAGESIZE() (unsigned)sysconf(_SC_PAGESIZE)
2505#endif
2506#ifdef DRSNX
2507#define OS_TYPE "DRSNX"
2508 extern int etext[];
2509 ptr_t GC_SysVGetDataStart(size_t, ptr_t);
2510#define DATASTART GC_SysVGetDataStart(0x10000, (ptr_t)etext)
2511#define DATASTART_IS_FUNC
2512#define MPROTECT_VDB
2513#define STACKBOTTOM ((ptr_t)0xdfff0000)
2514#define DYNAMIC_LOADING
2515#endif
2516#ifdef LINUX
2517#if !defined(__ELF__) && !defined(CPPCHECK)
2518#error Linux SPARC a.out not supported
2519#endif
2520#define SVR4
2521 extern int _etext[];
2522 ptr_t GC_SysVGetDataStart(size_t, ptr_t);
2523#ifdef __arch64__
2524#define DATASTART GC_SysVGetDataStart(0x100000, (ptr_t)_etext)
2525#else
2526#define DATASTART GC_SysVGetDataStart(0x10000, (ptr_t)_etext)
2527#endif
2528#define DATASTART_IS_FUNC
2529#endif
2530#ifdef OPENBSD
2531#endif
2532#ifdef NETBSD
2533#endif
2534#ifdef FREEBSD
2535#define SIG_SUSPEND SIGUSR1
2536#define SIG_THR_RESTART SIGUSR2
2537 extern char etext[];
2538 extern char edata[];
2539#if !defined(CPPCHECK)
2540 extern char end[];
2541#endif
2542#define NEED_FIND_LIMIT
2543#define DATASTART ((ptr_t)(&etext))
2544 void * GC_find_limit(void *, int);
2545#define DATAEND (ptr_t)GC_find_limit(DATASTART, TRUE)
2546#define DATAEND_IS_FUNC
2547#define GC_HAVE_DATAREGION2
2548#define DATASTART2 ((ptr_t)(&edata))
2549#define DATAEND2 ((ptr_t)(&end))
2550#endif
2551#endif
2552#ifdef I386
2553#define MACH_TYPE "I386"
2554#if (defined(__LP64__) || defined(_WIN64)) && !defined(CPPCHECK)
2555#error This should be handled as X86_64
2556#else
2557#define CPP_WORDSZ 32
2558#define ALIGNMENT 4
2559#endif
2560#ifdef SEQUENT
2561#define OS_TYPE "SEQUENT"
2562 extern int etext[];
2563#define DATASTART ((ptr_t)((((word)(etext)) + 0xfff) & ~0xfff))
2564#define STACKBOTTOM ((ptr_t)0x3ffff000)
2565#endif
2566#ifdef EMSCRIPTEN
2567#define OS_TYPE "EMSCRIPTEN"
2568#define DATASTART (ptr_t)ALIGNMENT
2569#define DATAEND (ptr_t)ALIGNMENT
2570#define USE_MMAP_ANON
2571#define STACK_GROWS_DOWN
2572#endif
2573#if defined(__QNX__)
2574#define OS_TYPE "QNX"
2575#define SA_RESTART 0
2576#define HEURISTIC1
2577 extern char etext[];
2578 extern int _end[];
2579#define DATASTART ((ptr_t)etext)
2580#define DATAEND ((ptr_t)_end)
2581#endif
2582#ifdef HAIKU
2583 extern int etext[];
2584#define DATASTART ((ptr_t)((((word)(etext)) + 0xfff) & ~0xfff))
2585#endif
2586#ifdef SOLARIS
2587#define DATASTART GC_SysVGetDataStart(0x1000, (ptr_t)_etext)
2588#ifdef SOLARIS25_PROC_VDB_BUG_FIXED
2589#define PROC_VDB
2590#endif
2591#endif
2592#ifdef SCO
2593#define OS_TYPE "SCO"
2594 extern int etext[];
2595#define DATASTART ((ptr_t)((((word)(etext)) + 0x3fffff) & ~0x3fffff) \
2596 + ((word)(etext) & 0xfff))
2597#define STACKBOTTOM ((ptr_t)0x7ffffffc)
2598#endif
2599#ifdef SCO_ELF
2600#define OS_TYPE "SCO_ELF"
2601 extern int etext[];
2602#define DATASTART ((ptr_t)(etext))
2603#define STACKBOTTOM ((ptr_t)0x08048000)
2604#define DYNAMIC_LOADING
2605#define ELF_CLASS ELFCLASS32
2606#endif
2607#ifdef DGUX
2608#define OS_TYPE "DGUX"
2609 extern int _etext, _end;
2610 ptr_t GC_SysVGetDataStart(size_t, ptr_t);
2611#define DATASTART GC_SysVGetDataStart(0x1000, (ptr_t)(&_etext))
2612#define DATASTART_IS_FUNC
2613#define DATAEND ((ptr_t)(&_end))
2614#define STACK_GROWS_DOWN
2615#define HEURISTIC2
2616 EXTERN_C_END
2617#include <unistd.h>
2618 EXTERN_C_BEGIN
2619#define GETPAGESIZE() (unsigned)sysconf(_SC_PAGESIZE)
2620#define DYNAMIC_LOADING
2621#ifndef USE_MMAP
2622#define USE_MMAP 1
2623#endif
2624#define MAP_FAILED (void *) ((word)-1)
2625#define HEAP_START (ptr_t)0x40000000
2626#endif
2627#ifdef LINUX
2628#if !defined(REDIRECT_MALLOC)
2629#define MPROTECT_VDB
2630#else
2631#endif
2632#define HEAP_START (ptr_t)0x1000
2633#ifdef __ELF__
2634#if defined(__GLIBC__) && __GLIBC__ >= 2 \
2635 || defined(HOST_ANDROID) || defined(HOST_TIZEN)
2636#define SEARCH_FOR_DATA_START
2637#else
2638 extern char **__environ;
2639#define DATASTART ((ptr_t)(&__environ))
2640#endif
2641#if !defined(GC_NO_SIGSETJMP) && (defined(HOST_TIZEN) \
2642 || (defined(HOST_ANDROID) \
2643 && !(GC_GNUC_PREREQ(4, 8) || GC_CLANG_PREREQ(3, 2) \
2644 || __ANDROID_API__ >= 18)))
2645#define GC_NO_SIGSETJMP 1
2646#endif
2647#else
2648 extern int etext[];
2649#define DATASTART ((ptr_t)((((word)(etext)) + 0xfff) & ~0xfff))
2650#endif
2651#ifdef USE_I686_PREFETCH
2652#define PREFETCH(x) \
2653 __asm__ __volatile__ ("prefetchnta %0" : : "m"(*(char *)(x)))
2654#ifdef FORCE_WRITE_PREFETCH
2655#define GC_PREFETCH_FOR_WRITE(x) \
2656 __asm__ __volatile__ ("prefetcht0 %0" : : "m"(*(char *)(x)))
2657#else
2658#define GC_NO_PREFETCH_FOR_WRITE
2659#endif
2660#elif defined(USE_3DNOW_PREFETCH)
2661#define PREFETCH(x) \
2662 __asm__ __volatile__ ("prefetch %0" : : "m"(*(char *)(x)))
2663#define GC_PREFETCH_FOR_WRITE(x) \
2664 __asm__ __volatile__ ("prefetchw %0" : : "m"(*(char *)(x)))
2665#endif
2666#if defined(__GLIBC__) && !defined(__UCLIBC__) \
2667 && !defined(GLIBC_TSX_BUG_FIXED)
2668#define GLIBC_2_19_TSX_BUG
2669 EXTERN_C_END
2670#include <gnu/libc-version.h>
2671 EXTERN_C_BEGIN
2672#endif
2673#ifndef SOFT_VDB
2674#define SOFT_VDB
2675#endif
2676#endif
2677#ifdef CYGWIN32
2678#define WOW64_THREAD_CONTEXT_WORKAROUND
2679#define DATASTART ((ptr_t)GC_DATASTART)
2680#define DATAEND ((ptr_t)GC_DATAEND)
2681#ifndef USE_WINALLOC
2682#
2683#ifdef USE_MMAP
2684#define NEED_FIND_LIMIT
2685#endif
2686#endif
2687#endif
2688#ifdef INTERIX
2689#define OS_TYPE "INTERIX"
2690 extern int _data_start__[];
2691 extern int _bss_end__[];
2692#define DATASTART ((ptr_t)_data_start__)
2693#define DATAEND ((ptr_t)_bss_end__)
2694#define STACKBOTTOM ({ ptr_t rv; \
2695 __asm__ __volatile__ ("movl %%fs:4, %%eax" \
2696 : "=a" (rv)); \
2697 rv; })
2698#define USE_MMAP_ANON
2699#endif
2700#ifdef OS2
2701#define OS_TYPE "OS2"
2702#define DATAEND
2703#endif
2704#ifdef MSWIN32
2705#define WOW64_THREAD_CONTEXT_WORKAROUND
2706#define RETRY_GET_THREAD_CONTEXT
2707#define MPROTECT_VDB
2708#endif
2709#ifdef MSWINCE
2710#endif
2711#ifdef DJGPP
2712#define OS_TYPE "DJGPP"
2713 EXTERN_C_END
2714#include "stubinfo.h"
2715 EXTERN_C_BEGIN
2716 extern int etext[];
2717 extern int _stklen;
2718 extern int __djgpp_stack_limit;
2719#define DATASTART ((ptr_t)((((word)(etext)) + 0x1ff) & ~0x1ff))
2720#define STACKBOTTOM ((ptr_t)((word)__djgpp_stack_limit + _stklen))
2721#endif
2722#ifdef OPENBSD
2723#endif
2724#ifdef FREEBSD
2725#ifdef __GLIBC__
2726#define SIG_SUSPEND (32+6)
2727#define SIG_THR_RESTART (32+5)
2728 extern int _end[];
2729#define DATAEND ((ptr_t)(_end))
2730#else
2731#define SIG_SUSPEND SIGUSR1
2732#define SIG_THR_RESTART SIGUSR2
2733#endif
2734#endif
2735#ifdef NETBSD
2736#endif
2737#ifdef THREE86BSD
2738#define OS_TYPE "THREE86BSD"
2739#define HEURISTIC2
2740 extern char etext[];
2741#define DATASTART ((ptr_t)(etext))
2742#endif
2743#ifdef BSDI
2744#define OS_TYPE "BSDI"
2745#define HEURISTIC2
2746 extern char etext[];
2747#define DATASTART ((ptr_t)(etext))
2748#endif
2749#ifdef NEXT
2750#define STACKBOTTOM ((ptr_t)0xc0000000)
2751#endif
2752#ifdef RTEMS
2753#define OS_TYPE "RTEMS"
2754 EXTERN_C_END
2755#include <sys/unistd.h>
2756 EXTERN_C_BEGIN
2757 extern int etext[];
2758 void *rtems_get_stack_bottom(void);
2759#define InitStackBottom rtems_get_stack_bottom()
2760#define DATASTART ((ptr_t)etext)
2761#define STACKBOTTOM ((ptr_t)InitStackBottom)
2762#define SIG_SUSPEND SIGUSR1
2763#define SIG_THR_RESTART SIGUSR2
2764#endif
2765#ifdef DOS4GW
2766#define OS_TYPE "DOS4GW"
2767 extern long __nullarea;
2768 extern char _end;
2769 extern char *_STACKTOP;
2770 #pragma aux __nullarea "*";
2771 #pragma aux _end "*";
2772#define STACKBOTTOM ((ptr_t)_STACKTOP)
2773#define DATASTART ((ptr_t)(&__nullarea))
2774#define DATAEND ((ptr_t)(&_end))
2775#endif
2776#ifdef HURD
2777#define OS_TYPE "HURD"
2778#define STACK_GROWS_DOWN
2779#define HEURISTIC2
2780#define SIG_SUSPEND SIGUSR1
2781#define SIG_THR_RESTART SIGUSR2
2782#define SEARCH_FOR_DATA_START
2783 extern int _end[];
2784#define DATAEND ((ptr_t)(_end))
2785#define DYNAMIC_LOADING
2786#define USE_MMAP_ANON
2787#endif
2788#ifdef DARWIN
2789#define DARWIN_DONT_PARSE_STACK 1
2790#define STACKBOTTOM ((ptr_t)0xc0000000)
2791#define MPROTECT_VDB
2792#if TARGET_OS_IPHONE && !defined(NO_DYLD_BIND_FULLY_IMAGE)
2793#define NO_DYLD_BIND_FULLY_IMAGE
2794#endif
2795#endif
2796#endif
2797#ifdef NS32K
2798#define MACH_TYPE "NS32K"
2799#define ALIGNMENT 4
2800 extern char **environ;
2801#define DATASTART ((ptr_t)(&environ))
2802#define STACKBOTTOM ((ptr_t)0xfffff000)
2803#endif
2804#ifdef LOONGARCH
2805#define MACH_TYPE "LoongArch"
2806#ifdef LINUX
2807#pragma weak __data_start
2808 extern int __data_start[];
2809#define DATASTART ((ptr_t)(__data_start))
2810#define CPP_WORDSZ _LOONGARCH_SZPTR
2811#define ALIGNMENT (_LOONGARCH_SZPTR/8)
2812#endif
2813#endif
2814#ifdef MIPS
2815#define MACH_TYPE "MIPS"
2816#ifdef LINUX
2817#pragma weak __data_start
2818 extern int __data_start[];
2819#define DATASTART ((ptr_t)(__data_start))
2820#ifdef _MIPS_SZPTR
2821#define CPP_WORDSZ _MIPS_SZPTR
2822#define ALIGNMENT (_MIPS_SZPTR/8)
2823#else
2824#define ALIGNMENT 4
2825#endif
2826#ifndef HBLKSIZE
2827#define HBLKSIZE 4096
2828#endif
2829#if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 2 || __GLIBC__ > 2
2830#define LINUX_STACKBOTTOM
2831#else
2832#define STACKBOTTOM ((ptr_t)0x7fff8000)
2833#endif
2834#endif
2835#ifdef EWS4800
2836#define OS_TYPE "EWS4800"
2837#define HEURISTIC2
2838#if defined(_MIPS_SZPTR) && (_MIPS_SZPTR == 64)
2839 extern int _fdata[], _end[];
2840#define DATASTART ((ptr_t)_fdata)
2841#define DATAEND ((ptr_t)_end)
2842#define CPP_WORDSZ _MIPS_SZPTR
2843#define ALIGNMENT (_MIPS_SZPTR/8)
2844#else
2845 extern int etext[], edata[];
2846#if !defined(CPPCHECK)
2847 extern int end[];
2848#endif
2849 extern int _DYNAMIC_LINKING[], _gp[];
2850#define DATASTART ((ptr_t)((((word)(etext) + 0x3ffff) & ~0x3ffff) \
2851 + ((word)(etext) & 0xffff)))
2852#define DATAEND ((ptr_t)(edata))
2853#define GC_HAVE_DATAREGION2
2854#define DATASTART2 (_DYNAMIC_LINKING \
2855 ? (ptr_t)(((word)_gp + 0x8000 + 0x3ffff) & ~0x3ffff) \
2856 : (ptr_t)edata)
2857#define DATAEND2 ((ptr_t)(end))
2858#define ALIGNMENT 4
2859#endif
2860#endif
2861#ifdef ULTRIX
2862#define OS_TYPE "ULTRIX"
2863#define HEURISTIC2
2864#define DATASTART ((ptr_t)0x10000000)
2865#define ALIGNMENT 4
2866#endif
2867#ifdef IRIX5
2868#define OS_TYPE "IRIX5"
2869#define HEURISTIC2
2870 extern int _fdata[];
2871#define DATASTART ((ptr_t)(_fdata))
2872#ifdef USE_MMAP
2873#define HEAP_START (ptr_t)0x30000000
2874#else
2875#define HEAP_START DATASTART
2876#endif
2877#ifdef _MIPS_SZPTR
2878#define CPP_WORDSZ _MIPS_SZPTR
2879#define ALIGNMENT (_MIPS_SZPTR/8)
2880#else
2881#define ALIGNMENT 4
2882#endif
2883#define DYNAMIC_LOADING
2884#endif
2885#ifdef MSWINCE
2886#define ALIGNMENT 4
2887#endif
2888#ifdef NETBSD
2889#define ALIGNMENT 4
2890#ifndef __ELF__
2891#define DATASTART ((ptr_t)0x10000000)
2892#define STACKBOTTOM ((ptr_t)0x7ffff000)
2893#endif
2894#endif
2895#ifdef OPENBSD
2896#define CPP_WORDSZ 64
2897#define ALIGNMENT 8
2898#endif
2899#ifdef FREEBSD
2900#define ALIGNMENT 4
2901#define SIG_SUSPEND SIGUSR1
2902#define SIG_THR_RESTART SIGUSR2
2903#endif
2904#ifdef NONSTOP
2905#define OS_TYPE "NONSTOP"
2906#define CPP_WORDSZ 32
2907#define ALIGNMENT 4
2908#define DATASTART ((ptr_t)0x08000000)
2909 extern char **environ;
2910#define DATAEND ((ptr_t)(environ - 0x10))
2911#define STACKBOTTOM ((ptr_t)0x4fffffff)
2912#endif
2913#endif
2914#ifdef NIOS2
2915#define CPP_WORDSZ 32
2916#define MACH_TYPE "NIOS2"
2917#ifdef LINUX
2918 extern int __data_start[];
2919#define DATASTART ((ptr_t)(__data_start))
2920#define ALIGNMENT 4
2921#ifndef HBLKSIZE
2922#define HBLKSIZE 4096
2923#endif
2924#endif
2925#endif
2926#ifdef OR1K
2927#define CPP_WORDSZ 32
2928#define MACH_TYPE "OR1K"
2929#ifdef LINUX
2930 extern int __data_start[];
2931#define DATASTART ((ptr_t)(__data_start))
2932#define ALIGNMENT 4
2933#ifndef HBLKSIZE
2934#define HBLKSIZE 4096
2935#endif
2936#endif
2937#endif
2938#ifdef HP_PA
2939#define MACH_TYPE "HP_PA"
2940#ifdef __LP64__
2941#define CPP_WORDSZ 64
2942#define ALIGNMENT 8
2943#else
2944#define CPP_WORDSZ 32
2945#define ALIGNMENT 4
2946#endif
2947#define STACK_GROWS_UP
2948#ifdef HPUX
2949#ifndef GC_THREADS
2950#define MPROTECT_VDB
2951#endif
2952#ifdef USE_HPUX_FIXED_STACKBOTTOM
2953#define STACKBOTTOM ((ptr_t)0x7b033000)
2954#elif defined(USE_ENVIRON_POINTER)
2955 extern char ** environ;
2956#define STACKBOTTOM ((ptr_t)environ)
2957#elif !defined(HEURISTIC2)
2958#define HPUX_MAIN_STACKBOTTOM
2959#define NEED_FIND_LIMIT
2960#endif
2961#ifndef __GNUC__
2962#define PREFETCH(x) do { \
2963 register long addr = (long)(x); \
2964 (void) _asm ("LDW", 0, 0, addr, 0); \
2965 } while (0)
2966#endif
2967#endif
2968#ifdef LINUX
2969#define SEARCH_FOR_DATA_START
2970#endif
2971#ifdef OPENBSD
2972#endif
2973#endif
2974#ifdef ALPHA
2975#define MACH_TYPE "ALPHA"
2976#define ALIGNMENT 8
2977#define CPP_WORDSZ 64
2978#ifdef NETBSD
2979#define ELFCLASS32 32
2980#define ELFCLASS64 64
2981#define ELF_CLASS ELFCLASS64
2982#endif
2983#ifdef OPENBSD
2984#endif
2985#ifdef FREEBSD
2986#define SIG_SUSPEND SIGUSR1
2987#define SIG_THR_RESTART SIGUSR2
2988 extern char etext[];
2989 extern char edata[];
2990#if !defined(CPPCHECK)
2991 extern char end[];
2992#endif
2993#define NEED_FIND_LIMIT
2994#define DATASTART ((ptr_t)(&etext))
2995 void * GC_find_limit(void *, int);
2996#define DATAEND (ptr_t)GC_find_limit(DATASTART, TRUE)
2997#define DATAEND_IS_FUNC
2998#define GC_HAVE_DATAREGION2
2999#define DATASTART2 ((ptr_t)(&edata))
3000#define DATAEND2 ((ptr_t)(&end))
3001#endif
3002#ifdef OSF1
3003#define OS_TYPE "OSF1"
3004#define DATASTART ((ptr_t)0x140000000)
3005 extern int _end[];
3006#define DATAEND ((ptr_t)(&_end))
3007 extern char ** environ;
3008#define STACKBOTTOM ((ptr_t)(((word)(environ) | (getpagesize()-1))+1))
3009 extern int __start[];
3010#define HEURISTIC2_LIMIT ((ptr_t)((word)(__start) & ~(getpagesize()-1)))
3011#ifndef GC_OSF1_THREADS
3012#define MPROTECT_VDB
3013#endif
3014#define DYNAMIC_LOADING
3015#endif
3016#ifdef LINUX
3017#ifdef __ELF__
3018#define SEARCH_FOR_DATA_START
3019#else
3020#define DATASTART ((ptr_t)0x140000000)
3021 extern int _end[];
3022#define DATAEND ((ptr_t)(_end))
3023#endif
3024#if !defined(REDIRECT_MALLOC)
3025#define MPROTECT_VDB
3026#endif
3027#endif
3028#endif
3029#ifdef IA64
3030#define MACH_TYPE "IA64"
3031#ifdef HPUX
3032#ifdef _ILP32
3033#define CPP_WORDSZ 32
3034#define ALIGNMENT 4
3035#else
3036#if !defined(_LP64) && !defined(CPPCHECK)
3037#error Unknown ABI
3038#endif
3039#define CPP_WORDSZ 64
3040#define ALIGNMENT 8
3041#endif
3042 extern char ** environ;
3043#define STACKBOTTOM ((ptr_t)environ)
3044#define HPUX_STACKBOTTOM
3045#define BACKING_STORE_DISPLACEMENT 0x1000000
3046#define BACKING_STORE_ALIGNMENT 0x1000
3047 extern ptr_t GC_register_stackbottom;
3048#define BACKING_STORE_BASE GC_register_stackbottom
3049#endif
3050#ifdef LINUX
3051#define CPP_WORDSZ 64
3052#define ALIGNMENT 8
3053 extern ptr_t GC_register_stackbottom;
3054#define BACKING_STORE_BASE GC_register_stackbottom
3055#define SEARCH_FOR_DATA_START
3056#ifdef __GNUC__
3057#define DYNAMIC_LOADING
3058#else
3059#endif
3060#if !defined(REDIRECT_MALLOC)
3061#define MPROTECT_VDB
3062#endif
3063#ifdef __GNUC__
3064#ifndef __INTEL_COMPILER
3065#define PREFETCH(x) \
3066 __asm__ (" lfetch [%0]": : "r"(x))
3067#define GC_PREFETCH_FOR_WRITE(x) \
3068 __asm__ (" lfetch.excl [%0]": : "r"(x))
3069#define CLEAR_DOUBLE(x) \
3070 __asm__ (" stf.spill [%0]=f0": : "r"((void *)(x)))
3071#else
3072 EXTERN_C_END
3073#include <ia64intrin.h>
3074 EXTERN_C_BEGIN
3075#define PREFETCH(x) __lfetch(__lfhint_none, (x))
3076#define GC_PREFETCH_FOR_WRITE(x) __lfetch(__lfhint_nta, (x))
3077#define CLEAR_DOUBLE(x) __stf_spill((void *)(x), 0)
3078#endif
3079#endif
3080#endif
3081#ifdef MSWIN32
3082#if defined(_WIN64)
3083#define CPP_WORDSZ 64
3084#else
3085#define CPP_WORDSZ 32
3086#endif
3087#define ALIGNMENT 8
3088#endif
3089#endif
3090#ifdef M88K
3091#define MACH_TYPE "M88K"
3092#define ALIGNMENT 4
3093#define STACKBOTTOM ((char*)0xf0000000)
3094 extern int etext[];
3095#ifdef CX_UX
3096#define OS_TYPE "CX_UX"
3097#define DATASTART ((ptr_t)((((word)(etext) + 0x3fffff) & ~0x3fffff) \
3098 + 0x10000))
3099#endif
3100#ifdef DGUX
3101#define OS_TYPE "DGUX"
3102 ptr_t GC_SysVGetDataStart(size_t, ptr_t);
3103#define DATASTART GC_SysVGetDataStart(0x10000, (ptr_t)etext)
3104#define DATASTART_IS_FUNC
3105#endif
3106#endif
3107#ifdef S370
3108#define MACH_TYPE "S370"
3109#define ALIGNMENT 4
3110#ifdef UTS4
3111#define OS_TYPE "UTS4"
3112 extern int etext[];
3113 extern int _etext[];
3114 extern int _end[];
3115 ptr_t GC_SysVGetDataStart(size_t, ptr_t);
3116#define DATASTART GC_SysVGetDataStart(0x10000, (ptr_t)_etext)
3117#define DATASTART_IS_FUNC
3118#define DATAEND ((ptr_t)(_end))
3119#define HEURISTIC2
3120#endif
3121#endif
3122#ifdef S390
3123#define MACH_TYPE "S390"
3124#ifndef __s390x__
3125#define ALIGNMENT 4
3126#define CPP_WORDSZ 32
3127#else
3128#define ALIGNMENT 8
3129#define CPP_WORDSZ 64
3130#ifndef HBLKSIZE
3131#define HBLKSIZE 4096
3132#endif
3133#endif
3134#ifdef LINUX
3135 extern int __data_start[] __attribute__((__weak__));
3136#define DATASTART ((ptr_t)(__data_start))
3137 extern int _end[] __attribute__((__weak__));
3138#define DATAEND ((ptr_t)(_end))
3139#define CACHE_LINE_SIZE 256
3140#define GETPAGESIZE() 4096
3141#if !defined(REDIRECT_MALLOC)
3142#define MPROTECT_VDB
3143#endif
3144#ifndef SOFT_VDB
3145#define SOFT_VDB
3146#endif
3147#endif
3148#endif
3149#ifdef AARCH64
3150#define MACH_TYPE "AARCH64"
3151#ifdef __ILP32__
3152#define CPP_WORDSZ 32
3153#define ALIGNMENT 4
3154#else
3155#define CPP_WORDSZ 64
3156#define ALIGNMENT 8
3157#endif
3158#ifndef HBLKSIZE
3159#define HBLKSIZE 4096
3160#endif
3161#ifdef LINUX
3162#if !defined(REDIRECT_MALLOC)
3163#define MPROTECT_VDB
3164#endif
3165#if defined(HOST_ANDROID)
3166#define SEARCH_FOR_DATA_START
3167#else
3168 extern int __data_start[];
3169#define DATASTART ((ptr_t)__data_start)
3170#endif
3171#endif
3172#ifdef DARWIN
3173#define DARWIN_DONT_PARSE_STACK 1
3174#define STACKBOTTOM ((ptr_t)0x16fdfffff)
3175#if TARGET_OS_IPHONE && !defined(NO_DYLD_BIND_FULLY_IMAGE)
3176#define NO_DYLD_BIND_FULLY_IMAGE
3177#endif
3178#endif
3179#ifdef FREEBSD
3180#endif
3181#ifdef NETBSD
3182#define ELF_CLASS ELFCLASS64
3183#endif
3184#ifdef OPENBSD
3185#endif
3186#ifdef NINTENDO_SWITCH
3187#define OS_TYPE "NINTENDO_SWITCH"
3188 extern int __bss_end[];
3189#define NO_HANDLE_FORK 1
3190#define DATASTART (ptr_t)ALIGNMENT
3191#define DATAEND (ptr_t)(&__bss_end)
3192 void *switch_get_stack_bottom(void);
3193#define STACKBOTTOM ((ptr_t)switch_get_stack_bottom())
3194#endif
3195#ifdef MSWIN32
3196#endif
3197#ifdef NOSYS
3198#define OS_TYPE "NOSYS"
3199 extern int __data_start[];
3200#define DATASTART ((ptr_t)__data_start)
3201 extern void *__stack_base__;
3202#define STACKBOTTOM ((ptr_t)__stack_base__)
3203#endif
3204#endif
3205#ifdef ARM32
3206#if defined(NACL)
3207#define MACH_TYPE "NACL"
3208#else
3209#define MACH_TYPE "ARM32"
3210#endif
3211#define CPP_WORDSZ 32
3212#define ALIGNMENT 4
3213#ifdef NETBSD
3214#endif
3215#ifdef LINUX
3216#if !defined(REDIRECT_MALLOC)
3217#define MPROTECT_VDB
3218#endif
3219#if defined(__GLIBC__) && __GLIBC__ >= 2 \
3220 || defined(HOST_ANDROID) || defined(HOST_TIZEN)
3221#define SEARCH_FOR_DATA_START
3222#else
3223 extern char **__environ;
3224#define DATASTART ((ptr_t)(&__environ))
3225#endif
3226#endif
3227#ifdef MSWINCE
3228#endif
3229#ifdef FREEBSD
3230#define SIG_SUSPEND SIGUSR1
3231#define SIG_THR_RESTART SIGUSR2
3232#endif
3233#ifdef DARWIN
3234#define DARWIN_DONT_PARSE_STACK 1
3235#define STACKBOTTOM ((ptr_t)0x30000000)
3236#if TARGET_OS_IPHONE && !defined(NO_DYLD_BIND_FULLY_IMAGE)
3237#define NO_DYLD_BIND_FULLY_IMAGE
3238#endif
3239#endif
3240#ifdef OPENBSD
3241#endif
3242#ifdef SN_TARGET_PSP2
3243#define OS_TYPE "SN_TARGET_PSP2"
3244#define NO_HANDLE_FORK 1
3245#define DATASTART (ptr_t)ALIGNMENT
3246#define DATAEND (ptr_t)ALIGNMENT
3247 void *psp2_get_stack_bottom(void);
3248#define STACKBOTTOM ((ptr_t)psp2_get_stack_bottom())
3249#endif
3250#ifdef NN_PLATFORM_CTR
3251#define OS_TYPE "NN_PLATFORM_CTR"
3252 extern unsigned char Image$$ZI$$ZI$$Base[];
3253#define DATASTART (ptr_t)(Image$$ZI$$ZI$$Base)
3254 extern unsigned char Image$$ZI$$ZI$$Limit[];
3255#define DATAEND (ptr_t)(Image$$ZI$$ZI$$Limit)
3256 void *n3ds_get_stack_bottom(void);
3257#define STACKBOTTOM ((ptr_t)n3ds_get_stack_bottom())
3258#endif
3259#ifdef MSWIN32
3260#endif
3261#ifdef NOSYS
3262#define OS_TYPE "NOSYS"
3263 extern int __data_start[];
3264#define DATASTART ((ptr_t)(__data_start))
3265 extern void *__stack_base__;
3266#define STACKBOTTOM ((ptr_t)(__stack_base__))
3267#endif
3268#endif
3269#ifdef CRIS
3270#define MACH_TYPE "CRIS"
3271#define CPP_WORDSZ 32
3272#define ALIGNMENT 1
3273#ifdef LINUX
3274#define SEARCH_FOR_DATA_START
3275#endif
3276#endif
3277#if defined(SH) && !defined(SH4)
3278#define MACH_TYPE "SH"
3279#define ALIGNMENT 4
3280#ifdef LINUX
3281#define SEARCH_FOR_DATA_START
3282#endif
3283#ifdef NETBSD
3284#endif
3285#ifdef OPENBSD
3286#endif
3287#ifdef MSWINCE
3288#endif
3289#endif
3290#ifdef SH4
3291#define MACH_TYPE "SH4"
3292#define ALIGNMENT 4
3293#ifdef MSWINCE
3294#endif
3295#endif
3296#ifdef AVR32
3297#define MACH_TYPE "AVR32"
3298#define CPP_WORDSZ 32
3299#define ALIGNMENT 4
3300#ifdef LINUX
3301#define SEARCH_FOR_DATA_START
3302#endif
3303#endif
3304#ifdef M32R
3305#define CPP_WORDSZ 32
3306#define MACH_TYPE "M32R"
3307#define ALIGNMENT 4
3308#ifdef LINUX
3309#define SEARCH_FOR_DATA_START
3310#endif
3311#endif
3312#ifdef X86_64
3313#define MACH_TYPE "X86_64"
3314#ifdef __ILP32__
3315#define ALIGNMENT 4
3316#define CPP_WORDSZ 32
3317#else
3318#define ALIGNMENT 8
3319#define CPP_WORDSZ 64
3320#endif
3321#ifndef HBLKSIZE
3322#define HBLKSIZE 4096
3323#endif
3324#ifndef CACHE_LINE_SIZE
3325#define CACHE_LINE_SIZE 64
3326#endif
3327#ifdef PLATFORM_GETMEM
3328#define OS_TYPE "PLATFORM_GETMEM"
3329#define DATASTART (ptr_t)ALIGNMENT
3330#define DATAEND (ptr_t)ALIGNMENT
3331 EXTERN_C_END
3332#include <pthread.h>
3333 EXTERN_C_BEGIN
3334 void *platform_get_stack_bottom(void);
3335#define STACKBOTTOM ((ptr_t)platform_get_stack_bottom())
3336#endif
3337#ifdef LINUX
3338#if !defined(REDIRECT_MALLOC)
3339#define MPROTECT_VDB
3340#else
3341#endif
3342#define SEARCH_FOR_DATA_START
3343#if defined(__GLIBC__) && !defined(__UCLIBC__)
3344#define USE_MMAP_ANON
3345#endif
3346#if defined(__GLIBC__) && !defined(__UCLIBC__) \
3347 && !defined(GETCONTEXT_FPU_BUG_FIXED)
3348#define GETCONTEXT_FPU_EXCMASK_BUG
3349#endif
3350#if defined(__GLIBC__) && !defined(__UCLIBC__) \
3351 && !defined(GLIBC_TSX_BUG_FIXED)
3352#define GLIBC_2_19_TSX_BUG
3353 EXTERN_C_END
3354#include <gnu/libc-version.h>
3355 EXTERN_C_BEGIN
3356#endif
3357#ifndef SOFT_VDB
3358#define SOFT_VDB
3359#endif
3360#endif
3361#ifdef DARWIN
3362#define DARWIN_DONT_PARSE_STACK 1
3363#define STACKBOTTOM ((ptr_t)0x7fff5fc00000)
3364#define MPROTECT_VDB
3365#if TARGET_OS_IPHONE && !defined(NO_DYLD_BIND_FULLY_IMAGE)
3366#define NO_DYLD_BIND_FULLY_IMAGE
3367#endif
3368#endif
3369#ifdef FREEBSD
3370#ifdef __GLIBC__
3371#define SIG_SUSPEND (32+6)
3372#define SIG_THR_RESTART (32+5)
3373 extern int _end[];
3374#define DATAEND ((ptr_t)(_end))
3375#else
3376#define SIG_SUSPEND SIGUSR1
3377#define SIG_THR_RESTART SIGUSR2
3378#endif
3379#if defined(__DragonFly__)
3380#define COUNT_UNMAPPED_REGIONS
3381#endif
3382#endif
3383#ifdef NETBSD
3384#endif
3385#ifdef OPENBSD
3386#endif
3387#ifdef HAIKU
3388#define HEURISTIC2
3389#define SEARCH_FOR_DATA_START
3390#endif
3391#ifdef SOLARIS
3392#define ELF_CLASS ELFCLASS64
3393#define DATASTART GC_SysVGetDataStart(0x1000, (ptr_t)_etext)
3394#ifdef SOLARIS25_PROC_VDB_BUG_FIXED
3395#define PROC_VDB
3396#endif
3397#endif
3398#ifdef CYGWIN32
3399#ifndef USE_WINALLOC
3400#if defined(THREAD_LOCAL_ALLOC)
3401#else
3402#define MPROTECT_VDB
3403#endif
3404#endif
3405#endif
3406#ifdef MSWIN_XBOX1
3407#define OS_TYPE "MSWIN_XBOX1"
3408#define NO_GETENV
3409#define DATASTART (ptr_t)ALIGNMENT
3410#define DATAEND (ptr_t)ALIGNMENT
3411 LONG64 durango_get_stack_bottom(void);
3412#define STACKBOTTOM ((ptr_t)durango_get_stack_bottom())
3413#define GETPAGESIZE() 4096
3414#ifndef USE_MMAP
3415#define USE_MMAP 1
3416#endif
3417#define PROT_NONE 0
3418#define PROT_READ 1
3419#define PROT_WRITE 2
3420#define PROT_EXEC 4
3421#define MAP_PRIVATE 2
3422#define MAP_FIXED 0x10
3423#define MAP_FAILED ((void *)-1)
3424#endif
3425#ifdef MSWIN32
3426#define RETRY_GET_THREAD_CONTEXT
3427#if !defined(__GNUC__) || defined(__INTEL_COMPILER) \
3428 || GC_GNUC_PREREQ(4, 7)
3429#define MPROTECT_VDB
3430#endif
3431#endif
3432#endif
3433#ifdef ARC
3434#define CPP_WORDSZ 32
3435#define MACH_TYPE "ARC"
3436#define ALIGNMENT 4
3437#define CACHE_LINE_SIZE 64
3438#ifdef LINUX
3439 extern int __data_start[] __attribute__((__weak__));
3440#define DATASTART ((ptr_t)__data_start)
3441#endif
3442#endif
3443#ifdef HEXAGON
3444#define CPP_WORDSZ 32
3445#define MACH_TYPE "HEXAGON"
3446#define ALIGNMENT 4
3447#ifdef LINUX
3448#if !defined(REDIRECT_MALLOC)
3449#define MPROTECT_VDB
3450#endif
3451#if defined(__GLIBC__)
3452#define SEARCH_FOR_DATA_START
3453#elif !defined(CPPCHECK)
3454#error Unknown Hexagon libc configuration
3455#endif
3456#endif
3457#endif
3458#ifdef TILEPRO
3459#define CPP_WORDSZ 32
3460#define MACH_TYPE "TILEPro"
3461#define ALIGNMENT 4
3462#define PREFETCH(x) __insn_prefetch(x)
3463#define CACHE_LINE_SIZE 64
3464#ifdef LINUX
3465 extern int __data_start[];
3466#define DATASTART ((ptr_t)__data_start)
3467#endif
3468#endif
3469#ifdef TILEGX
3470#define CPP_WORDSZ (__SIZEOF_POINTER__ * 8)
3471#define MACH_TYPE "TILE-Gx"
3472#define ALIGNMENT __SIZEOF_POINTER__
3473#if CPP_WORDSZ < 64
3474#define CLEAR_DOUBLE(x) (*(long long *)(x) = 0)
3475#endif
3476#define PREFETCH(x) __insn_prefetch_l1(x)
3477#define CACHE_LINE_SIZE 64
3478#ifdef LINUX
3479 extern int __data_start[];
3480#define DATASTART ((ptr_t)__data_start)
3481#endif
3482#endif
3483#ifdef RISCV
3484#define MACH_TYPE "RISC-V"
3485#define CPP_WORDSZ __riscv_xlen
3486#define ALIGNMENT (CPP_WORDSZ/8)
3487#ifdef FREEBSD
3488#define SIG_SUSPEND SIGUSR1
3489#define SIG_THR_RESTART SIGUSR2
3490#endif
3491#ifdef LINUX
3492 extern int __data_start[] __attribute__((__weak__));
3493#define DATASTART ((ptr_t)__data_start)
3494#endif
3495#endif
3496#if defined(__GLIBC__) && !defined(DONT_USE_LIBC_PRIVATES)
3497#define USE_LIBC_PRIVATES
3498#endif
3499#ifdef NO_RETRY_GET_THREAD_CONTEXT
3500#undef RETRY_GET_THREAD_CONTEXT
3501#endif
3502#if defined(LINUX_STACKBOTTOM) && defined(NO_PROC_STAT) \
3503 && !defined(USE_LIBC_PRIVATES)
3504#undef LINUX_STACKBOTTOM
3505#define HEURISTIC2
3506#endif
3507#if defined(USE_MMAP_ANON) && !defined(USE_MMAP)
3508#define USE_MMAP 1
3509#elif (defined(LINUX) || defined(OPENBSD)) && defined(USE_MMAP)
3510#define USE_MMAP_ANON
3511#endif
3512#if defined(GC_LINUX_THREADS) && defined(REDIRECT_MALLOC) \
3513 && !defined(USE_PROC_FOR_LIBRARIES)
3514#define USE_PROC_FOR_LIBRARIES
3515#endif
3516#ifndef STACK_GROWS_UP
3517#define STACK_GROWS_DOWN
3518#endif
3519#ifndef CPP_WORDSZ
3520#define CPP_WORDSZ 32
3521#endif
3522#ifndef OS_TYPE
3523#define OS_TYPE ""
3524#endif
3525#ifndef DATAEND
3526#if !defined(CPPCHECK)
3527 extern int end[];
3528#endif
3529#define DATAEND ((ptr_t)(end))
3530#endif
3531#if defined(HOST_ANDROID) && defined(__clang__) \
3532 && !defined(BROKEN_UUENDUU_SYM)
3533#undef DATAEND
3534#pragma weak __end__
3535 extern int __end__[];
3536#define DATAEND (__end__ != 0 ? (ptr_t)__end__ : (ptr_t)_end)
3537#endif
3538#if (defined(SVR4) || defined(HOST_ANDROID) || defined(HOST_TIZEN)) \
3539 && !defined(GETPAGESIZE)
3540 EXTERN_C_END
3541#include <unistd.h>
3542 EXTERN_C_BEGIN
3543#define GETPAGESIZE() (unsigned)sysconf(_SC_PAGESIZE)
3544#endif
3545#ifndef GETPAGESIZE
3546#if defined(SOLARIS) || defined(IRIX5) || defined(LINUX) \
3547 || defined(NETBSD) || defined(FREEBSD) || defined(HPUX)
3548 EXTERN_C_END
3549#include <unistd.h>
3550 EXTERN_C_BEGIN
3551#endif
3552#define GETPAGESIZE() (unsigned)getpagesize()
3553#endif
3554#if defined(HOST_ANDROID) && !(__ANDROID_API__ >= 23) \
3555 && ((defined(MIPS) && (CPP_WORDSZ == 32)) \
3556 || defined(ARM32) || defined(I386) )
3557#define USE_TKILL_ON_ANDROID
3558#endif
3559#if defined(SOLARIS) || defined(DRSNX) || defined(UTS4)
3560#define SVR4
3561#endif
3562#if defined(SOLARIS) || defined(DRSNX)
3563#define SOLARISDL
3564#define SUNOS5SIGS
3565#endif
3566#if defined(HPUX)
3567#define SUNOS5SIGS
3568#endif
3569#if defined(FREEBSD) && (defined(__DragonFly__) || __FreeBSD__ >= 4 \
3570 || (__FreeBSD_kernel__ >= 4))
3571#define SUNOS5SIGS
3572#endif
3573#if !defined(GC_EXPLICIT_SIGNALS_UNBLOCK) && defined(SUNOS5SIGS) \
3574 && !defined(GC_NO_PTHREAD_SIGMASK)
3575#define GC_EXPLICIT_SIGNALS_UNBLOCK
3576#endif
3577#if !defined(NO_SIGNALS_UNBLOCK_IN_MAIN) && defined(GC_NO_PTHREAD_SIGMASK)
3578#define NO_SIGNALS_UNBLOCK_IN_MAIN
3579#endif
3580#if !defined(NO_MARKER_SPECIAL_SIGMASK) \
3581 && (defined(NACL) || defined(GC_WIN32_PTHREADS))
3582#define NO_MARKER_SPECIAL_SIGMASK
3583#endif
3584#ifdef GC_NETBSD_THREADS
3585#define SIGRTMIN 33
3586#define SIGRTMAX 63
3587#define GC_NETBSD_THREADS_WORKAROUND
3588#endif
3589#ifdef GC_OPENBSD_THREADS
3590 EXTERN_C_END
3591#include <sys/param.h>
3592 EXTERN_C_BEGIN
3593#if OpenBSD < 201211
3594#define GC_OPENBSD_UTHREADS 1
3595#endif
3596#endif
3597#if defined(SVR4) || defined(LINUX) || defined(IRIX5) || defined(HPUX) \
3598 || defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD) \
3599 || defined(DGUX) || defined(BSD) || defined(HAIKU) || defined(HURD) \
3600 || defined(AIX) || defined(DARWIN) || defined(OSF1)
3601#define UNIX_LIKE
3602#endif
3603#if defined(CPPCHECK)
3604#undef CPP_WORDSZ
3605#define CPP_WORDSZ (__SIZEOF_POINTER__ * 8)
3606#elif CPP_WORDSZ != 32 && CPP_WORDSZ != 64
3607#error Bad word size
3608#endif
3609#if !defined(ALIGNMENT) && !defined(CPPCHECK)
3610#error Undefined ALIGNMENT
3611#endif
3612#ifdef PCR
3613#undef DYNAMIC_LOADING
3614#undef STACKBOTTOM
3615#undef HEURISTIC1
3616#undef HEURISTIC2
3617#undef PROC_VDB
3618#undef MPROTECT_VDB
3619#define PCR_VDB
3620#endif
3621#if !defined(STACKBOTTOM) && (defined(ECOS) || defined(NOSYS)) \
3622 && !defined(CPPCHECK)
3623#error Undefined STACKBOTTOM
3624#endif
3625#ifdef IGNORE_DYNAMIC_LOADING
3626#undef DYNAMIC_LOADING
3627#endif
3628#if defined(SMALL_CONFIG) && !defined(GC_DISABLE_INCREMENTAL)
3629#define GC_DISABLE_INCREMENTAL
3630#endif
3631#if (defined(MSWIN32) || defined(MSWINCE)) && !defined(USE_WINALLOC)
3632#define USE_WINALLOC 1
3633#endif
3634#ifdef USE_WINALLOC
3635#undef USE_MMAP
3636#endif
3637#if defined(DARWIN) || defined(FREEBSD) || defined(HAIKU) \
3638 || defined(IRIX5) || defined(LINUX) || defined(NETBSD) \
3639 || defined(OPENBSD) || defined(SOLARIS) \
3640 || ((defined(CYGWIN32) || defined(USE_MMAP) || defined(USE_MUNMAP)) \
3641 && !defined(USE_WINALLOC))
3642#define MMAP_SUPPORTED
3643#endif
3644#if defined(USE_MUNMAP) && !defined(MUNMAP_THRESHOLD) \
3645 && (defined(SN_TARGET_PS3) \
3646 || defined(SN_TARGET_PSP2) || defined(MSWIN_XBOX1))
3647#define MUNMAP_THRESHOLD 2
3648#endif
3649#if defined(USE_MUNMAP) && defined(COUNT_UNMAPPED_REGIONS) \
3650 && !defined(GC_UNMAPPED_REGIONS_SOFT_LIMIT)
3651#if defined(__DragonFly__)
3652#define GC_UNMAPPED_REGIONS_SOFT_LIMIT (1000000 / 4)
3653#else
3654#define GC_UNMAPPED_REGIONS_SOFT_LIMIT 16384
3655#endif
3656#endif
3657#if defined(GC_DISABLE_INCREMENTAL) || defined(DEFAULT_VDB)
3658#undef GWW_VDB
3659#undef MPROTECT_VDB
3660#undef PCR_VDB
3661#undef PROC_VDB
3662#undef SOFT_VDB
3663#endif
3664#ifdef NO_GWW_VDB
3665#undef GWW_VDB
3666#endif
3667#ifdef NO_MPROTECT_VDB
3668#undef MPROTECT_VDB
3669#endif
3670#ifdef NO_SOFT_VDB
3671#undef SOFT_VDB
3672#endif
3673#if defined(SOFT_VDB) && defined(SOFT_VDB_LINUX_VER_STATIC_CHECK)
3674 EXTERN_C_END
3675#include <linux/version.h>
3676 EXTERN_C_BEGIN
3677#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)
3678#undef SOFT_VDB
3679#endif
3680#endif
3681#ifdef GC_DISABLE_INCREMENTAL
3682#undef CHECKSUMS
3683#endif
3684#ifdef USE_GLOBAL_ALLOC
3685#undef GWW_VDB
3686#endif
3687#if defined(BASE_ATOMIC_OPS_EMULATED)
3688#undef MPROTECT_VDB
3689#endif
3690#if defined(USE_PROC_FOR_LIBRARIES) && defined(GC_LINUX_THREADS)
3691#undef MPROTECT_VDB
3692#endif
3693#if defined(MPROTECT_VDB) && defined(GC_PREFER_MPROTECT_VDB)
3694#undef PCR_VDB
3695#undef PROC_VDB
3696#endif
3697#ifdef PROC_VDB
3698#undef MPROTECT_VDB
3699#undef SOFT_VDB
3700#endif
3701#if defined(MPROTECT_VDB) && !defined(MSWIN32) && !defined(MSWINCE)
3702#include <signal.h>
3703#endif
3704#if defined(SIGBUS) && !defined(HAVE_SIGBUS) && !defined(CPPCHECK)
3705#define HAVE_SIGBUS
3706#endif
3707#ifndef SA_SIGINFO
3708#define NO_SA_SIGACTION
3709#endif
3710#if (defined(NO_SA_SIGACTION) || defined(GC_NO_SIGSETJMP)) \
3711 && defined(MPROTECT_VDB) && !defined(DARWIN) \
3712 && !defined(MSWIN32) && !defined(MSWINCE)
3713#undef MPROTECT_VDB
3714#endif
3715#if !defined(PCR_VDB) && !defined(PROC_VDB) && !defined(MPROTECT_VDB) \
3716 && !defined(GWW_VDB) && !defined(SOFT_VDB) && !defined(DEFAULT_VDB) \
3717 && !defined(GC_DISABLE_INCREMENTAL)
3718#define DEFAULT_VDB
3719#endif
3720#if !defined(PROC_VDB) && !defined(SOFT_VDB) \
3721 && !defined(NO_VDB_FOR_STATIC_ROOTS)
3722#define NO_VDB_FOR_STATIC_ROOTS
3723#endif
3724#if ((defined(UNIX_LIKE) && (defined(DARWIN) || defined(HAIKU) \
3725 || defined(HURD) || defined(OPENBSD) \
3726 || defined(ARM32) \
3727 || defined(AVR32) || defined(MIPS) \
3728 || defined(NIOS2) || defined(OR1K))) \
3729 || (defined(LINUX) && !defined(__gnu_linux__)) \
3730 || (defined(RTEMS) && defined(I386)) || defined(HOST_ANDROID)) \
3731 && !defined(NO_GETCONTEXT)
3732#define NO_GETCONTEXT 1
3733#endif
3734#ifndef PREFETCH
3735#if GC_GNUC_PREREQ(3, 0) && !defined(NO_PREFETCH)
3736#define PREFETCH(x) __builtin_prefetch((x), 0, 0)
3737#else
3738#define PREFETCH(x) (void)0
3739#endif
3740#endif
3741#ifndef GC_PREFETCH_FOR_WRITE
3742#if GC_GNUC_PREREQ(3, 0) && !defined(GC_NO_PREFETCH_FOR_WRITE)
3743#define GC_PREFETCH_FOR_WRITE(x) __builtin_prefetch((x), 1)
3744#else
3745#define GC_PREFETCH_FOR_WRITE(x) (void)0
3746#endif
3747#endif
3748#ifndef CACHE_LINE_SIZE
3749#define CACHE_LINE_SIZE 32
3750#endif
3751#ifndef STATIC
3752#ifdef GC_ASSERTIONS
3753#define STATIC
3754#else
3755#define STATIC static
3756#endif
3757#endif
3758#if defined(LINUX) && (defined(USE_PROC_FOR_LIBRARIES) || defined(IA64) \
3759 || !defined(SMALL_CONFIG))
3760#define NEED_PROC_MAPS
3761#endif
3762#if defined(LINUX) || defined(HURD) || defined(__GLIBC__)
3763#define REGISTER_LIBRARIES_EARLY
3764#endif
3765#if defined(SEARCH_FOR_DATA_START)
3766 extern ptr_t GC_data_start;
3767#define DATASTART GC_data_start
3768#endif
3769#ifndef HEAP_START
3770#define HEAP_START ((ptr_t)0)
3771#endif
3772#ifndef CLEAR_DOUBLE
3773#define CLEAR_DOUBLE(x) (((word*)(x))[0] = 0, ((word*)(x))[1] = 0)
3774#endif
3775#if defined(GC_LINUX_THREADS) && defined(REDIRECT_MALLOC) \
3776 && !defined(INCLUDE_LINUX_THREAD_DESCR)
3777#define INCLUDE_LINUX_THREAD_DESCR
3778#endif
3779#if !defined(CPPCHECK)
3780#if defined(GC_IRIX_THREADS) && !defined(IRIX5)
3781#error Inconsistent configuration
3782#endif
3783#if defined(GC_LINUX_THREADS) && !defined(LINUX) && !defined(NACL)
3784#error Inconsistent configuration
3785#endif
3786#if defined(GC_NETBSD_THREADS) && !defined(NETBSD)
3787#error Inconsistent configuration
3788#endif
3789#if defined(GC_FREEBSD_THREADS) && !defined(FREEBSD)
3790#error Inconsistent configuration
3791#endif
3792#if defined(GC_SOLARIS_THREADS) && !defined(SOLARIS)
3793#error Inconsistent configuration
3794#endif
3795#if defined(GC_HPUX_THREADS) && !defined(HPUX)
3796#error Inconsistent configuration
3797#endif
3798#if defined(GC_AIX_THREADS) && !defined(_AIX)
3799#error Inconsistent configuration
3800#endif
3801#if defined(GC_WIN32_THREADS) && !defined(CYGWIN32) && !defined(MSWIN32) \
3802 && !defined(MSWINCE) && !defined(MSWIN_XBOX1)
3803#error Inconsistent configuration
3804#endif
3805#if defined(GC_WIN32_PTHREADS) && defined(CYGWIN32)
3806#error Inconsistent configuration
3807#endif
3808#endif
3809#if defined(PCR) || defined(GC_WIN32_THREADS) || defined(GC_PTHREADS) \
3810 || ((defined(NN_PLATFORM_CTR) || defined(NINTENDO_SWITCH) \
3811 || defined(SN_TARGET_PS3) \
3812 || defined(SN_TARGET_PSP2)) && defined(GC_THREADS))
3813#define THREADS
3814#endif
3815#if defined(PARALLEL_MARK) && !defined(THREADS) && !defined(CPPCHECK)
3816#error Invalid config: PARALLEL_MARK requires GC_THREADS
3817#endif
3818#if defined(GWW_VDB) && !defined(USE_WINALLOC) && !defined(CPPCHECK)
3819#error Invalid config: GWW_VDB requires USE_WINALLOC
3820#endif
3821#if (((defined(MSWIN32) || defined(MSWINCE)) && !defined(__GNUC__)) \
3822 || (defined(MSWIN32) && defined(I386)) \
3823 || (defined(USE_PROC_FOR_LIBRARIES) && defined(THREADS))) \
3824 && !defined(NO_CRT) && !defined(NO_WRAP_MARK_SOME)
3825#define WRAP_MARK_SOME
3826#endif
3827#if defined(PARALLEL_MARK) && !defined(DEFAULT_STACK_MAYBE_SMALL) \
3828 && (defined(HPUX) || defined(GC_DGUX386_THREADS) \
3829 || defined(NO_GETCONTEXT) )
3830#define DEFAULT_STACK_MAYBE_SMALL
3831#endif
3832#ifdef PARALLEL_MARK
3833#define MIN_STACK_SIZE (8 * HBLKSIZE * sizeof(word))
3834#endif
3835#if defined(HOST_ANDROID) && !defined(THREADS) \
3836 && !defined(USE_GET_STACKBASE_FOR_MAIN)
3837#define USE_GET_STACKBASE_FOR_MAIN
3838#endif
3839#if ((defined(FREEBSD) && defined(__GLIBC__)) \
3840 || defined(LINUX) || defined(NETBSD) || defined(HOST_ANDROID)) \
3841 && !defined(NO_PTHREAD_GETATTR_NP)
3842#define HAVE_PTHREAD_GETATTR_NP 1
3843#elif defined(FREEBSD) && !defined(__GLIBC__) \
3844 && !defined(NO_PTHREAD_ATTR_GET_NP)
3845#define HAVE_PTHREAD_NP_H 1
3846#define HAVE_PTHREAD_ATTR_GET_NP 1
3847#endif
3848#if defined(UNIX_LIKE) && defined(THREADS) && !defined(NO_CANCEL_SAFE) \
3849 && !defined(HOST_ANDROID)
3850#define CANCEL_SAFE
3851#endif
3852#ifdef CANCEL_SAFE
3853#define IF_CANCEL(x) x
3854#else
3855#define IF_CANCEL(x)
3856#endif
3857#if !defined(CAN_HANDLE_FORK) && !defined(NO_HANDLE_FORK) \
3858 && !defined(HAVE_NO_FORK) \
3859 && ((defined(GC_PTHREADS) && !defined(NACL) \
3860 && !defined(GC_WIN32_PTHREADS) && !defined(USE_WINALLOC)) \
3861 || (defined(DARWIN) && defined(MPROTECT_VDB)) || defined(HANDLE_FORK))
3862#define CAN_HANDLE_FORK
3863#endif
3864#if defined(CAN_HANDLE_FORK) && !defined(CAN_CALL_ATFORK) \
3865 && !defined(GC_NO_CAN_CALL_ATFORK) && !defined(HOST_TIZEN) \
3866 && !defined(HURD) && (!defined(HOST_ANDROID) || __ANDROID_API__ >= 21)
3867#define CAN_CALL_ATFORK
3868#endif
3869#if !defined(CAN_HANDLE_FORK) && !defined(HAVE_NO_FORK) \
3870 && !(defined(CYGWIN32) || defined(SOLARIS) || defined(UNIX_LIKE))
3871#define HAVE_NO_FORK
3872#endif
3873#if !defined(USE_MARK_BITS) && !defined(USE_MARK_BYTES) \
3874 && defined(PARALLEL_MARK)
3875#define USE_MARK_BYTES
3876#endif
3877#if (defined(MSWINCE) && !defined(__CEGCC__) || defined(MSWINRT_FLAVOR)) \
3878 && !defined(NO_GETENV)
3879#define NO_GETENV
3880#endif
3881#if (defined(NO_GETENV) || defined(MSWINCE)) && !defined(NO_GETENV_WIN32)
3882#define NO_GETENV_WIN32
3883#endif
3884#if !defined(MSGBOX_ON_ERROR) && !defined(NO_MSGBOX_ON_ERROR) \
3885 && !defined(SMALL_CONFIG) && defined(MSWIN32) \
3886 && !defined(MSWINRT_FLAVOR) && !defined(MSWIN_XBOX1)
3887#define MSGBOX_ON_ERROR
3888#endif
3889#ifndef STRTOULL
3890#if defined(_WIN64) && !defined(__GNUC__)
3891#define STRTOULL _strtoui64
3892#elif defined(_LLP64) || defined(__LLP64__) || defined(_WIN64)
3893#define STRTOULL strtoull
3894#else
3895#define STRTOULL strtoul
3896#endif
3897#endif
3898#ifndef GC_WORD_C
3899#if defined(_WIN64) && !defined(__GNUC__)
3900#define GC_WORD_C(val) val##ui64
3901#elif defined(_LLP64) || defined(__LLP64__) || defined(_WIN64)
3902#define GC_WORD_C(val) val##ULL
3903#else
3904#define GC_WORD_C(val) ((word)val##UL)
3905#endif
3906#endif
3907#if defined(__has_feature)
3908#if __has_feature(address_sanitizer) && !defined(ADDRESS_SANITIZER)
3909#define ADDRESS_SANITIZER
3910#endif
3911#if __has_feature(memory_sanitizer) && !defined(MEMORY_SANITIZER)
3912#define MEMORY_SANITIZER
3913#endif
3914#if __has_feature(thread_sanitizer) && !defined(THREAD_SANITIZER)
3915#define THREAD_SANITIZER
3916#endif
3917#else
3918#ifdef __SANITIZE_ADDRESS__
3919#define ADDRESS_SANITIZER
3920#endif
3921#endif
3922#if defined(SPARC)
3923#define ASM_CLEAR_CODE
3924#endif
3925#if defined(SPARC)
3926#define CAN_SAVE_CALL_ARGS
3927#endif
3928#if (defined(I386) || defined(X86_64)) \
3929 && (defined(LINUX) || defined(__GLIBC__))
3930#define CAN_SAVE_CALL_ARGS
3931#endif
3932#if defined(SAVE_CALL_COUNT) && !defined(GC_ADD_CALLER) \
3933 && defined(GC_CAN_SAVE_CALL_STACKS)
3934#define SAVE_CALL_CHAIN
3935#endif
3936#ifdef SAVE_CALL_CHAIN
3937#if defined(SAVE_CALL_NARGS) && defined(CAN_SAVE_CALL_ARGS)
3938#define NARGS SAVE_CALL_NARGS
3939#else
3940#define NARGS 0
3941#endif
3942#endif
3943#ifdef SAVE_CALL_CHAIN
3944#if !defined(SAVE_CALL_COUNT) || defined(CPPCHECK)
3945#define NFRAMES 6
3946#else
3947#define NFRAMES ((SAVE_CALL_COUNT + 1) & ~1)
3948#endif
3949#define NEED_CALLINFO
3950#endif
3951#ifdef GC_ADD_CALLER
3952#define NFRAMES 1
3953#define NARGS 0
3954#define NEED_CALLINFO
3955#endif
3956#if (defined(FREEBSD) || (defined(DARWIN) && !defined(_POSIX_C_SOURCE)) \
3957 || (defined(SOLARIS) && (!defined(_XOPEN_SOURCE) \
3958 || defined(__EXTENSIONS__))) \
3959 || defined(LINUX)) && !defined(HAVE_DLADDR)
3960#define HAVE_DLADDR 1
3961#endif
3962#if defined(MAKE_BACK_GRAPH) && !defined(DBG_HDRS_ALL)
3963#define DBG_HDRS_ALL 1
3964#endif
3965#if defined(POINTER_MASK) && !defined(POINTER_SHIFT)
3966#define POINTER_SHIFT 0
3967#endif
3968#if defined(POINTER_SHIFT) && !defined(POINTER_MASK)
3969#define POINTER_MASK ((word)(-1))
3970#endif
3971#if !defined(FIXUP_POINTER) && defined(POINTER_MASK)
3972#define FIXUP_POINTER(p) (p = ((p) & POINTER_MASK) << POINTER_SHIFT)
3973#endif
3974#if defined(FIXUP_POINTER)
3975#define NEED_FIXUP_POINTER
3976#else
3977#define FIXUP_POINTER(p)
3978#endif
3979#if !defined(MARK_BIT_PER_GRANULE) && !defined(MARK_BIT_PER_OBJ)
3980#define MARK_BIT_PER_GRANULE
3981#endif
3982#if !defined(CPPCHECK)
3983#if defined(MARK_BIT_PER_GRANULE) && defined(MARK_BIT_PER_OBJ)
3984#error Define only one of MARK_BIT_PER_GRANULE and MARK_BIT_PER_OBJ
3985#endif
3986#if defined(STACK_GROWS_UP) && defined(STACK_GROWS_DOWN)
3987#error Only one of STACK_GROWS_UP and STACK_GROWS_DOWN should be defined
3988#endif
3989#if !defined(STACK_GROWS_UP) && !defined(STACK_GROWS_DOWN)
3990#error One of STACK_GROWS_UP and STACK_GROWS_DOWN should be defined
3991#endif
3992#if defined(REDIRECT_MALLOC) && defined(THREADS) && !defined(LINUX) \
3993 && !defined(REDIRECT_MALLOC_IN_HEADER)
3994#error REDIRECT_MALLOC with THREADS works at most on Linux
3995#endif
3996#endif
3997#ifdef GC_PRIVATE_H
3998 struct hblk;
3999#if defined(PCR)
4000 char * real_malloc(size_t bytes);
4001#define GET_MEM(bytes) HBLKPTR(real_malloc(SIZET_SAT_ADD(bytes, \
4002 GC_page_size)) \
4003 + GC_page_size-1)
4004#elif defined(OS2)
4005 void * os2_alloc(size_t bytes);
4006#define GET_MEM(bytes) HBLKPTR((ptr_t)os2_alloc( \
4007 SIZET_SAT_ADD(bytes, \
4008 GC_page_size)) \
4009 + GC_page_size-1)
4010#elif defined(NEXT) || defined(DOS4GW) || defined(NONSTOP) \
4011 || (defined(AMIGA) && !defined(GC_AMIGA_FASTALLOC)) \
4012 || (defined(SOLARIS) && !defined(USE_MMAP)) || defined(RTEMS) \
4013 || defined(__CC_ARM)
4014#define GET_MEM(bytes) HBLKPTR((size_t)calloc(1, \
4015 SIZET_SAT_ADD(bytes, \
4016 GC_page_size)) \
4017 + GC_page_size - 1)
4018#elif defined(MSWIN_XBOX1)
4019 ptr_t GC_durango_get_mem(size_t bytes);
4020#define GET_MEM(bytes) (struct hblk *)GC_durango_get_mem(bytes)
4021#elif defined(MSWIN32) || defined(CYGWIN32)
4022 ptr_t GC_win32_get_mem(size_t bytes);
4023#define GET_MEM(bytes) (struct hblk *)GC_win32_get_mem(bytes)
4024#elif defined(MACOS)
4025#if defined(USE_TEMPORARY_MEMORY)
4026 Ptr GC_MacTemporaryNewPtr(size_t size, Boolean clearMemory);
4027#define GET_MEM(bytes) HBLKPTR(GC_MacTemporaryNewPtr( \
4028 SIZET_SAT_ADD(bytes, \
4029 GC_page_size), true) \
4030 + GC_page_size-1)
4031#else
4032#define GET_MEM(bytes) HBLKPTR(NewPtrClear(SIZET_SAT_ADD(bytes, \
4033 GC_page_size)) \
4034 + GC_page_size-1)
4035#endif
4036#elif defined(MSWINCE)
4037 ptr_t GC_wince_get_mem(size_t bytes);
4038#define GET_MEM(bytes) (struct hblk *)GC_wince_get_mem(bytes)
4039#elif defined(AMIGA) && defined(GC_AMIGA_FASTALLOC)
4040 void *GC_amiga_get_mem(size_t bytes);
4041#define GET_MEM(bytes) HBLKPTR((size_t)GC_amiga_get_mem( \
4042 SIZET_SAT_ADD(bytes, \
4043 GC_page_size)) \
4044 + GC_page_size-1)
4045#elif defined(PLATFORM_GETMEM)
4046 void *platform_get_mem(size_t bytes);
4047#define GET_MEM(bytes) (struct hblk*)platform_get_mem(bytes)
4048#elif defined(SN_TARGET_PS3)
4049 void *ps3_get_mem(size_t bytes);
4050#define GET_MEM(bytes) (struct hblk*)ps3_get_mem(bytes)
4051#elif defined(SN_TARGET_PSP2)
4052 void *psp2_get_mem(size_t bytes);
4053#define GET_MEM(bytes) (struct hblk*)psp2_get_mem(bytes)
4054#elif defined(NINTENDO_SWITCH)
4055 void *switch_get_mem(size_t bytes);
4056#define GET_MEM(bytes) (struct hblk*)switch_get_mem(bytes)
4057#elif defined(HAIKU)
4058 ptr_t GC_haiku_get_mem(size_t bytes);
4059#define GET_MEM(bytes) (struct hblk*)GC_haiku_get_mem(bytes)
4060#elif defined(EMSCRIPTEN_TINY)
4061 void *emmalloc_memalign(size_t alignment, size_t size);
4062#define GET_MEM(bytes) (struct hblk*)emmalloc_memalign(GC_page_size, bytes)
4063#else
4064 ptr_t GC_unix_get_mem(size_t bytes);
4065#define GET_MEM(bytes) (struct hblk *)GC_unix_get_mem(bytes)
4066#endif
4067#endif
4068EXTERN_C_END
4069#endif
4070#if !defined(GC_ATOMIC_UNCOLLECTABLE) && defined(ATOMIC_UNCOLLECTABLE)
4071#define GC_ATOMIC_UNCOLLECTABLE
4072#endif
4073#ifndef GC_INNER
4074#if defined(GC_DLL) && defined(__GNUC__) && !defined(MSWIN32) \
4075 && !defined(MSWINCE) && !defined(CYGWIN32)
4076#if GC_GNUC_PREREQ(4, 0) && !defined(GC_NO_VISIBILITY)
4077#define GC_INNER __attribute__((__visibility__("hidden")))
4078#else
4079#define GC_INNER
4080#endif
4081#else
4082#define GC_INNER
4083#endif
4084#define GC_EXTERN extern GC_INNER
4085#endif
4086#ifdef __cplusplus
4087#define REGISTER
4088#else
4089#define REGISTER register
4090#endif
4091#if defined(CPPCHECK)
4092#define MACRO_BLKSTMT_BEGIN {
4093#define MACRO_BLKSTMT_END }
4094#else
4095#define MACRO_BLKSTMT_BEGIN do {
4096#define MACRO_BLKSTMT_END } while (0)
4097#endif
4098#if defined(M68K) && defined(__GNUC__)
4099#define GC_ATTR_WORD_ALIGNED __attribute__((__aligned__(sizeof(word))))
4100#else
4101#define GC_ATTR_WORD_ALIGNED
4102#endif
4103#ifndef HEADERS_H
4104#ifndef GC_HEADERS_H
4105#define GC_HEADERS_H
4106#if CPP_WORDSZ != 32 && CPP_WORDSZ < 36 && !defined(CPPCHECK)
4107#error Get a real machine
4108#endif
4109EXTERN_C_BEGIN
4110typedef struct hblkhdr hdr;
4111#if CPP_WORDSZ > 32
4112#define HASH_TL
4113#endif
4114#if defined(LARGE_CONFIG) || !defined(SMALL_CONFIG)
4115#define LOG_BOTTOM_SZ 10
4116#else
4117#define LOG_BOTTOM_SZ 11
4118#endif
4119#define BOTTOM_SZ (1 << LOG_BOTTOM_SZ)
4120#ifndef HASH_TL
4121#define LOG_TOP_SZ (WORDSZ - LOG_BOTTOM_SZ - LOG_HBLKSIZE)
4122#else
4123#define LOG_TOP_SZ 11
4124#endif
4125#define TOP_SZ (1 << LOG_TOP_SZ)
4126#ifdef COUNT_HDR_CACHE_HITS
4127 extern word GC_hdr_cache_hits;
4128 extern word GC_hdr_cache_misses;
4129#define HC_HIT() (void)(++GC_hdr_cache_hits)
4130#define HC_MISS() (void)(++GC_hdr_cache_misses)
4131#else
4132#define HC_HIT()
4133#define HC_MISS()
4134#endif
4135typedef struct hce {
4136 word block_addr;
4137 hdr * hce_hdr;
4138} hdr_cache_entry;
4139#define HDR_CACHE_SIZE 8
4140#define DECLARE_HDR_CACHE \
4141 hdr_cache_entry hdr_cache[HDR_CACHE_SIZE]
4142#define INIT_HDR_CACHE BZERO(hdr_cache, sizeof(hdr_cache))
4143#define HCE(h) \
4144 (hdr_cache + (((word)(h) >> LOG_HBLKSIZE) & (HDR_CACHE_SIZE-1)))
4145#define HCE_VALID_FOR(hce, h) ((hce) -> block_addr == \
4146 ((word)(h) >> LOG_HBLKSIZE))
4147#define HCE_HDR(h) ((hce) -> hce_hdr)
4148#ifdef PRINT_BLACK_LIST
4149 GC_INNER hdr * GC_header_cache_miss(ptr_t p, hdr_cache_entry *hce,
4150 ptr_t source);
4151#define HEADER_CACHE_MISS(p, hce, source) \
4152 GC_header_cache_miss(p, hce, source)
4153#else
4154 GC_INNER hdr * GC_header_cache_miss(ptr_t p, hdr_cache_entry *hce);
4155#define HEADER_CACHE_MISS(p, hce, source) GC_header_cache_miss(p, hce)
4156#endif
4157#define HC_GET_HDR(p, hhdr, source) \
4158 { \
4159 hdr_cache_entry * hce = HCE(p); \
4160 if (EXPECT(HCE_VALID_FOR(hce, p), TRUE)) { \
4161 HC_HIT(); \
4162 hhdr = hce -> hce_hdr; \
4163 } else { \
4164 hhdr = HEADER_CACHE_MISS(p, hce, source); \
4165 if (NULL == hhdr) break; \
4166 } \
4167 }
4168typedef struct bi {
4169 hdr * index[BOTTOM_SZ];
4170 struct bi * asc_link;
4171 struct bi * desc_link;
4172 word key;
4173#ifdef HASH_TL
4174 struct bi * hash_link;
4175#endif
4176} bottom_index;
4177#define MAX_JUMP (HBLKSIZE - 1)
4178#define HDR_FROM_BI(bi, p) \
4179 ((bi)->index[((word)(p) >> LOG_HBLKSIZE) & (BOTTOM_SZ - 1)])
4180#ifndef HASH_TL
4181#define BI(p) (GC_top_index \
4182 [(word)(p) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE)])
4183#define HDR_INNER(p) HDR_FROM_BI(BI(p),p)
4184#ifdef SMALL_CONFIG
4185#define HDR(p) GC_find_header((ptr_t)(p))
4186#else
4187#define HDR(p) HDR_INNER(p)
4188#endif
4189#define GET_BI(p, bottom_indx) (void)((bottom_indx) = BI(p))
4190#define GET_HDR(p, hhdr) (void)((hhdr) = HDR(p))
4191#define SET_HDR(p, hhdr) (void)(HDR_INNER(p) = (hhdr))
4192#define GET_HDR_ADDR(p, ha) (void)((ha) = &HDR_INNER(p))
4193#else
4194#define TL_HASH(hi) ((hi) & (TOP_SZ - 1))
4195#define GET_BI(p, bottom_indx) \
4196 do { \
4197 REGISTER word hi = (word)(p) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE); \
4198 REGISTER bottom_index * _bi = GC_top_index[TL_HASH(hi)]; \
4199 while (_bi -> key != hi && _bi != GC_all_nils) \
4200 _bi = _bi -> hash_link; \
4201 (bottom_indx) = _bi; \
4202 } while (0)
4203#define GET_HDR_ADDR(p, ha) \
4204 do { \
4205 REGISTER bottom_index * bi; \
4206 GET_BI(p, bi); \
4207 (ha) = &HDR_FROM_BI(bi, p); \
4208 } while (0)
4209#define GET_HDR(p, hhdr) \
4210 do { \
4211 REGISTER hdr ** _ha; \
4212 GET_HDR_ADDR(p, _ha); \
4213 (hhdr) = *_ha; \
4214 } while (0)
4215#define SET_HDR(p, hhdr) \
4216 do { \
4217 REGISTER hdr ** _ha; \
4218 GET_HDR_ADDR(p, _ha); \
4219 *_ha = (hhdr); \
4220 } while (0)
4221#define HDR(p) GC_find_header((ptr_t)(p))
4222#endif
4223#define IS_FORWARDING_ADDR_OR_NIL(hhdr) ((size_t) (hhdr) <= MAX_JUMP)
4224#define FORWARDED_ADDR(h, hhdr) ((struct hblk *)(h) - (size_t)(hhdr))
4225EXTERN_C_END
4226#endif
4227#endif
4228#ifndef GC_ATTR_NO_SANITIZE_ADDR
4229#ifndef ADDRESS_SANITIZER
4230#define GC_ATTR_NO_SANITIZE_ADDR
4231#elif GC_CLANG_PREREQ(3, 8)
4232#define GC_ATTR_NO_SANITIZE_ADDR __attribute__((no_sanitize("address")))
4233#else
4234#define GC_ATTR_NO_SANITIZE_ADDR __attribute__((no_sanitize_address))
4235#endif
4236#endif
4237#ifndef GC_ATTR_NO_SANITIZE_MEMORY
4238#ifndef MEMORY_SANITIZER
4239#define GC_ATTR_NO_SANITIZE_MEMORY
4240#elif GC_CLANG_PREREQ(3, 8)
4241#define GC_ATTR_NO_SANITIZE_MEMORY __attribute__((no_sanitize("memory")))
4242#else
4243#define GC_ATTR_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
4244#endif
4245#endif
4246#ifndef GC_ATTR_NO_SANITIZE_THREAD
4247#ifndef THREAD_SANITIZER
4248#define GC_ATTR_NO_SANITIZE_THREAD
4249#elif GC_CLANG_PREREQ(3, 8)
4250#define GC_ATTR_NO_SANITIZE_THREAD __attribute__((no_sanitize("thread")))
4251#else
4252#define GC_ATTR_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
4253#endif
4254#endif
4255#ifndef GC_ATTR_UNUSED
4256#if GC_GNUC_PREREQ(3, 4)
4257#define GC_ATTR_UNUSED __attribute__((__unused__))
4258#else
4259#define GC_ATTR_UNUSED
4260#endif
4261#endif
4262#ifdef HAVE_CONFIG_H
4263#define GC_INLINE static inline
4264#elif defined(_MSC_VER) || defined(__INTEL_COMPILER) || defined(__DMC__) \
4265 || (GC_GNUC_PREREQ(3, 0) && defined(__STRICT_ANSI__)) \
4266 || defined(__WATCOMC__)
4267#define GC_INLINE static __inline
4268#elif GC_GNUC_PREREQ(3, 0) || defined(__sun)
4269#define GC_INLINE static inline
4270#else
4271#define GC_INLINE static
4272#endif
4273#ifndef GC_ATTR_NOINLINE
4274#if GC_GNUC_PREREQ(4, 0)
4275#define GC_ATTR_NOINLINE __attribute__((__noinline__))
4276#elif _MSC_VER >= 1400
4277#define GC_ATTR_NOINLINE __declspec(noinline)
4278#else
4279#define GC_ATTR_NOINLINE
4280#endif
4281#endif
4282#ifndef GC_API_OSCALL
4283#if defined(__GNUC__)
4284#if GC_GNUC_PREREQ(4, 0) && !defined(GC_NO_VISIBILITY)
4285#define GC_API_OSCALL extern __attribute__((__visibility__("default")))
4286#else
4287#define GC_API_OSCALL extern
4288#endif
4289#else
4290#define GC_API_OSCALL GC_API
4291#endif
4292#endif
4293#ifndef GC_API_PRIV
4294#define GC_API_PRIV GC_API
4295#endif
4296#if defined(THREADS) && !defined(NN_PLATFORM_CTR)
4297#ifndef GC_ATOMIC_OPS_H
4298#define GC_ATOMIC_OPS_H
4299#ifdef GC_BUILTIN_ATOMIC
4300#ifdef __cplusplus
4301 extern "C" {
4302#endif
4303 typedef GC_word AO_t;
4304#ifdef GC_PRIVATE_H
4305#define AO_INLINE GC_INLINE
4306#else
4307#define AO_INLINE static __inline
4308#endif
4309 typedef unsigned char AO_TS_t;
4310#define AO_TS_CLEAR 0
4311#define AO_TS_INITIALIZER (AO_TS_t)AO_TS_CLEAR
4312#if defined(__GCC_ATOMIC_TEST_AND_SET_TRUEVAL) && !defined(CPPCHECK)
4313#define AO_TS_SET __GCC_ATOMIC_TEST_AND_SET_TRUEVAL
4314#else
4315#define AO_TS_SET (AO_TS_t)1
4316#endif
4317#define AO_CLEAR(p) __atomic_clear(p, __ATOMIC_RELEASE)
4318#define AO_test_and_set_acquire(p) __atomic_test_and_set(p, __ATOMIC_ACQUIRE)
4319#define AO_HAVE_test_and_set_acquire
4320#define AO_compiler_barrier() __atomic_signal_fence(__ATOMIC_SEQ_CST)
4321#define AO_nop_full() __atomic_thread_fence(__ATOMIC_SEQ_CST)
4322#define AO_HAVE_nop_full
4323#define AO_fetch_and_add(p, v) __atomic_fetch_add(p, v, __ATOMIC_RELAXED)
4324#define AO_HAVE_fetch_and_add
4325#define AO_fetch_and_add1(p) AO_fetch_and_add(p, 1)
4326#define AO_HAVE_fetch_and_add1
4327#define AO_or(p, v) (void)__atomic_or_fetch(p, v, __ATOMIC_RELAXED)
4328#define AO_HAVE_or
4329#define AO_load(p) __atomic_load_n(p, __ATOMIC_RELAXED)
4330#define AO_HAVE_load
4331#define AO_load_acquire(p) __atomic_load_n(p, __ATOMIC_ACQUIRE)
4332#define AO_HAVE_load_acquire
4333#define AO_load_acquire_read(p) AO_load_acquire(p)
4334#define AO_HAVE_load_acquire_read
4335#define AO_store(p, v) __atomic_store_n(p, v, __ATOMIC_RELAXED)
4336#define AO_HAVE_store
4337#define AO_store_release(p, v) __atomic_store_n(p, v, __ATOMIC_RELEASE)
4338#define AO_HAVE_store_release
4339#define AO_store_release_write(p, v) AO_store_release(p, v)
4340#define AO_HAVE_store_release_write
4341#define AO_char_load(p) __atomic_load_n(p, __ATOMIC_RELAXED)
4342#define AO_HAVE_char_load
4343#define AO_char_store(p, v) __atomic_store_n(p, v, __ATOMIC_RELAXED)
4344#define AO_HAVE_char_store
4345#ifdef AO_REQUIRE_CAS
4346 AO_INLINE int
4347 AO_compare_and_swap(volatile AO_t *p, AO_t ov, AO_t nv)
4348 {
4349 return (int)__atomic_compare_exchange_n(p, &ov, nv, 0,
4350 __ATOMIC_RELAXED, __ATOMIC_RELAXED);
4351 }
4352 AO_INLINE int
4353 AO_compare_and_swap_release(volatile AO_t *p, AO_t ov, AO_t nv)
4354 {
4355 return (int)__atomic_compare_exchange_n(p, &ov, nv, 0,
4356 __ATOMIC_RELEASE, __ATOMIC_RELAXED);
4357 }
4358#define AO_HAVE_compare_and_swap_release
4359#endif
4360#ifdef __cplusplus
4361 }
4362#endif
4363#ifndef NO_LOCKFREE_AO_OR
4364#define HAVE_LOCKFREE_AO_OR 1
4365#endif
4366#else
4367#include "atomic_ops.h"
4368#if (!defined(AO_HAVE_load) || !defined(AO_HAVE_store)) && !defined(CPPCHECK)
4369#error AO_load or AO_store is missing; probably old version of atomic_ops
4370#endif
4371#endif
4372#endif
4373#ifndef AO_HAVE_compiler_barrier
4374#define AO_HAVE_compiler_barrier 1
4375#endif
4376#endif
4377#if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
4378#ifndef WIN32_LEAN_AND_MEAN
4379#define WIN32_LEAN_AND_MEAN 1
4380#endif
4381#define NOSERVICE
4382#include <windows.h>
4383#include <winbase.h>
4384#endif
4385#ifndef GC_LOCKS_H
4386#define GC_LOCKS_H
4387#ifdef THREADS
4388#ifdef PCR
4389#include <base/PCR_Base.h>
4390#include <th/PCR_Th.h>
4391#endif
4392 EXTERN_C_BEGIN
4393#ifdef PCR
4394 GC_EXTERN PCR_Th_ML GC_allocate_ml;
4395#if defined(CPPCHECK)
4396#define DCL_LOCK_STATE
4397#else
4398#define DCL_LOCK_STATE \
4399 PCR_ERes GC_fastLockRes; PCR_sigset_t GC_old_sig_mask
4400#endif
4401#define UNCOND_LOCK() PCR_Th_ML_Acquire(&GC_allocate_ml)
4402#define UNCOND_UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml)
4403#elif defined(NN_PLATFORM_CTR) || defined(NINTENDO_SWITCH)
4404 extern void GC_lock(void);
4405 extern void GC_unlock(void);
4406#define UNCOND_LOCK() GC_lock()
4407#define UNCOND_UNLOCK() GC_unlock()
4408#endif
4409#if (!defined(AO_HAVE_test_and_set_acquire) || defined(GC_RTEMS_PTHREADS) \
4410 || defined(SN_TARGET_PS3) \
4411 || defined(GC_WIN32_THREADS) || defined(BASE_ATOMIC_OPS_EMULATED) \
4412 || defined(LINT2)) && defined(GC_PTHREADS)
4413#define USE_PTHREAD_LOCKS
4414#undef USE_SPIN_LOCK
4415#if defined(LINT2) && !defined(NO_PTHREAD_TRYLOCK)
4416#define NO_PTHREAD_TRYLOCK
4417#endif
4418#endif
4419#if defined(GC_WIN32_THREADS) && !defined(USE_PTHREAD_LOCKS)
4420#define NO_THREAD (DWORD)(-1)
4421 GC_EXTERN CRITICAL_SECTION GC_allocate_ml;
4422#ifdef GC_ASSERTIONS
4423 GC_EXTERN DWORD GC_lock_holder;
4424#define SET_LOCK_HOLDER() GC_lock_holder = GetCurrentThreadId()
4425#define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD
4426#define I_HOLD_LOCK() (!GC_need_to_lock \
4427 || GC_lock_holder == GetCurrentThreadId())
4428#ifdef THREAD_SANITIZER
4429#define I_DONT_HOLD_LOCK() TRUE
4430#else
4431#define I_DONT_HOLD_LOCK() (!GC_need_to_lock \
4432 || GC_lock_holder != GetCurrentThreadId())
4433#endif
4434#define UNCOND_LOCK() \
4435 { GC_ASSERT(I_DONT_HOLD_LOCK()); \
4436 EnterCriticalSection(&GC_allocate_ml); \
4437 SET_LOCK_HOLDER(); }
4438#define UNCOND_UNLOCK() \
4439 { GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
4440 LeaveCriticalSection(&GC_allocate_ml); }
4441#else
4442#define UNCOND_LOCK() EnterCriticalSection(&GC_allocate_ml)
4443#define UNCOND_UNLOCK() LeaveCriticalSection(&GC_allocate_ml)
4444#endif
4445#elif defined(GC_PTHREADS)
4446 EXTERN_C_END
4447#include <pthread.h>
4448 EXTERN_C_BEGIN
4449#if !defined(GC_WIN32_PTHREADS)
4450#define NUMERIC_THREAD_ID(id) ((unsigned long)(id))
4451#define THREAD_EQUAL(id1, id2) ((id1) == (id2))
4452#define NUMERIC_THREAD_ID_UNIQUE
4453#elif defined(__WINPTHREADS_VERSION_MAJOR)
4454#define NUMERIC_THREAD_ID(id) ((unsigned long)(id))
4455#define THREAD_EQUAL(id1, id2) ((id1) == (id2))
4456#ifndef _WIN64
4457#define NUMERIC_THREAD_ID_UNIQUE
4458#endif
4459#else
4460#define NUMERIC_THREAD_ID(id) ((unsigned long)(word)(id.p))
4461#define THREAD_EQUAL(id1, id2) ((id1.p == id2.p) && (id1.x == id2.x))
4462#undef NUMERIC_THREAD_ID_UNIQUE
4463#endif
4464#define NO_THREAD ((unsigned long)(-1l))
4465#ifdef SN_TARGET_PSP2
4466 EXTERN_C_END
4467#include "psp2-support.h"
4468 EXTERN_C_BEGIN
4469 GC_EXTERN WapiMutex GC_allocate_ml_PSP2;
4470#define UNCOND_LOCK() { int res; GC_ASSERT(I_DONT_HOLD_LOCK()); \
4471 res = PSP2_MutexLock(&GC_allocate_ml_PSP2); \
4472 GC_ASSERT(0 == res); (void)res; \
4473 SET_LOCK_HOLDER(); }
4474#define UNCOND_UNLOCK() { int res; GC_ASSERT(I_HOLD_LOCK()); \
4475 UNSET_LOCK_HOLDER(); \
4476 res = PSP2_MutexUnlock(&GC_allocate_ml_PSP2); \
4477 GC_ASSERT(0 == res); (void)res; }
4478#elif (!defined(THREAD_LOCAL_ALLOC) || defined(USE_SPIN_LOCK)) \
4479 && !defined(USE_PTHREAD_LOCKS)
4480#undef USE_SPIN_LOCK
4481#define USE_SPIN_LOCK
4482 GC_EXTERN volatile AO_TS_t GC_allocate_lock;
4483 GC_INNER void GC_lock(void);
4484#ifdef GC_ASSERTIONS
4485#define UNCOND_LOCK() \
4486 { GC_ASSERT(I_DONT_HOLD_LOCK()); \
4487 if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_SET) \
4488 GC_lock(); \
4489 SET_LOCK_HOLDER(); }
4490#define UNCOND_UNLOCK() \
4491 { GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
4492 AO_CLEAR(&GC_allocate_lock); }
4493#else
4494#define UNCOND_LOCK() \
4495 { if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_SET) \
4496 GC_lock(); }
4497#define UNCOND_UNLOCK() AO_CLEAR(&GC_allocate_lock)
4498#endif
4499#else
4500#ifndef USE_PTHREAD_LOCKS
4501#define USE_PTHREAD_LOCKS
4502#endif
4503#endif
4504#ifdef USE_PTHREAD_LOCKS
4505 EXTERN_C_END
4506#include <pthread.h>
4507 EXTERN_C_BEGIN
4508 GC_EXTERN pthread_mutex_t GC_allocate_ml;
4509#ifdef GC_ASSERTIONS
4510 GC_INNER void GC_lock(void);
4511#define UNCOND_LOCK() { GC_ASSERT(I_DONT_HOLD_LOCK()); \
4512 GC_lock(); SET_LOCK_HOLDER(); }
4513#define UNCOND_UNLOCK() \
4514 { GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
4515 pthread_mutex_unlock(&GC_allocate_ml); }
4516#else
4517#if defined(NO_PTHREAD_TRYLOCK)
4518#define UNCOND_LOCK() pthread_mutex_lock(&GC_allocate_ml)
4519#else
4520 GC_INNER void GC_lock(void);
4521#define UNCOND_LOCK() \
4522 { if (0 != pthread_mutex_trylock(&GC_allocate_ml)) \
4523 GC_lock(); }
4524#endif
4525#define UNCOND_UNLOCK() pthread_mutex_unlock(&GC_allocate_ml)
4526#endif
4527#endif
4528#ifdef GC_ASSERTIONS
4529 GC_EXTERN unsigned long GC_lock_holder;
4530#define SET_LOCK_HOLDER() \
4531 GC_lock_holder = NUMERIC_THREAD_ID(pthread_self())
4532#define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD
4533#define I_HOLD_LOCK() \
4534 (!GC_need_to_lock \
4535 || GC_lock_holder == NUMERIC_THREAD_ID(pthread_self()))
4536#if !defined(NUMERIC_THREAD_ID_UNIQUE) || defined(THREAD_SANITIZER)
4537#define I_DONT_HOLD_LOCK() TRUE
4538#else
4539#define I_DONT_HOLD_LOCK() \
4540 (!GC_need_to_lock \
4541 || GC_lock_holder != NUMERIC_THREAD_ID(pthread_self()))
4542#endif
4543#endif
4544#ifndef GC_WIN32_THREADS
4545 GC_EXTERN volatile GC_bool GC_collecting;
4546#ifdef AO_HAVE_char_store
4547#define ENTER_GC() AO_char_store((unsigned char*)&GC_collecting, TRUE)
4548#define EXIT_GC() AO_char_store((unsigned char*)&GC_collecting, FALSE)
4549#else
4550#define ENTER_GC() (void)(GC_collecting = TRUE)
4551#define EXIT_GC() (void)(GC_collecting = FALSE)
4552#endif
4553#endif
4554#endif
4555#if defined(GC_ALWAYS_MULTITHREADED) \
4556 && (defined(USE_PTHREAD_LOCKS) || defined(USE_SPIN_LOCK))
4557#define GC_need_to_lock TRUE
4558#define set_need_to_lock() (void)0
4559#else
4560#if defined(GC_ALWAYS_MULTITHREADED) && !defined(CPPCHECK)
4561#error Runtime initialization of GC lock is needed!
4562#endif
4563#undef GC_ALWAYS_MULTITHREADED
4564 GC_EXTERN GC_bool GC_need_to_lock;
4565#ifdef THREAD_SANITIZER
4566#define set_need_to_lock() \
4567 (void)(*(GC_bool volatile *)&GC_need_to_lock \
4568 ? FALSE \
4569 : (GC_need_to_lock = TRUE))
4570#else
4571#define set_need_to_lock() (void)(GC_need_to_lock = TRUE)
4572#endif
4573#endif
4574 EXTERN_C_END
4575#else
4576#define LOCK() (void)0
4577#define UNLOCK() (void)0
4578#ifdef GC_ASSERTIONS
4579#define I_HOLD_LOCK() TRUE
4580#define I_DONT_HOLD_LOCK() TRUE
4581#endif
4582#endif
4583#if defined(UNCOND_LOCK) && !defined(LOCK)
4584#if (defined(LINT2) && defined(USE_PTHREAD_LOCKS)) \
4585 || defined(GC_ALWAYS_MULTITHREADED)
4586#define LOCK() UNCOND_LOCK()
4587#define UNLOCK() UNCOND_UNLOCK()
4588#else
4589#define LOCK() do { if (GC_need_to_lock) UNCOND_LOCK(); } while (0)
4590#define UNLOCK() do { if (GC_need_to_lock) UNCOND_UNLOCK(); } while (0)
4591#endif
4592#endif
4593#ifndef ENTER_GC
4594#define ENTER_GC()
4595#define EXIT_GC()
4596#endif
4597#ifndef DCL_LOCK_STATE
4598#define DCL_LOCK_STATE
4599#endif
4600#endif
4601#define GC_WORD_MAX (~(word)0)
4602#ifdef STACK_GROWS_DOWN
4603#define COOLER_THAN >
4604#define HOTTER_THAN <
4605#define MAKE_COOLER(x,y) if ((word)((x) + (y)) > (word)(x)) {(x) += (y);} \
4606 else (x) = (ptr_t)GC_WORD_MAX
4607#define MAKE_HOTTER(x,y) (x) -= (y)
4608#else
4609#define COOLER_THAN <
4610#define HOTTER_THAN >
4611#define MAKE_COOLER(x,y) if ((word)((x) - (y)) < (word)(x)) {(x) -= (y);} \
4612 else (x) = 0
4613#define MAKE_HOTTER(x,y) (x) += (y)
4614#endif
4615#if defined(AMIGA) && defined(__SASC)
4616#define GC_FAR __far
4617#else
4618#define GC_FAR
4619#endif
4620EXTERN_C_BEGIN
4621#ifndef GC_NO_FINALIZATION
4622#define GC_INVOKE_FINALIZERS() GC_notify_or_invoke_finalizers()
4623 GC_INNER void GC_notify_or_invoke_finalizers(void);
4624 GC_INNER void GC_finalize(void);
4625#ifndef GC_TOGGLE_REFS_NOT_NEEDED
4626 GC_INNER void GC_process_togglerefs(void);
4627#endif
4628#ifndef SMALL_CONFIG
4629 GC_INNER void GC_print_finalization_stats(void);
4630#endif
4631#else
4632#define GC_INVOKE_FINALIZERS() (void)0
4633#endif
4634#if !defined(DONT_ADD_BYTE_AT_END)
4635#ifdef LINT2
4636#define EXTRA_BYTES ((size_t)(GC_all_interior_pointers? 1 : 0))
4637#else
4638#define EXTRA_BYTES (size_t)GC_all_interior_pointers
4639#endif
4640#define MAX_EXTRA_BYTES 1
4641#else
4642#define EXTRA_BYTES 0
4643#define MAX_EXTRA_BYTES 0
4644#endif
4645#ifndef LARGE_CONFIG
4646#define MINHINCR 16
4647#define MAXHINCR 2048
4648#else
4649#define MINHINCR 64
4650#define MAXHINCR 4096
4651#endif
4652#define BL_LIMIT GC_black_list_spacing
4653#ifdef NEED_CALLINFO
4654 struct callinfo {
4655 word ci_pc;
4656#if NARGS > 0
4657 word ci_arg[NARGS];
4658#endif
4659#if (NFRAMES * (NARGS + 1)) % 2 == 1
4660 word ci_dummy;
4661#endif
4662 };
4663#endif
4664#ifdef SAVE_CALL_CHAIN
4665 GC_INNER void GC_save_callers(struct callinfo info[NFRAMES]);
4666 GC_INNER void GC_print_callers(struct callinfo info[NFRAMES]);
4667#endif
4668EXTERN_C_END
4669#ifndef NO_CLOCK
4670#ifdef BSD_TIME
4671#undef CLOCK_TYPE
4672#undef GET_TIME
4673#undef MS_TIME_DIFF
4674#define CLOCK_TYPE struct timeval
4675#define CLOCK_TYPE_INITIALIZER { 0, 0 }
4676#define GET_TIME(x) \
4677 do { \
4678 struct rusage rusage; \
4679 getrusage(RUSAGE_SELF, &rusage); \
4680 x = rusage.ru_utime; \
4681 } while (0)
4682#define MS_TIME_DIFF(a,b) ((unsigned long)((long)(a.tv_sec-b.tv_sec) * 1000 \
4683 + (long)(a.tv_usec - b.tv_usec) / 1000 \
4684 - (a.tv_usec < b.tv_usec \
4685 && (long)(a.tv_usec - b.tv_usec) % 1000 != 0 ? 1 : 0)))
4686#define NS_FRAC_TIME_DIFF(a, b) ((unsigned long) \
4687 ((a.tv_usec < b.tv_usec \
4688 && (long)(a.tv_usec - b.tv_usec) % 1000 != 0 ? 1000L : 0) \
4689 + (long)(a.tv_usec - b.tv_usec) % 1000) * 1000)
4690#elif defined(MSWIN32) || defined(MSWINCE) || defined(WINXP_USE_PERF_COUNTER)
4691#if defined(MSWINRT_FLAVOR) || defined(WINXP_USE_PERF_COUNTER)
4692#define CLOCK_TYPE ULONGLONG
4693#define GET_TIME(x) \
4694 do { \
4695 LARGE_INTEGER freq, tc; \
4696 if (!QueryPerformanceFrequency(&freq) \
4697 || !QueryPerformanceCounter(&tc)) \
4698 ABORT("QueryPerformanceCounter requires WinXP+"); \
4699 x = (CLOCK_TYPE)((double)tc.QuadPart/freq.QuadPart * 1e9); \
4700 } while (0)
4701#define MS_TIME_DIFF(a, b) ((unsigned long)(((a) - (b)) / 1000000UL))
4702#define NS_FRAC_TIME_DIFF(a, b) ((unsigned long)(((a) - (b)) % 1000000UL))
4703#else
4704#define CLOCK_TYPE DWORD
4705#define GET_TIME(x) (void)(x = GetTickCount())
4706#define MS_TIME_DIFF(a, b) ((unsigned long)((a) - (b)))
4707#define NS_FRAC_TIME_DIFF(a, b) 0UL
4708#endif
4709#elif defined(NN_PLATFORM_CTR)
4710#define CLOCK_TYPE long long
4711 EXTERN_C_BEGIN
4712 CLOCK_TYPE n3ds_get_system_tick(void);
4713 CLOCK_TYPE n3ds_convert_tick_to_ms(CLOCK_TYPE tick);
4714 EXTERN_C_END
4715#define GET_TIME(x) (void)(x = n3ds_get_system_tick())
4716#define MS_TIME_DIFF(a,b) ((unsigned long)n3ds_convert_tick_to_ms((a)-(b)))
4717#define NS_FRAC_TIME_DIFF(a, b) 0UL
4718#elif defined(NINTENDO_SWITCH) \
4719 || (((defined(LINUX) && defined(__USE_POSIX199309)) \
4720 || defined(CYGWIN32)) && defined(_POSIX_TIMERS))
4721#include <time.h>
4722#define HAVE_CLOCK_GETTIME 1
4723#define CLOCK_TYPE struct timespec
4724#define CLOCK_TYPE_INITIALIZER { 0, 0 }
4725#if defined(_POSIX_MONOTONIC_CLOCK) && !defined(NINTENDO_SWITCH)
4726#define GET_TIME(x) \
4727 do { \
4728 if (clock_gettime(CLOCK_MONOTONIC, &x) == -1) \
4729 ABORT("clock_gettime failed"); \
4730 } while (0)
4731#else
4732#define GET_TIME(x) \
4733 do { \
4734 if (clock_gettime(CLOCK_REALTIME, &x) == -1) \
4735 ABORT("clock_gettime failed"); \
4736 } while (0)
4737#endif
4738#define MS_TIME_DIFF(a, b) \
4739 \
4740 ((unsigned long)((a).tv_nsec + (1000000L*1000 - (b).tv_nsec)) / 1000000UL \
4741 + ((unsigned long)((a).tv_sec - (b).tv_sec) * 1000UL) - 1000UL)
4742#define NS_FRAC_TIME_DIFF(a, b) \
4743 ((unsigned long)((a).tv_nsec + (1000000L*1000 - (b).tv_nsec)) % 1000000UL)
4744#else
4745#include <time.h>
4746#if defined(FREEBSD) && !defined(CLOCKS_PER_SEC)
4747#include <machine/limits.h>
4748#define CLOCKS_PER_SEC CLK_TCK
4749#endif
4750#if !defined(CLOCKS_PER_SEC)
4751#define CLOCKS_PER_SEC 1000000
4752#endif
4753#define CLOCK_TYPE clock_t
4754#define GET_TIME(x) (void)(x = clock())
4755#define MS_TIME_DIFF(a,b) (CLOCKS_PER_SEC % 1000 == 0 ? \
4756 (unsigned long)((a) - (b)) / (unsigned long)(CLOCKS_PER_SEC / 1000) \
4757 : ((unsigned long)((a) - (b)) * 1000) / (unsigned long)CLOCKS_PER_SEC)
4758#define NS_FRAC_TIME_DIFF(a, b) (CLOCKS_PER_SEC <= 1000 ? 0UL \
4759 : (unsigned long)(CLOCKS_PER_SEC <= (clock_t)1000000UL \
4760 ? (((a) - (b)) * ((clock_t)1000000UL / CLOCKS_PER_SEC) % 1000) * 1000 \
4761 : (CLOCKS_PER_SEC <= (clock_t)1000000UL * 1000 \
4762 ? ((a) - (b)) * ((clock_t)1000000UL * 1000 / CLOCKS_PER_SEC) \
4763 : (((a) - (b)) * (clock_t)1000000UL * 1000) / CLOCKS_PER_SEC) \
4764 % (clock_t)1000000UL))
4765#endif
4766#ifndef CLOCK_TYPE_INITIALIZER
4767#define CLOCK_TYPE_INITIALIZER 0
4768#endif
4769#endif
4770#if defined(SPARC) && defined(SUNOS4) \
4771 || (defined(M68K) && defined(NEXT)) || defined(VAX)
4772#define BCOPY_EXISTS
4773#elif defined(AMIGA) || defined(DARWIN)
4774#include <string.h>
4775#define BCOPY_EXISTS
4776#elif defined(MACOS) && defined(POWERPC)
4777#include <MacMemory.h>
4778#define bcopy(x,y,n) BlockMoveData(x, y, n)
4779#define bzero(x,n) BlockZero(x, n)
4780#define BCOPY_EXISTS
4781#endif
4782#if !defined(BCOPY_EXISTS) || defined(CPPCHECK)
4783#include <string.h>
4784#define BCOPY(x,y,n) memcpy(y, x, (size_t)(n))
4785#define BZERO(x,n) memset(x, 0, (size_t)(n))
4786#else
4787#define BCOPY(x,y,n) bcopy((void *)(x),(void *)(y),(size_t)(n))
4788#define BZERO(x,n) bzero((void *)(x),(size_t)(n))
4789#endif
4790#ifdef PCR
4791#include "th/PCR_ThCtl.h"
4792#endif
4793EXTERN_C_BEGIN
4794#ifdef PCR
4795#define STOP_WORLD() \
4796 PCR_ThCtl_SetExclusiveMode(PCR_ThCtl_ExclusiveMode_stopNormal, \
4797 PCR_allSigsBlocked, \
4798 PCR_waitForever)
4799#define START_WORLD() \
4800 PCR_ThCtl_SetExclusiveMode(PCR_ThCtl_ExclusiveMode_null, \
4801 PCR_allSigsBlocked, \
4802 PCR_waitForever)
4803#else
4804#if defined(NN_PLATFORM_CTR) || defined(NINTENDO_SWITCH) \
4805 || defined(GC_WIN32_THREADS) || defined(GC_PTHREADS)
4806 GC_INNER void GC_stop_world(void);
4807 GC_INNER void GC_start_world(void);
4808#define STOP_WORLD() GC_stop_world()
4809#define START_WORLD() GC_start_world()
4810#else
4811#define STOP_WORLD() GC_ASSERT(GC_blocked_sp == NULL)
4812#define START_WORLD()
4813#endif
4814#endif
4815#ifdef THREADS
4816 GC_EXTERN GC_on_thread_event_proc GC_on_thread_event;
4817#endif
4818#if defined(SMALL_CONFIG) || defined(PCR)
4819#define GC_on_abort(msg) (void)0
4820#else
4821 GC_API_PRIV GC_abort_func GC_on_abort;
4822#endif
4823#if defined(CPPCHECK)
4824#define ABORT(msg) { GC_on_abort(msg); abort(); }
4825#elif defined(PCR)
4826#define ABORT(s) PCR_Base_Panic(s)
4827#else
4828#if defined(MSWIN_XBOX1) && !defined(DebugBreak)
4829#define DebugBreak() __debugbreak()
4830#elif defined(MSWINCE) && !defined(DebugBreak) \
4831 && (!defined(UNDER_CE) || (defined(__MINGW32CE__) && !defined(ARM32)))
4832#define DebugBreak() _exit(-1)
4833#endif
4834#if defined(MSWIN32) && (defined(NO_DEBUGGING) || defined(LINT2))
4835#define ABORT(msg) (GC_on_abort(msg), _exit(-1))
4836#elif defined(MSWINCE) && defined(NO_DEBUGGING)
4837#define ABORT(msg) (GC_on_abort(msg), ExitProcess(-1))
4838#elif defined(MSWIN32) || defined(MSWINCE)
4839#if defined(_CrtDbgBreak) && defined(_DEBUG) && defined(_MSC_VER)
4840#define ABORT(msg) { GC_on_abort(msg); \
4841 _CrtDbgBreak() ; }
4842#else
4843#define ABORT(msg) { GC_on_abort(msg); DebugBreak(); }
4844#endif
4845#else
4846#define ABORT(msg) (GC_on_abort(msg), abort())
4847#endif
4848#endif
4849#define ABORT_ARG1(C_msg, C_fmt, arg1) \
4850 MACRO_BLKSTMT_BEGIN \
4851 GC_ERRINFO_PRINTF(C_msg C_fmt "\n", arg1); \
4852 ABORT(C_msg); \
4853 MACRO_BLKSTMT_END
4854#define ABORT_ARG2(C_msg, C_fmt, arg1, arg2) \
4855 MACRO_BLKSTMT_BEGIN \
4856 GC_ERRINFO_PRINTF(C_msg C_fmt "\n", arg1, arg2); \
4857 ABORT(C_msg); \
4858 MACRO_BLKSTMT_END
4859#define ABORT_ARG3(C_msg, C_fmt, arg1, arg2, arg3) \
4860 MACRO_BLKSTMT_BEGIN \
4861 GC_ERRINFO_PRINTF(C_msg C_fmt "\n", \
4862 arg1, arg2, arg3); \
4863 ABORT(C_msg); \
4864 MACRO_BLKSTMT_END
4865#define ABORT_RET(msg) \
4866 if ((signed_word)GC_current_warn_proc == -1) {} else ABORT(msg)
4867#ifdef PCR
4868#define EXIT() PCR_Base_Exit(1,PCR_waitForever)
4869#else
4870#define EXIT() (GC_on_abort(NULL), exit(1 ))
4871#endif
4872#define WARN(msg, arg) \
4873 (*GC_current_warn_proc)(( char *)("GC Warning: " msg), \
4874 (word)(arg))
4875GC_EXTERN GC_warn_proc GC_current_warn_proc;
4876#ifndef WARN_PRIdPTR
4877#define WARN_PRIdPTR "ld"
4878#endif
4879#define TRUSTED_STRING(s) (char*)COVERT_DATAFLOW(s)
4880#ifdef GC_READ_ENV_FILE
4881 GC_INNER char * GC_envfile_getenv(const char *name);
4882#define GETENV(name) GC_envfile_getenv(name)
4883#elif defined(NO_GETENV) && !defined(CPPCHECK)
4884#define GETENV(name) NULL
4885#elif defined(EMPTY_GETENV_RESULTS)
4886 GC_INLINE char * fixed_getenv(const char *name)
4887 {
4888 char *value = getenv(name);
4889 return value != NULL && *value != '\0' ? value : NULL;
4890 }
4891#define GETENV(name) fixed_getenv(name)
4892#else
4893#define GETENV(name) getenv(name)
4894#endif
4895EXTERN_C_END
4896#if defined(DARWIN)
4897#include <mach/thread_status.h>
4898#ifndef MAC_OS_X_VERSION_MAX_ALLOWED
4899#include <AvailabilityMacros.h>
4900#endif
4901#if defined(POWERPC)
4902#if CPP_WORDSZ == 32
4903#define GC_THREAD_STATE_T ppc_thread_state_t
4904#else
4905#define GC_THREAD_STATE_T ppc_thread_state64_t
4906#define GC_MACH_THREAD_STATE PPC_THREAD_STATE64
4907#define GC_MACH_THREAD_STATE_COUNT PPC_THREAD_STATE64_COUNT
4908#endif
4909#elif defined(I386) || defined(X86_64)
4910#if CPP_WORDSZ == 32
4911#if defined(i386_THREAD_STATE_COUNT) && !defined(x86_THREAD_STATE32_COUNT)
4912#define GC_THREAD_STATE_T i386_thread_state_t
4913#define GC_MACH_THREAD_STATE i386_THREAD_STATE
4914#define GC_MACH_THREAD_STATE_COUNT i386_THREAD_STATE_COUNT
4915#else
4916#define GC_THREAD_STATE_T x86_thread_state32_t
4917#define GC_MACH_THREAD_STATE x86_THREAD_STATE32
4918#define GC_MACH_THREAD_STATE_COUNT x86_THREAD_STATE32_COUNT
4919#endif
4920#else
4921#define GC_THREAD_STATE_T x86_thread_state64_t
4922#define GC_MACH_THREAD_STATE x86_THREAD_STATE64
4923#define GC_MACH_THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT
4924#endif
4925#elif defined(ARM32) && defined(ARM_UNIFIED_THREAD_STATE) \
4926 && !defined(CPPCHECK)
4927#define GC_THREAD_STATE_T arm_unified_thread_state_t
4928#define GC_MACH_THREAD_STATE ARM_UNIFIED_THREAD_STATE
4929#define GC_MACH_THREAD_STATE_COUNT ARM_UNIFIED_THREAD_STATE_COUNT
4930#elif defined(ARM32)
4931#define GC_THREAD_STATE_T arm_thread_state_t
4932#ifdef ARM_MACHINE_THREAD_STATE_COUNT
4933#define GC_MACH_THREAD_STATE ARM_MACHINE_THREAD_STATE
4934#define GC_MACH_THREAD_STATE_COUNT ARM_MACHINE_THREAD_STATE_COUNT
4935#endif
4936#elif defined(AARCH64)
4937#define GC_THREAD_STATE_T arm_thread_state64_t
4938#define GC_MACH_THREAD_STATE ARM_THREAD_STATE64
4939#define GC_MACH_THREAD_STATE_COUNT ARM_THREAD_STATE64_COUNT
4940#elif !defined(CPPCHECK)
4941#error define GC_THREAD_STATE_T
4942#endif
4943#ifndef GC_MACH_THREAD_STATE
4944#define GC_MACH_THREAD_STATE MACHINE_THREAD_STATE
4945#define GC_MACH_THREAD_STATE_COUNT MACHINE_THREAD_STATE_COUNT
4946#endif
4947#if CPP_WORDSZ == 32
4948#define GC_MACH_HEADER mach_header
4949#define GC_MACH_SECTION section
4950#define GC_GETSECTBYNAME getsectbynamefromheader
4951#else
4952#define GC_MACH_HEADER mach_header_64
4953#define GC_MACH_SECTION section_64
4954#define GC_GETSECTBYNAME getsectbynamefromheader_64
4955#endif
4956#if __DARWIN_UNIX03
4957#define THREAD_FLD_NAME(x) __ ## x
4958#else
4959#define THREAD_FLD_NAME(x) x
4960#endif
4961#if defined(ARM32) && defined(ARM_UNIFIED_THREAD_STATE)
4962#define THREAD_FLD(x) ts_32.THREAD_FLD_NAME(x)
4963#else
4964#define THREAD_FLD(x) THREAD_FLD_NAME(x)
4965#endif
4966#endif
4967#include <setjmp.h>
4968#if __STDC_VERSION__ >= 201112L
4969#include <assert.h>
4970#endif
4971EXTERN_C_BEGIN
4972#if CPP_WORDSZ == 32
4973#define WORDS_TO_BYTES(x) ((x)<<2)
4974#define BYTES_TO_WORDS(x) ((x)>>2)
4975#define LOGWL ((word)5)
4976#define modWORDSZ(n) ((n) & 0x1f)
4977#if ALIGNMENT != 4
4978#define UNALIGNED_PTRS
4979#endif
4980#endif
4981#if CPP_WORDSZ == 64
4982#define WORDS_TO_BYTES(x) ((x)<<3)
4983#define BYTES_TO_WORDS(x) ((x)>>3)
4984#define LOGWL ((word)6)
4985#define modWORDSZ(n) ((n) & 0x3f)
4986#if ALIGNMENT != 8
4987#define UNALIGNED_PTRS
4988#endif
4989#endif
4990#define GRANULE_BYTES GC_GRANULE_BYTES
4991#define TINY_FREELISTS GC_TINY_FREELISTS
4992#define WORDSZ ((word)CPP_WORDSZ)
4993#define SIGNB ((word)1 << (WORDSZ-1))
4994#define BYTES_PER_WORD ((word)(sizeof (word)))
4995#define divWORDSZ(n) ((n) >> LOGWL)
4996#if GRANULE_BYTES == 8
4997#define BYTES_TO_GRANULES(n) ((n)>>3)
4998#define GRANULES_TO_BYTES(n) ((n)<<3)
4999#if CPP_WORDSZ == 64
5000#define GRANULES_TO_WORDS(n) (n)
5001#elif CPP_WORDSZ == 32
5002#define GRANULES_TO_WORDS(n) ((n)<<1)
5003#else
5004#define GRANULES_TO_WORDS(n) BYTES_TO_WORDS(GRANULES_TO_BYTES(n))
5005#endif
5006#elif GRANULE_BYTES == 16
5007#define BYTES_TO_GRANULES(n) ((n)>>4)
5008#define GRANULES_TO_BYTES(n) ((n)<<4)
5009#if CPP_WORDSZ == 64
5010#define GRANULES_TO_WORDS(n) ((n)<<1)
5011#elif CPP_WORDSZ == 32
5012#define GRANULES_TO_WORDS(n) ((n)<<2)
5013#else
5014#define GRANULES_TO_WORDS(n) BYTES_TO_WORDS(GRANULES_TO_BYTES(n))
5015#endif
5016#else
5017#error Bad GRANULE_BYTES value
5018#endif
5019#ifndef HBLKSIZE
5020#if defined(LARGE_CONFIG) || !defined(SMALL_CONFIG)
5021#ifdef ALPHA
5022#define CPP_LOG_HBLKSIZE 13
5023#elif defined(SN_TARGET_PSP2)
5024#define CPP_LOG_HBLKSIZE 16
5025#else
5026#define CPP_LOG_HBLKSIZE 12
5027#endif
5028#else
5029#define CPP_LOG_HBLKSIZE 10
5030#endif
5031#else
5032#if HBLKSIZE == 512
5033#define CPP_LOG_HBLKSIZE 9
5034#elif HBLKSIZE == 1024
5035#define CPP_LOG_HBLKSIZE 10
5036#elif HBLKSIZE == 2048
5037#define CPP_LOG_HBLKSIZE 11
5038#elif HBLKSIZE == 4096
5039#define CPP_LOG_HBLKSIZE 12
5040#elif HBLKSIZE == 8192
5041#define CPP_LOG_HBLKSIZE 13
5042#elif HBLKSIZE == 16384
5043#define CPP_LOG_HBLKSIZE 14
5044#elif !defined(CPPCHECK)
5045#error Bad HBLKSIZE value
5046#endif
5047#undef HBLKSIZE
5048#endif
5049#define CPP_HBLKSIZE (1 << CPP_LOG_HBLKSIZE)
5050#define LOG_HBLKSIZE ((size_t)CPP_LOG_HBLKSIZE)
5051#define HBLKSIZE ((size_t)CPP_HBLKSIZE)
5052#define GC_SQRT_SIZE_MAX ((((size_t)1) << (WORDSZ / 2)) - 1)
5053#define CPP_MAXOBJBYTES (CPP_HBLKSIZE/2)
5054#define MAXOBJBYTES ((size_t)CPP_MAXOBJBYTES)
5055#define CPP_MAXOBJWORDS BYTES_TO_WORDS(CPP_MAXOBJBYTES)
5056#define MAXOBJWORDS ((size_t)CPP_MAXOBJWORDS)
5057#define CPP_MAXOBJGRANULES BYTES_TO_GRANULES(CPP_MAXOBJBYTES)
5058#define MAXOBJGRANULES ((size_t)CPP_MAXOBJGRANULES)
5059#define divHBLKSZ(n) ((n) >> LOG_HBLKSIZE)
5060#define HBLK_PTR_DIFF(p,q) divHBLKSZ((ptr_t)p - (ptr_t)q)
5061#define modHBLKSZ(n) ((n) & (HBLKSIZE-1))
5062#define HBLKPTR(objptr) ((struct hblk *)(((word)(objptr)) \
5063 & ~(word)(HBLKSIZE-1)))
5064#define HBLKDISPL(objptr) (((size_t) (objptr)) & (HBLKSIZE-1))
5065#define ROUNDUP_GRANULE_SIZE(lb) \
5066 (SIZET_SAT_ADD(lb, GRANULE_BYTES - 1) & ~(GRANULE_BYTES - 1))
5067#define ROUNDED_UP_GRANULES(lb) \
5068 BYTES_TO_GRANULES(SIZET_SAT_ADD(lb, GRANULE_BYTES - 1 + EXTRA_BYTES))
5069#if MAX_EXTRA_BYTES == 0
5070#define SMALL_OBJ(bytes) EXPECT((bytes) <= (MAXOBJBYTES), TRUE)
5071#else
5072#define SMALL_OBJ(bytes) \
5073 (EXPECT((bytes) <= (MAXOBJBYTES - MAX_EXTRA_BYTES), TRUE) \
5074 || (bytes) <= MAXOBJBYTES - EXTRA_BYTES)
5075#endif
5076#define ADD_SLOP(lb) \
5077 SIZET_SAT_ADD(lb, EXTRA_BYTES)
5078#ifndef LOG_PHT_ENTRIES
5079#ifdef LARGE_CONFIG
5080#if CPP_WORDSZ == 32
5081#define LOG_PHT_ENTRIES 20
5082#else
5083#define LOG_PHT_ENTRIES 21
5084#endif
5085#elif !defined(SMALL_CONFIG)
5086#define LOG_PHT_ENTRIES 18
5087#else
5088#define LOG_PHT_ENTRIES 15
5089#endif
5090#endif
5091#define PHT_ENTRIES ((word)1 << LOG_PHT_ENTRIES)
5092#define PHT_SIZE (PHT_ENTRIES >> LOGWL)
5093typedef word page_hash_table[PHT_SIZE];
5094#define PHT_HASH(addr) ((((word)(addr)) >> LOG_HBLKSIZE) & (PHT_ENTRIES - 1))
5095#define get_pht_entry_from_index(bl, index) \
5096 (((bl)[divWORDSZ(index)] >> modWORDSZ(index)) & 1)
5097#define set_pht_entry_from_index(bl, index) \
5098 (void)((bl)[divWORDSZ(index)] |= (word)1 << modWORDSZ(index))
5099#if defined(THREADS) && defined(AO_HAVE_or)
5100#define set_pht_entry_from_index_concurrent(bl, index) \
5101 AO_or((volatile AO_t *)&(bl)[divWORDSZ(index)], \
5102 (AO_t)((word)1 << modWORDSZ(index)))
5103#else
5104#define set_pht_entry_from_index_concurrent(bl, index) \
5105 set_pht_entry_from_index(bl, index)
5106#endif
5107#define HBLKMASK (HBLKSIZE-1)
5108#define MARK_BITS_PER_HBLK (HBLKSIZE/GRANULE_BYTES)
5109union word_ptr_ao_u {
5110 word w;
5111 signed_word sw;
5112 void *vp;
5113#ifdef PARALLEL_MARK
5114 volatile AO_t ao;
5115#endif
5116};
5117struct hblkhdr {
5118 struct hblk * hb_next;
5119 struct hblk * hb_prev;
5120 struct hblk * hb_block;
5121 unsigned char hb_obj_kind;
5122 unsigned char hb_flags;
5123#define IGNORE_OFF_PAGE 1
5124#define WAS_UNMAPPED 2
5125#define FREE_BLK 4
5126#ifdef ENABLE_DISCLAIM
5127#define HAS_DISCLAIM 8
5128#define MARK_UNCONDITIONALLY 0x10
5129#endif
5130#ifdef MARK_BIT_PER_GRANULE
5131#define LARGE_BLOCK 0x20
5132#endif
5133 unsigned short hb_last_reclaimed;
5134#ifdef MARK_BIT_PER_OBJ
5135 unsigned32 hb_inv_sz;
5136#define LARGE_INV_SZ (1 << 16)
5137#endif
5138 word hb_sz;
5139 word hb_descr;
5140#ifdef MARK_BIT_PER_GRANULE
5141 unsigned short * hb_map;
5142#endif
5143#ifdef PARALLEL_MARK
5144 volatile AO_t hb_n_marks;
5145#else
5146 size_t hb_n_marks;
5147#endif
5148#ifdef USE_MARK_BYTES
5149#define MARK_BITS_SZ (MARK_BITS_PER_HBLK + 1)
5150 union {
5151 char _hb_marks[MARK_BITS_SZ];
5152 word dummy;
5153 } _mark_byte_union;
5154#define hb_marks _mark_byte_union._hb_marks
5155#else
5156#define MARK_BITS_SZ (MARK_BITS_PER_HBLK/CPP_WORDSZ + 1)
5157 word hb_marks[MARK_BITS_SZ];
5158#endif
5159};
5160#define ANY_INDEX 23
5161#define HBLK_WORDS (HBLKSIZE/sizeof(word))
5162#define HBLK_GRANULES (HBLKSIZE/GRANULE_BYTES)
5163#define HBLK_OBJS(sz_in_bytes) (HBLKSIZE/(sz_in_bytes))
5164struct hblk {
5165 char hb_body[HBLKSIZE];
5166};
5167#define HBLK_IS_FREE(hdr) (((hdr) -> hb_flags & FREE_BLK) != 0)
5168#define OBJ_SZ_TO_BLOCKS(lb) divHBLKSZ((lb) + HBLKSIZE-1)
5169#define OBJ_SZ_TO_BLOCKS_CHECKED(lb) \
5170 divHBLKSZ(SIZET_SAT_ADD(lb, HBLKSIZE - 1))
5171#define obj_link(p) (*(void **)(p))
5172#define LOG_MAX_MARK_PROCS 6
5173#define MAX_MARK_PROCS (1 << LOG_MAX_MARK_PROCS)
5174#ifdef LARGE_CONFIG
5175#define MAX_ROOT_SETS 8192
5176#elif !defined(SMALL_CONFIG)
5177#define MAX_ROOT_SETS 2048
5178#else
5179#define MAX_ROOT_SETS 512
5180#endif
5181#define MAX_EXCLUSIONS (MAX_ROOT_SETS/4)
5182struct exclusion {
5183 ptr_t e_start;
5184 ptr_t e_end;
5185};
5186struct roots {
5187 ptr_t r_start;
5188 ptr_t r_end;
5189#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
5190 struct roots * r_next;
5191#endif
5192 GC_bool r_tmp;
5193};
5194#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
5195#define LOG_RT_SIZE 6
5196#define RT_SIZE (1 << LOG_RT_SIZE)
5197#endif
5198#if !defined(MAX_HEAP_SECTS) && (defined(CYGWIN32) || defined(MSWIN32) \
5199 || defined(MSWINCE) || defined(USE_PROC_FOR_LIBRARIES))
5200#ifdef LARGE_CONFIG
5201#if CPP_WORDSZ > 32
5202#define MAX_HEAP_SECTS 81920
5203#else
5204#define MAX_HEAP_SECTS 7680
5205#endif
5206#elif defined(SMALL_CONFIG) && !defined(USE_PROC_FOR_LIBRARIES)
5207#if defined(PARALLEL_MARK) && (defined(MSWIN32) || defined(CYGWIN32))
5208#define MAX_HEAP_SECTS 384
5209#else
5210#define MAX_HEAP_SECTS 128
5211#endif
5212#elif CPP_WORDSZ > 32
5213#define MAX_HEAP_SECTS 1024
5214#else
5215#define MAX_HEAP_SECTS 512
5216#endif
5217#endif
5218typedef struct GC_ms_entry {
5219 ptr_t mse_start;
5220 union word_ptr_ao_u mse_descr;
5221} mse;
5222typedef int mark_state_t;
5223struct disappearing_link;
5224struct finalizable_object;
5225struct dl_hashtbl_s {
5226 struct disappearing_link **head;
5227 word entries;
5228 unsigned log_size;
5229};
5230struct fnlz_roots_s {
5231 struct finalizable_object **fo_head;
5232 struct finalizable_object *finalize_now;
5233};
5234union toggle_ref_u {
5235 void *strong_ref;
5236 GC_hidden_pointer weak_ref;
5237};
5238typedef struct {
5239 word ed_bitmap;
5240 GC_bool ed_continued;
5241} typed_ext_descr_t;
5242struct HeapSect {
5243 ptr_t hs_start;
5244 size_t hs_bytes;
5245};
5246struct _GC_arrays {
5247 word _heapsize;
5248 word _requested_heapsize;
5249 ptr_t _last_heap_addr;
5250 word _large_free_bytes;
5251 word _large_allocd_bytes;
5252 word _max_large_allocd_bytes;
5253 word _bytes_allocd_before_gc;
5254#define GC_our_mem_bytes GC_arrays._our_mem_bytes
5255 word _our_mem_bytes;
5256#ifndef SEPARATE_GLOBALS
5257#define GC_bytes_allocd GC_arrays._bytes_allocd
5258 word _bytes_allocd;
5259#endif
5260 word _bytes_dropped;
5261 word _bytes_finalized;
5262 word _bytes_freed;
5263 word _finalizer_bytes_freed;
5264 bottom_index *_all_bottom_indices;
5265 bottom_index *_all_bottom_indices_end;
5266 ptr_t _scratch_free_ptr;
5267 hdr *_hdr_free_list;
5268 ptr_t _scratch_end_ptr;
5269#if defined(IRIX5) || (defined(USE_PROC_FOR_LIBRARIES) && !defined(LINUX))
5270#define USE_SCRATCH_LAST_END_PTR
5271#define GC_scratch_last_end_ptr GC_arrays._scratch_last_end_ptr
5272 ptr_t _scratch_last_end_ptr;
5273#endif
5274 mse *_mark_stack;
5275 mse *_mark_stack_limit;
5276#ifdef PARALLEL_MARK
5277 mse *volatile _mark_stack_top;
5278#else
5279 mse *_mark_stack_top;
5280#endif
5281 word _composite_in_use;
5282 word _atomic_in_use;
5283#ifdef USE_MUNMAP
5284#define GC_unmapped_bytes GC_arrays._unmapped_bytes
5285 word _unmapped_bytes;
5286#ifdef COUNT_UNMAPPED_REGIONS
5287#define GC_num_unmapped_regions GC_arrays._num_unmapped_regions
5288 signed_word _num_unmapped_regions;
5289#endif
5290#else
5291#define GC_unmapped_bytes 0
5292#endif
5293 bottom_index * _all_nils;
5294#define GC_scan_ptr GC_arrays._scan_ptr
5295 struct hblk * _scan_ptr;
5296#ifdef PARALLEL_MARK
5297#define GC_main_local_mark_stack GC_arrays._main_local_mark_stack
5298 mse *_main_local_mark_stack;
5299#define GC_first_nonempty GC_arrays._first_nonempty
5300 volatile AO_t _first_nonempty;
5301#endif
5302#define GC_mark_stack_size GC_arrays._mark_stack_size
5303 size_t _mark_stack_size;
5304#define GC_mark_state GC_arrays._mark_state
5305 mark_state_t _mark_state;
5306#define GC_mark_stack_too_small GC_arrays._mark_stack_too_small
5307 GC_bool _mark_stack_too_small;
5308#define GC_objects_are_marked GC_arrays._objects_are_marked
5309 GC_bool _objects_are_marked;
5310#ifdef ENABLE_TRACE
5311#define GC_trace_addr GC_arrays._trace_addr
5312 ptr_t _trace_addr;
5313#endif
5314#define GC_capacity_heap_sects GC_arrays._capacity_heap_sects
5315 size_t _capacity_heap_sects;
5316#define GC_n_heap_sects GC_arrays._n_heap_sects
5317 word _n_heap_sects;
5318#if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
5319#define GC_n_heap_bases GC_arrays._n_heap_bases
5320 word _n_heap_bases;
5321#endif
5322#ifdef USE_PROC_FOR_LIBRARIES
5323#define GC_n_memory GC_arrays._n_memory
5324 word _n_memory;
5325#endif
5326#ifdef GC_GCJ_SUPPORT
5327#define GC_gcjobjfreelist GC_arrays._gcjobjfreelist
5328 ptr_t *_gcjobjfreelist;
5329#endif
5330#define GC_fo_entries GC_arrays._fo_entries
5331 word _fo_entries;
5332#ifndef GC_NO_FINALIZATION
5333#define GC_dl_hashtbl GC_arrays._dl_hashtbl
5334#define GC_fnlz_roots GC_arrays._fnlz_roots
5335#define GC_log_fo_table_size GC_arrays._log_fo_table_size
5336#ifndef GC_LONG_REFS_NOT_NEEDED
5337#define GC_ll_hashtbl GC_arrays._ll_hashtbl
5338 struct dl_hashtbl_s _ll_hashtbl;
5339#endif
5340 struct dl_hashtbl_s _dl_hashtbl;
5341 struct fnlz_roots_s _fnlz_roots;
5342 unsigned _log_fo_table_size;
5343#ifndef GC_TOGGLE_REFS_NOT_NEEDED
5344#define GC_toggleref_arr GC_arrays._toggleref_arr
5345#define GC_toggleref_array_size GC_arrays._toggleref_array_size
5346#define GC_toggleref_array_capacity GC_arrays._toggleref_array_capacity
5347 union toggle_ref_u *_toggleref_arr;
5348 size_t _toggleref_array_size;
5349 size_t _toggleref_array_capacity;
5350#endif
5351#endif
5352#ifdef TRACE_BUF
5353#define GC_trace_buf_ptr GC_arrays._trace_buf_ptr
5354 int _trace_buf_ptr;
5355#endif
5356#ifdef ENABLE_DISCLAIM
5357#define GC_finalized_kind GC_arrays._finalized_kind
5358 int _finalized_kind;
5359#endif
5360#define n_root_sets GC_arrays._n_root_sets
5361#define GC_excl_table_entries GC_arrays._excl_table_entries
5362 int _n_root_sets;
5363 size_t _excl_table_entries;
5364#ifdef THREADS
5365#define GC_roots_were_cleared GC_arrays._roots_were_cleared
5366 GC_bool _roots_were_cleared;
5367#endif
5368#define GC_explicit_typing_initialized GC_arrays._explicit_typing_initialized
5369#define GC_ed_size GC_arrays._ed_size
5370#define GC_avail_descr GC_arrays._avail_descr
5371#define GC_ext_descriptors GC_arrays._ext_descriptors
5372#ifdef AO_HAVE_load_acquire
5373 volatile AO_t _explicit_typing_initialized;
5374#else
5375 GC_bool _explicit_typing_initialized;
5376#endif
5377 size_t _ed_size;
5378 size_t _avail_descr;
5379 typed_ext_descr_t *_ext_descriptors;
5380 GC_mark_proc _mark_procs[MAX_MARK_PROCS];
5381 char _modws_valid_offsets[sizeof(word)];
5382#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
5383#define GC_root_index GC_arrays._root_index
5384 struct roots * _root_index[RT_SIZE];
5385#endif
5386#ifdef SAVE_CALL_CHAIN
5387#define GC_last_stack GC_arrays._last_stack
5388 struct callinfo _last_stack[NFRAMES];
5389#endif
5390#ifndef SEPARATE_GLOBALS
5391#define GC_objfreelist GC_arrays._objfreelist
5392 void *_objfreelist[MAXOBJGRANULES+1];
5393#define GC_aobjfreelist GC_arrays._aobjfreelist
5394 void *_aobjfreelist[MAXOBJGRANULES+1];
5395#endif
5396 void *_uobjfreelist[MAXOBJGRANULES+1];
5397#ifdef GC_ATOMIC_UNCOLLECTABLE
5398#define GC_auobjfreelist GC_arrays._auobjfreelist
5399 void *_auobjfreelist[MAXOBJGRANULES+1];
5400#endif
5401 size_t _size_map[MAXOBJBYTES+1];
5402#ifdef MARK_BIT_PER_GRANULE
5403#define GC_obj_map GC_arrays._obj_map
5404 unsigned short * _obj_map[MAXOBJGRANULES + 1];
5405#define MAP_LEN BYTES_TO_GRANULES(HBLKSIZE)
5406#endif
5407#define VALID_OFFSET_SZ HBLKSIZE
5408 char _valid_offsets[VALID_OFFSET_SZ];
5409#ifndef GC_DISABLE_INCREMENTAL
5410#define GC_grungy_pages GC_arrays._grungy_pages
5411 page_hash_table _grungy_pages;
5412#define GC_dirty_pages GC_arrays._dirty_pages
5413 volatile page_hash_table _dirty_pages;
5414#endif
5415#if (defined(CHECKSUMS) && (defined(GWW_VDB) || defined(SOFT_VDB))) \
5416 || defined(PROC_VDB)
5417#define GC_written_pages GC_arrays._written_pages
5418 page_hash_table _written_pages;
5419#endif
5420#define GC_heap_sects GC_arrays._heap_sects
5421 struct HeapSect *_heap_sects;
5422#if defined(USE_PROC_FOR_LIBRARIES)
5423#define GC_our_memory GC_arrays._our_memory
5424 struct HeapSect _our_memory[MAX_HEAP_SECTS];
5425#endif
5426#if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
5427#define GC_heap_bases GC_arrays._heap_bases
5428 ptr_t _heap_bases[MAX_HEAP_SECTS];
5429#endif
5430#ifdef MSWINCE
5431#define GC_heap_lengths GC_arrays._heap_lengths
5432 word _heap_lengths[MAX_HEAP_SECTS];
5433#endif
5434 struct roots _static_roots[MAX_ROOT_SETS];
5435 struct exclusion _excl_table[MAX_EXCLUSIONS];
5436 bottom_index * _top_index[TOP_SZ];
5437};
5438GC_API_PRIV GC_FAR struct _GC_arrays GC_arrays;
5439#define GC_all_nils GC_arrays._all_nils
5440#define GC_atomic_in_use GC_arrays._atomic_in_use
5441#define GC_bytes_allocd_before_gc GC_arrays._bytes_allocd_before_gc
5442#define GC_bytes_dropped GC_arrays._bytes_dropped
5443#define GC_bytes_finalized GC_arrays._bytes_finalized
5444#define GC_bytes_freed GC_arrays._bytes_freed
5445#define GC_composite_in_use GC_arrays._composite_in_use
5446#define GC_excl_table GC_arrays._excl_table
5447#define GC_finalizer_bytes_freed GC_arrays._finalizer_bytes_freed
5448#define GC_heapsize GC_arrays._heapsize
5449#define GC_large_allocd_bytes GC_arrays._large_allocd_bytes
5450#define GC_large_free_bytes GC_arrays._large_free_bytes
5451#define GC_last_heap_addr GC_arrays._last_heap_addr
5452#define GC_mark_stack GC_arrays._mark_stack
5453#define GC_mark_stack_limit GC_arrays._mark_stack_limit
5454#define GC_mark_stack_top GC_arrays._mark_stack_top
5455#define GC_mark_procs GC_arrays._mark_procs
5456#define GC_max_large_allocd_bytes GC_arrays._max_large_allocd_bytes
5457#define GC_modws_valid_offsets GC_arrays._modws_valid_offsets
5458#define GC_requested_heapsize GC_arrays._requested_heapsize
5459#define GC_all_bottom_indices GC_arrays._all_bottom_indices
5460#define GC_all_bottom_indices_end GC_arrays._all_bottom_indices_end
5461#define GC_scratch_free_ptr GC_arrays._scratch_free_ptr
5462#define GC_hdr_free_list GC_arrays._hdr_free_list
5463#define GC_scratch_end_ptr GC_arrays._scratch_end_ptr
5464#define GC_size_map GC_arrays._size_map
5465#define GC_static_roots GC_arrays._static_roots
5466#define GC_top_index GC_arrays._top_index
5467#define GC_uobjfreelist GC_arrays._uobjfreelist
5468#define GC_valid_offsets GC_arrays._valid_offsets
5469#define beginGC_arrays ((ptr_t)(&GC_arrays))
5470#define endGC_arrays (((ptr_t)(&GC_arrays)) + (sizeof GC_arrays))
5471#define USED_HEAP_SIZE (GC_heapsize - GC_large_free_bytes)
5472#ifndef MAXOBJKINDS
5473#define MAXOBJKINDS 16
5474#endif
5475GC_EXTERN struct obj_kind {
5476 void **ok_freelist;
5477 struct hblk **ok_reclaim_list;
5478 word ok_descriptor;
5479 GC_bool ok_relocate_descr;
5480 GC_bool ok_init;
5481#ifdef ENABLE_DISCLAIM
5482 GC_bool ok_mark_unconditionally;
5483 int (GC_CALLBACK *ok_disclaim_proc)(void * );
5484#define OK_DISCLAIM_INITZ , FALSE, 0
5485#else
5486#define OK_DISCLAIM_INITZ
5487#endif
5488} GC_obj_kinds[MAXOBJKINDS];
5489#define beginGC_obj_kinds ((ptr_t)(&GC_obj_kinds))
5490#define endGC_obj_kinds (beginGC_obj_kinds + (sizeof GC_obj_kinds))
5491#ifdef SEPARATE_GLOBALS
5492 extern word GC_bytes_allocd;
5493 extern ptr_t GC_objfreelist[MAXOBJGRANULES+1];
5494#define beginGC_objfreelist ((ptr_t)(&GC_objfreelist))
5495#define endGC_objfreelist (beginGC_objfreelist + sizeof(GC_objfreelist))
5496 extern ptr_t GC_aobjfreelist[MAXOBJGRANULES+1];
5497#define beginGC_aobjfreelist ((ptr_t)(&GC_aobjfreelist))
5498#define endGC_aobjfreelist (beginGC_aobjfreelist + sizeof(GC_aobjfreelist))
5499#endif
5500#define PTRFREE 0
5501#define NORMAL 1
5502#define UNCOLLECTABLE 2
5503#ifdef GC_ATOMIC_UNCOLLECTABLE
5504#define AUNCOLLECTABLE 3
5505#define IS_UNCOLLECTABLE(k) (((k) & ~1) == UNCOLLECTABLE)
5506#define GC_N_KINDS_INITIAL_VALUE 4
5507#else
5508#define IS_UNCOLLECTABLE(k) ((k) == UNCOLLECTABLE)
5509#define GC_N_KINDS_INITIAL_VALUE 3
5510#endif
5511GC_EXTERN unsigned GC_n_kinds;
5512GC_EXTERN size_t GC_page_size;
5513#define ROUNDUP_PAGESIZE(lb) \
5514 (SIZET_SAT_ADD(lb, GC_page_size - 1) & ~(GC_page_size - 1))
5515#ifdef MMAP_SUPPORTED
5516#define ROUNDUP_PAGESIZE_IF_MMAP(lb) ROUNDUP_PAGESIZE(lb)
5517#else
5518#define ROUNDUP_PAGESIZE_IF_MMAP(lb) (lb)
5519#endif
5520#if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
5521 GC_EXTERN SYSTEM_INFO GC_sysinfo;
5522 GC_INNER GC_bool GC_is_heap_base(void *p);
5523#endif
5524GC_EXTERN word GC_black_list_spacing;
5525#ifdef GC_GCJ_SUPPORT
5526 extern struct hblk * GC_hblkfreelist[];
5527 extern word GC_free_bytes[];
5528#endif
5529GC_EXTERN word GC_root_size;
5530GC_EXTERN GC_bool GC_debugging_started;
5531struct blocking_data {
5532 GC_fn_type fn;
5533 void * client_data;
5534};
5535struct GC_traced_stack_sect_s {
5536 ptr_t saved_stack_ptr;
5537#ifdef IA64
5538 ptr_t saved_backing_store_ptr;
5539 ptr_t backing_store_end;
5540#endif
5541 struct GC_traced_stack_sect_s *prev;
5542};
5543#ifdef THREADS
5544 GC_INNER void GC_push_all_stack_sections(ptr_t lo, ptr_t hi,
5545 struct GC_traced_stack_sect_s *traced_stack_sect);
5546 GC_EXTERN word GC_total_stacksize;
5547#else
5548 GC_EXTERN ptr_t GC_blocked_sp;
5549 GC_EXTERN struct GC_traced_stack_sect_s *GC_traced_stack_sect;
5550#endif
5551#ifdef IA64
5552 GC_INNER void GC_push_all_register_sections(ptr_t bs_lo, ptr_t bs_hi,
5553 int eager, struct GC_traced_stack_sect_s *traced_stack_sect);
5554#endif
5555#ifdef USE_MARK_BYTES
5556#define mark_bit_from_hdr(hhdr,n) ((hhdr)->hb_marks[n])
5557#define set_mark_bit_from_hdr(hhdr,n) ((hhdr)->hb_marks[n] = 1)
5558#define clear_mark_bit_from_hdr(hhdr,n) ((hhdr)->hb_marks[n] = 0)
5559#else
5560#if defined(PARALLEL_MARK) || (defined(THREAD_SANITIZER) && defined(THREADS))
5561#define OR_WORD(addr, bits) AO_or((volatile AO_t *)(addr), (AO_t)(bits))
5562#else
5563#define OR_WORD(addr, bits) (void)(*(addr) |= (bits))
5564#endif
5565#define mark_bit_from_hdr(hhdr,n) \
5566 (((hhdr)->hb_marks[divWORDSZ(n)] >> modWORDSZ(n)) & (word)1)
5567#define set_mark_bit_from_hdr(hhdr,n) \
5568 OR_WORD((hhdr)->hb_marks+divWORDSZ(n), (word)1 << modWORDSZ(n))
5569#define clear_mark_bit_from_hdr(hhdr,n) \
5570 ((hhdr)->hb_marks[divWORDSZ(n)] &= ~((word)1 << modWORDSZ(n)))
5571#endif
5572#ifdef MARK_BIT_PER_OBJ
5573#define MARK_BIT_NO(offset, sz) (((word)(offset))/(sz))
5574#define MARK_BIT_OFFSET(sz) 1
5575#define IF_PER_OBJ(x) x
5576#define FINAL_MARK_BIT(sz) ((sz) > MAXOBJBYTES? 1 : HBLK_OBJS(sz))
5577#else
5578#define MARK_BIT_NO(offset, sz) BYTES_TO_GRANULES((word)(offset))
5579#define MARK_BIT_OFFSET(sz) BYTES_TO_GRANULES(sz)
5580#define IF_PER_OBJ(x)
5581#define FINAL_MARK_BIT(sz) \
5582 ((sz) > MAXOBJBYTES ? MARK_BITS_PER_HBLK \
5583 : BYTES_TO_GRANULES((sz) * HBLK_OBJS(sz)))
5584#endif
5585GC_INNER ptr_t GC_approx_sp(void);
5586GC_INNER GC_bool GC_should_collect(void);
5587void GC_apply_to_all_blocks(void (*fn)(struct hblk *h, word client_data),
5588 word client_data);
5589GC_INNER struct hblk * GC_next_block(struct hblk *h, GC_bool allow_free);
5590GC_INNER struct hblk * GC_prev_block(struct hblk * h);
5591GC_INNER void GC_mark_init(void);
5592GC_INNER void GC_clear_marks(void);
5593GC_INNER void GC_invalidate_mark_state(void);
5594GC_INNER GC_bool GC_mark_some(ptr_t cold_gc_frame);
5595GC_INNER void GC_initiate_gc(void);
5596GC_INNER GC_bool GC_collection_in_progress(void);
5597#define GC_PUSH_ALL_SYM(sym) \
5598 GC_push_all(( void *)&(sym), \
5599 ( void *)(&(sym) + 1))
5600GC_INNER void GC_push_all_stack(ptr_t b, ptr_t t);
5601#ifdef NO_VDB_FOR_STATIC_ROOTS
5602#define GC_push_conditional_static(b, t, all) \
5603 ((void)(all), GC_push_all(b, t))
5604#else
5605 GC_INNER void GC_push_conditional_static(void *b, void *t, GC_bool all);
5606#endif
5607#if defined(WRAP_MARK_SOME) && defined(PARALLEL_MARK)
5608 GC_INNER void GC_push_conditional_eager(void *bottom, void *top,
5609 GC_bool all);
5610#endif
5611GC_INNER void GC_push_roots(GC_bool all, ptr_t cold_gc_frame);
5612GC_API_PRIV GC_push_other_roots_proc GC_push_other_roots;
5613#ifdef THREADS
5614 void GC_push_thread_structures(void);
5615#endif
5616GC_EXTERN void (*GC_push_typed_structures)(void);
5617GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
5618 volatile ptr_t arg);
5619#if defined(SPARC) || defined(IA64)
5620 ptr_t GC_save_regs_in_stack(void);
5621#endif
5622#if defined(AMIGA) || defined(MACOS) || defined(GC_DARWIN_THREADS)
5623 void GC_push_one(word p);
5624#endif
5625#ifdef GC_WIN32_THREADS
5626 GC_INNER void GC_push_many_regs(const word *regs, unsigned count);
5627#endif
5628#if defined(PRINT_BLACK_LIST) || defined(KEEP_BACK_PTRS)
5629 GC_INNER void GC_mark_and_push_stack(ptr_t p, ptr_t source);
5630#else
5631 GC_INNER void GC_mark_and_push_stack(ptr_t p);
5632#endif
5633GC_INNER void GC_clear_hdr_marks(hdr * hhdr);
5634GC_INNER void GC_set_hdr_marks(hdr * hhdr);
5635GC_INNER void GC_set_fl_marks(ptr_t p);
5636#if defined(GC_ASSERTIONS) && defined(THREAD_LOCAL_ALLOC)
5637 void GC_check_fl_marks(void **);
5638#endif
5639void GC_add_roots_inner(ptr_t b, ptr_t e, GC_bool tmp);
5640#ifdef USE_PROC_FOR_LIBRARIES
5641 GC_INNER void GC_remove_roots_subregion(ptr_t b, ptr_t e);
5642#endif
5643GC_INNER void GC_exclude_static_roots_inner(void *start, void *finish);
5644#if defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE) \
5645 || defined(CYGWIN32) || defined(PCR)
5646 GC_INNER void GC_register_dynamic_libraries(void);
5647#endif
5648GC_INNER void GC_cond_register_dynamic_libraries(void);
5649ptr_t GC_get_main_stack_base(void);
5650#ifdef IA64
5651 GC_INNER ptr_t GC_get_register_stack_base(void);
5652#endif
5653void GC_register_data_segments(void);
5654#ifdef THREADS
5655 GC_INNER void GC_thr_init(void);
5656 GC_INNER void GC_init_parallel(void);
5657#else
5658 GC_INNER GC_bool GC_is_static_root(void *p);
5659#ifdef TRACE_BUF
5660 void GC_add_trace_entry(char *kind, word arg1, word arg2);
5661#endif
5662#endif
5663#ifdef PRINT_BLACK_LIST
5664 GC_INNER void GC_add_to_black_list_normal(word p, ptr_t source);
5665#define GC_ADD_TO_BLACK_LIST_NORMAL(bits, source) \
5666 if (GC_all_interior_pointers) { \
5667 GC_add_to_black_list_stack((word)(bits), (source)); \
5668 } else \
5669 GC_add_to_black_list_normal((word)(bits), (source))
5670 GC_INNER void GC_add_to_black_list_stack(word p, ptr_t source);
5671#define GC_ADD_TO_BLACK_LIST_STACK(bits, source) \
5672 GC_add_to_black_list_stack((word)(bits), (source))
5673#else
5674 GC_INNER void GC_add_to_black_list_normal(word p);
5675#define GC_ADD_TO_BLACK_LIST_NORMAL(bits, source) \
5676 if (GC_all_interior_pointers) { \
5677 GC_add_to_black_list_stack((word)(bits)); \
5678 } else \
5679 GC_add_to_black_list_normal((word)(bits))
5680 GC_INNER void GC_add_to_black_list_stack(word p);
5681#define GC_ADD_TO_BLACK_LIST_STACK(bits, source) \
5682 GC_add_to_black_list_stack((word)(bits))
5683#endif
5684struct hblk * GC_is_black_listed(struct hblk * h, word len);
5685GC_INNER void GC_promote_black_lists(void);
5686GC_INNER void GC_unpromote_black_lists(void);
5687GC_INNER ptr_t GC_scratch_alloc(size_t bytes);
5688#ifdef GWW_VDB
5689#else
5690#define GC_scratch_recycle_no_gww GC_scratch_recycle_inner
5691#endif
5692GC_INNER void GC_scratch_recycle_inner(void *ptr, size_t bytes);
5693#ifdef MARK_BIT_PER_GRANULE
5694 GC_INNER GC_bool GC_add_map_entry(size_t sz);
5695#endif
5696GC_INNER void GC_register_displacement_inner(size_t offset);
5697GC_INNER void GC_new_hblk(size_t size_in_granules, int kind);
5698GC_INNER ptr_t GC_build_fl(struct hblk *h, size_t words, GC_bool clear,
5699 ptr_t list);
5700GC_INNER struct hblk * GC_allochblk(size_t size_in_bytes, int kind,
5701 unsigned flags);
5702GC_INNER ptr_t GC_alloc_large(size_t lb, int k, unsigned flags);
5703GC_INNER void GC_freehblk(struct hblk * p);
5704GC_INNER GC_bool GC_expand_hp_inner(word n);
5705GC_INNER void GC_start_reclaim(GC_bool abort_if_found);
5706GC_INNER void GC_continue_reclaim(word sz, int kind);
5707GC_INNER GC_bool GC_reclaim_all(GC_stop_func stop_func, GC_bool ignore_old);
5708GC_INNER ptr_t GC_reclaim_generic(struct hblk * hbp, hdr *hhdr, size_t sz,
5709 GC_bool init, ptr_t list,
5710 signed_word *count);
5711GC_INNER GC_bool GC_block_empty(hdr * hhdr);
5712GC_INNER int GC_CALLBACK GC_never_stop_func(void);
5713GC_INNER GC_bool GC_try_to_collect_inner(GC_stop_func f);
5714#define GC_gcollect_inner() \
5715 (void)GC_try_to_collect_inner(GC_never_stop_func)
5716#ifdef THREADS
5717 GC_EXTERN GC_bool GC_in_thread_creation;
5718#endif
5719GC_EXTERN GC_bool GC_is_initialized;
5720GC_INNER void GC_collect_a_little_inner(int n);
5721GC_INNER void * GC_generic_malloc_inner(size_t lb, int k);
5722#if defined(DBG_HDRS_ALL) || defined(GC_GCJ_SUPPORT) \
5723 || !defined(GC_NO_FINALIZATION)
5724 GC_INNER void * GC_generic_malloc_inner_ignore_off_page(size_t lb, int k);
5725#endif
5726GC_INNER GC_bool GC_collect_or_expand(word needed_blocks,
5727 GC_bool ignore_off_page, GC_bool retry);
5728GC_INNER ptr_t GC_allocobj(size_t sz, int kind);
5729#ifdef GC_ADD_CALLER
5730#ifdef GC_HAVE_RETURN_ADDR_PARENT
5731#define GC_DBG_EXTRAS GC_RETURN_ADDR_PARENT, NULL, 0
5732#else
5733#define GC_DBG_EXTRAS GC_RETURN_ADDR, NULL, 0
5734#endif
5735#else
5736#define GC_DBG_EXTRAS "unknown", 0
5737#endif
5738#ifdef GC_COLLECT_AT_MALLOC
5739 extern size_t GC_dbg_collect_at_malloc_min_lb;
5740#define GC_DBG_COLLECT_AT_MALLOC(lb) \
5741 (void)((lb) >= GC_dbg_collect_at_malloc_min_lb ? \
5742 (GC_gcollect(), 0) : 0)
5743#else
5744#define GC_DBG_COLLECT_AT_MALLOC(lb) (void)0
5745#endif
5746#if defined(THREAD_LOCAL_ALLOC) && defined(GC_GCJ_SUPPORT)
5747 GC_INNER void * GC_core_gcj_malloc(size_t, void *);
5748#endif
5749GC_INNER void GC_init_headers(void);
5750GC_INNER struct hblkhdr * GC_install_header(struct hblk *h);
5751GC_INNER GC_bool GC_install_counts(struct hblk * h, size_t sz);
5752GC_INNER void GC_remove_header(struct hblk * h);
5753GC_INNER void GC_remove_counts(struct hblk * h, size_t sz);
5754GC_INNER hdr * GC_find_header(ptr_t h);
5755#ifdef USE_PROC_FOR_LIBRARIES
5756 GC_INNER void GC_add_to_our_memory(ptr_t p, size_t bytes);
5757#else
5758#define GC_add_to_our_memory(p, bytes) \
5759 (GC_our_mem_bytes += (bytes), (void)(p))
5760#endif
5761GC_INNER void GC_print_all_errors(void);
5762GC_EXTERN void (*GC_check_heap)(void);
5763GC_EXTERN void (*GC_print_all_smashed)(void);
5764GC_EXTERN void (*GC_print_heap_obj)(ptr_t p);
5765#if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG)
5766 void GC_print_address_map(void);
5767#endif
5768#ifndef SHORT_DBG_HDRS
5769 GC_EXTERN GC_bool GC_findleak_delay_free;
5770 GC_INNER GC_bool GC_check_leaked(ptr_t base);
5771#endif
5772GC_EXTERN GC_bool GC_have_errors;
5773#define VERBOSE 2
5774#if !defined(NO_CLOCK) || !defined(SMALL_CONFIG)
5775 extern int GC_print_stats;
5776#else
5777#define GC_print_stats 0
5778#endif
5779#ifdef KEEP_BACK_PTRS
5780 GC_EXTERN long GC_backtraces;
5781 GC_INNER void GC_generate_random_backtrace_no_gc(void);
5782#endif
5783#ifdef LINT2
5784#define GC_RAND_MAX (~0U >> 1)
5785 GC_API_PRIV long GC_random(void);
5786#endif
5787GC_EXTERN GC_bool GC_print_back_height;
5788#ifdef MAKE_BACK_GRAPH
5789 void GC_print_back_graph_stats(void);
5790#endif
5791#ifdef THREADS
5792 GC_INNER void GC_free_inner(void * p);
5793#endif
5794#ifdef DBG_HDRS_ALL
5795 GC_INNER void * GC_debug_generic_malloc_inner(size_t lb, int k);
5796 GC_INNER void * GC_debug_generic_malloc_inner_ignore_off_page(size_t lb,
5797 int k);
5798#define GC_INTERNAL_MALLOC GC_debug_generic_malloc_inner
5799#define GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE \
5800 GC_debug_generic_malloc_inner_ignore_off_page
5801#ifdef THREADS
5802 GC_INNER void GC_debug_free_inner(void * p);
5803#define GC_INTERNAL_FREE GC_debug_free_inner
5804#else
5805#define GC_INTERNAL_FREE GC_debug_free
5806#endif
5807#else
5808#define GC_INTERNAL_MALLOC GC_generic_malloc_inner
5809#define GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE \
5810 GC_generic_malloc_inner_ignore_off_page
5811#ifdef THREADS
5812#define GC_INTERNAL_FREE GC_free_inner
5813#else
5814#define GC_INTERNAL_FREE GC_free
5815#endif
5816#endif
5817#ifdef USE_MUNMAP
5818 GC_INNER void GC_unmap_old(void);
5819 GC_INNER void GC_merge_unmapped(void);
5820 GC_INNER void GC_unmap(ptr_t start, size_t bytes);
5821 GC_INNER void GC_remap(ptr_t start, size_t bytes);
5822 GC_INNER void GC_unmap_gap(ptr_t start1, size_t bytes1, ptr_t start2,
5823 size_t bytes2);
5824 GC_INLINE ptr_t GC_unmap_end(ptr_t start, size_t bytes)
5825 {
5826 return (ptr_t)((word)(start + bytes) & ~(GC_page_size - 1));
5827 }
5828#endif
5829#ifdef CAN_HANDLE_FORK
5830 GC_EXTERN int GC_handle_fork;
5831#endif
5832#ifdef GC_DISABLE_INCREMENTAL
5833#define GC_incremental FALSE
5834#define GC_auto_incremental FALSE
5835#define GC_manual_vdb FALSE
5836#define GC_dirty(p) (void)(p)
5837#define REACHABLE_AFTER_DIRTY(p) (void)(p)
5838#else
5839 GC_EXTERN GC_bool GC_incremental;
5840 GC_INNER void GC_read_dirty(GC_bool output_unneeded);
5841 GC_INNER GC_bool GC_page_was_dirty(struct hblk *h);
5842 GC_INNER void GC_remove_protection(struct hblk *h, word nblocks,
5843 GC_bool pointerfree);
5844#if !defined(NO_VDB_FOR_STATIC_ROOTS) && !defined(PROC_VDB)
5845 GC_INNER GC_bool GC_is_vdb_for_static_roots(void);
5846#endif
5847#ifdef CAN_HANDLE_FORK
5848#if defined(PROC_VDB) || defined(SOFT_VDB)
5849 GC_INNER void GC_dirty_update_child(void);
5850#else
5851#define GC_dirty_update_child() (void)0
5852#endif
5853#endif
5854 GC_INNER GC_bool GC_dirty_init(void);
5855 GC_EXTERN GC_bool GC_manual_vdb;
5856#define GC_auto_incremental (GC_incremental && !GC_manual_vdb)
5857 GC_INNER void GC_dirty_inner(const void *p);
5858#define GC_dirty(p) (GC_manual_vdb ? GC_dirty_inner(p) : (void)0)
5859#define REACHABLE_AFTER_DIRTY(p) GC_reachable_here(p)
5860#endif
5861#define GC_base_C(p) ((const void *)GC_base(( void *)(p)))
5862void GC_print_block_list(void);
5863void GC_print_hblkfreelist(void);
5864void GC_print_heap_sects(void);
5865void GC_print_static_roots(void);
5866#ifdef KEEP_BACK_PTRS
5867 GC_INNER void GC_store_back_pointer(ptr_t source, ptr_t dest);
5868 GC_INNER void GC_marked_for_finalization(ptr_t dest);
5869#define GC_STORE_BACK_PTR(source, dest) GC_store_back_pointer(source, dest)
5870#define GC_MARKED_FOR_FINALIZATION(dest) GC_marked_for_finalization(dest)
5871#else
5872#define GC_STORE_BACK_PTR(source, dest) (void)(source)
5873#define GC_MARKED_FOR_FINALIZATION(dest)
5874#endif
5875void GC_noop6(word, word, word, word, word, word);
5876GC_API void GC_CALL GC_noop1(word);
5877#ifndef GC_ATTR_FORMAT_PRINTF
5878#if GC_GNUC_PREREQ(3, 0)
5879#define GC_ATTR_FORMAT_PRINTF(spec_argnum, first_checked) \
5880 __attribute__((__format__(__printf__, spec_argnum, first_checked)))
5881#else
5882#define GC_ATTR_FORMAT_PRINTF(spec_argnum, first_checked)
5883#endif
5884#endif
5885GC_API_PRIV void GC_printf(const char * format, ...)
5886 GC_ATTR_FORMAT_PRINTF(1, 2);
5887GC_API_PRIV void GC_err_printf(const char * format, ...)
5888 GC_ATTR_FORMAT_PRINTF(1, 2);
5889GC_API_PRIV void GC_log_printf(const char * format, ...)
5890 GC_ATTR_FORMAT_PRINTF(1, 2);
5891#ifndef GC_ANDROID_LOG
5892#define GC_PRINT_STATS_FLAG (GC_print_stats != 0)
5893#define GC_INFOLOG_PRINTF GC_COND_LOG_PRINTF
5894#define GC_verbose_log_printf GC_log_printf
5895#else
5896 extern GC_bool GC_quiet;
5897#define GC_PRINT_STATS_FLAG (!GC_quiet)
5898#ifndef GC_INFOLOG_PRINTF
5899#define GC_INFOLOG_PRINTF if (GC_quiet) {} else GC_info_log_printf
5900#endif
5901 GC_INNER void GC_info_log_printf(const char *format, ...)
5902 GC_ATTR_FORMAT_PRINTF(1, 2);
5903 GC_INNER void GC_verbose_log_printf(const char *format, ...)
5904 GC_ATTR_FORMAT_PRINTF(1, 2);
5905#endif
5906#if defined(SMALL_CONFIG) || defined(GC_ANDROID_LOG)
5907#define GC_ERRINFO_PRINTF GC_INFOLOG_PRINTF
5908#else
5909#define GC_ERRINFO_PRINTF GC_log_printf
5910#endif
5911#define GC_COND_LOG_PRINTF \
5912 if (EXPECT(!GC_print_stats, TRUE)) {} else GC_log_printf
5913#define GC_VERBOSE_LOG_PRINTF \
5914 if (EXPECT(GC_print_stats != VERBOSE, TRUE)) {} else GC_verbose_log_printf
5915#ifndef GC_DBGLOG_PRINTF
5916#define GC_DBGLOG_PRINTF if (!GC_PRINT_STATS_FLAG) {} else GC_log_printf
5917#endif
5918void GC_err_puts(const char *s);
5919#define TO_KiB_UL(v) ((unsigned long)(((v) + ((1 << 9) - 1)) >> 10))
5920GC_EXTERN unsigned GC_fail_count;
5921GC_EXTERN long GC_large_alloc_warn_interval;
5922GC_EXTERN signed_word GC_bytes_found;
5923#ifndef GC_GET_HEAP_USAGE_NOT_NEEDED
5924 GC_EXTERN word GC_reclaimed_bytes_before_gc;
5925#endif
5926#ifdef USE_MUNMAP
5927 GC_EXTERN int GC_unmap_threshold;
5928 GC_EXTERN GC_bool GC_force_unmap_on_gcollect;
5929#endif
5930#ifdef MSWIN32
5931 GC_EXTERN GC_bool GC_no_win32_dlls;
5932 GC_EXTERN GC_bool GC_wnt;
5933#endif
5934#ifdef THREADS
5935#if (defined(MSWIN32) && !defined(CONSOLE_LOG)) || defined(MSWINCE)
5936 GC_EXTERN CRITICAL_SECTION GC_write_cs;
5937#ifdef GC_ASSERTIONS
5938 GC_EXTERN GC_bool GC_write_disabled;
5939#endif
5940#endif
5941#if defined(GC_DISABLE_INCREMENTAL) || defined(HAVE_LOCKFREE_AO_OR)
5942#define GC_acquire_dirty_lock() (void)0
5943#define GC_release_dirty_lock() (void)0
5944#else
5945#define GC_acquire_dirty_lock() \
5946 do { \
5947 } while (AO_test_and_set_acquire(&GC_fault_handler_lock) == AO_TS_SET)
5948#define GC_release_dirty_lock() AO_CLEAR(&GC_fault_handler_lock)
5949 GC_EXTERN volatile AO_TS_t GC_fault_handler_lock;
5950#endif
5951#ifdef MSWINCE
5952 GC_EXTERN GC_bool GC_dont_query_stack_min;
5953#endif
5954#elif defined(IA64)
5955 GC_EXTERN ptr_t GC_save_regs_ret_val;
5956#endif
5957#ifdef THREAD_LOCAL_ALLOC
5958 GC_EXTERN GC_bool GC_world_stopped;
5959 GC_INNER void GC_mark_thread_local_free_lists(void);
5960#endif
5961#if defined(GLIBC_2_19_TSX_BUG) && defined(THREADS)
5962 GC_INNER int GC_parse_version(int *pminor, const char *pverstr);
5963#endif
5964#if defined(MPROTECT_VDB) && defined(GWW_VDB)
5965 GC_INNER GC_bool GC_gww_dirty_init(void);
5966#endif
5967#if defined(CHECKSUMS) || defined(PROC_VDB)
5968 GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk * h);
5969#endif
5970#ifdef CHECKSUMS
5971#if defined(MPROTECT_VDB) && !defined(DARWIN)
5972 void GC_record_fault(struct hblk * h);
5973#endif
5974 void GC_check_dirty(void);
5975#endif
5976GC_INNER void GC_default_print_heap_obj_proc(ptr_t p);
5977GC_INNER void GC_setpagesize(void);
5978GC_INNER void GC_initialize_offsets(void);
5979GC_INNER void GC_bl_init(void);
5980GC_INNER void GC_bl_init_no_interiors(void);
5981GC_INNER void GC_start_debugging_inner(void);
5982GC_INNER void *GC_store_debug_info_inner(void *p, word sz, const char *str,
5983 int linenum);
5984#ifdef REDIRECT_MALLOC
5985#ifdef GC_LINUX_THREADS
5986 GC_INNER GC_bool GC_text_mapping(char *nm, ptr_t *startp, ptr_t *endp);
5987#endif
5988#elif defined(USE_WINALLOC)
5989 GC_INNER void GC_add_current_malloc_heap(void);
5990#endif
5991#ifdef MAKE_BACK_GRAPH
5992 GC_INNER void GC_build_back_graph(void);
5993 GC_INNER void GC_traverse_back_graph(void);
5994#endif
5995#ifdef MSWIN32
5996 GC_INNER void GC_init_win32(void);
5997#endif
5998#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
5999 GC_INNER void * GC_roots_present(ptr_t);
6000#endif
6001#ifdef GC_WIN32_THREADS
6002 GC_INNER void GC_get_next_stack(char *start, char * limit, char **lo,
6003 char **hi);
6004#if defined(MPROTECT_VDB) && !defined(CYGWIN32)
6005 GC_INNER void GC_set_write_fault_handler(void);
6006#endif
6007#if defined(WRAP_MARK_SOME) && !defined(GC_PTHREADS)
6008 GC_INNER GC_bool GC_started_thread_while_stopped(void);
6009#endif
6010#endif
6011#ifdef THREADS
6012 GC_INNER void GC_reset_finalizer_nested(void);
6013 GC_INNER unsigned char *GC_check_finalizer_nested(void);
6014 GC_INNER void GC_do_blocking_inner(ptr_t data, void * context);
6015 GC_INNER void GC_push_all_stacks(void);
6016#ifdef USE_PROC_FOR_LIBRARIES
6017 GC_INNER GC_bool GC_segment_is_thread_stack(ptr_t lo, ptr_t hi);
6018#endif
6019#ifdef IA64
6020 GC_INNER ptr_t GC_greatest_stack_base_below(ptr_t bound);
6021#endif
6022#endif
6023#ifdef DYNAMIC_LOADING
6024 GC_INNER GC_bool GC_register_main_static_data(void);
6025#ifdef DARWIN
6026 GC_INNER void GC_init_dyld(void);
6027#endif
6028#endif
6029#ifdef SEARCH_FOR_DATA_START
6030 GC_INNER void GC_init_linux_data_start(void);
6031 void * GC_find_limit(void *, int);
6032#endif
6033#if defined(NETBSD) && defined(__ELF__)
6034 GC_INNER void GC_init_netbsd_elf(void);
6035 void * GC_find_limit(void *, int);
6036#endif
6037#ifdef UNIX_LIKE
6038 GC_INNER void GC_set_and_save_fault_handler(void (*handler)(int));
6039#endif
6040#ifdef NEED_PROC_MAPS
6041#if defined(DYNAMIC_LOADING) && defined(USE_PROC_FOR_LIBRARIES)
6042 GC_INNER const char *GC_parse_map_entry(const char *maps_ptr,
6043 ptr_t *start, ptr_t *end,
6044 const char **prot,
6045 unsigned *maj_dev,
6046 const char **mapping_name);
6047#endif
6048#if defined(IA64) || defined(INCLUDE_LINUX_THREAD_DESCR)
6049 GC_INNER GC_bool GC_enclosing_mapping(ptr_t addr,
6050 ptr_t *startp, ptr_t *endp);
6051#endif
6052 GC_INNER const char *GC_get_maps(void);
6053#endif
6054#ifdef GC_ASSERTIONS
6055#define GC_ASSERT(expr) \
6056 do { \
6057 if (!(expr)) { \
6058 GC_err_printf("Assertion failure: %s:%d\n", \
6059 __FILE__, __LINE__); \
6060 ABORT("assertion failure"); \
6061 } \
6062 } while (0)
6063 GC_INNER word GC_compute_large_free_bytes(void);
6064 GC_INNER word GC_compute_root_size(void);
6065#else
6066#define GC_ASSERT(expr)
6067#endif
6068#if _MSC_VER >= 1700
6069#define GC_STATIC_ASSERT(expr) \
6070 static_assert(expr, "static assertion failed: " #expr)
6071#elif defined(static_assert) && __STDC_VERSION__ >= 201112L
6072#define GC_STATIC_ASSERT(expr) static_assert(expr, #expr)
6073#elif defined(mips) && !defined(__GNUC__)
6074#define GC_STATIC_ASSERT(expr) \
6075 do { if (0) { char j[(expr)? 1 : -1]; j[0]='\0'; j[0]=j[0]; } } while(0)
6076#else
6077#define GC_STATIC_ASSERT(expr) (void)sizeof(char[(expr)? 1 : -1])
6078#endif
6079#if GC_GNUC_PREREQ(4, 0)
6080#define NONNULL_ARG_NOT_NULL(arg) (*(volatile void **)&(arg) != NULL)
6081#else
6082#define NONNULL_ARG_NOT_NULL(arg) (NULL != (arg))
6083#endif
6084#define COND_DUMP_CHECKS \
6085 do { \
6086 GC_ASSERT(GC_compute_large_free_bytes() == GC_large_free_bytes); \
6087 GC_ASSERT(GC_compute_root_size() == GC_root_size); \
6088 } while (0)
6089#ifndef NO_DEBUGGING
6090 GC_EXTERN GC_bool GC_dump_regularly;
6091#define COND_DUMP if (EXPECT(GC_dump_regularly, FALSE)) { \
6092 GC_dump_named(NULL); \
6093 } else COND_DUMP_CHECKS
6094#else
6095#define COND_DUMP COND_DUMP_CHECKS
6096#endif
6097#if defined(PARALLEL_MARK)
6098#define GC_markers_m1 GC_parallel
6099 GC_EXTERN GC_bool GC_parallel_mark_disabled;
6100 GC_INNER void GC_wait_for_markers_init(void);
6101 GC_INNER void GC_acquire_mark_lock(void);
6102 GC_INNER void GC_release_mark_lock(void);
6103 GC_INNER void GC_notify_all_builder(void);
6104 GC_INNER void GC_wait_for_reclaim(void);
6105 GC_EXTERN signed_word GC_fl_builder_count;
6106 GC_INNER void GC_notify_all_marker(void);
6107 GC_INNER void GC_wait_marker(void);
6108 GC_EXTERN word GC_mark_no;
6109 GC_INNER void GC_help_marker(word my_mark_no);
6110 GC_INNER void GC_start_mark_threads_inner(void);
6111#endif
6112#if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS) && !defined(NACL) \
6113 && !defined(GC_DARWIN_THREADS) && !defined(SIG_SUSPEND)
6114#if (defined(GC_LINUX_THREADS) || defined(GC_DGUX386_THREADS)) \
6115 && !defined(GC_USESIGRT_SIGNALS)
6116#if defined(SPARC) && !defined(SIGPWR)
6117#define SIG_SUSPEND SIGLOST
6118#else
6119#define SIG_SUSPEND SIGPWR
6120#endif
6121#elif defined(GC_OPENBSD_THREADS)
6122#ifndef GC_OPENBSD_UTHREADS
6123#define SIG_SUSPEND SIGXFSZ
6124#endif
6125#elif defined(_SIGRTMIN) && !defined(CPPCHECK)
6126#define SIG_SUSPEND _SIGRTMIN + 6
6127#else
6128#define SIG_SUSPEND SIGRTMIN + 6
6129#endif
6130#endif
6131#if defined(GC_PTHREADS) && !defined(GC_SEM_INIT_PSHARED)
6132#define GC_SEM_INIT_PSHARED 0
6133#endif
6134#if (defined(UNIX_LIKE) || (defined(NEED_FIND_LIMIT) && defined(CYGWIN32))) \
6135 && !defined(GC_NO_SIGSETJMP)
6136#if defined(SUNOS5SIGS) && !defined(FREEBSD) && !defined(LINUX)
6137 EXTERN_C_END
6138#include <sys/siginfo.h>
6139 EXTERN_C_BEGIN
6140#endif
6141#define SETJMP(env) sigsetjmp(env, 1)
6142#define LONGJMP(env, val) siglongjmp(env, val)
6143#define JMP_BUF sigjmp_buf
6144#else
6145#ifdef ECOS
6146#define SETJMP(env) hal_setjmp(env)
6147#else
6148#define SETJMP(env) setjmp(env)
6149#endif
6150#define LONGJMP(env, val) longjmp(env, val)
6151#define JMP_BUF jmp_buf
6152#endif
6153#if defined(HEURISTIC2) || defined(SEARCH_FOR_DATA_START) \
6154 || ((defined(SVR4) || defined(AIX) || defined(DGUX) \
6155 || (defined(LINUX) && defined(SPARC))) && !defined(PCR))
6156#define NEED_FIND_LIMIT
6157#endif
6158#if defined(DATASTART_USES_BSDGETDATASTART)
6159 EXTERN_C_END
6160#include <machine/trap.h>
6161 EXTERN_C_BEGIN
6162#if !defined(PCR)
6163#define NEED_FIND_LIMIT
6164#endif
6165 GC_INNER ptr_t GC_FreeBSDGetDataStart(size_t, ptr_t);
6166#define DATASTART_IS_FUNC
6167#endif
6168#if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__) \
6169 && !defined(NEED_FIND_LIMIT)
6170#define NEED_FIND_LIMIT
6171#endif
6172#if defined(IA64) && !defined(NEED_FIND_LIMIT)
6173#define NEED_FIND_LIMIT
6174#endif
6175#if defined(NEED_FIND_LIMIT) \
6176 || (defined(USE_PROC_FOR_LIBRARIES) && defined(THREADS))
6177 GC_EXTERN JMP_BUF GC_jmp_buf;
6178 GC_INNER void GC_setup_temporary_fault_handler(void);
6179 GC_INNER void GC_reset_fault_handler(void);
6180#endif
6181#if defined(CANCEL_SAFE)
6182#if defined(GC_ASSERTIONS) \
6183 && (defined(USE_COMPILER_TLS) \
6184 || (defined(LINUX) && !defined(ARM32) && GC_GNUC_PREREQ(3, 3) \
6185 || defined(HPUX) ))
6186 extern __thread unsigned char GC_cancel_disable_count;
6187#define NEED_CANCEL_DISABLE_COUNT
6188#define INCR_CANCEL_DISABLE() ++GC_cancel_disable_count
6189#define DECR_CANCEL_DISABLE() --GC_cancel_disable_count
6190#define ASSERT_CANCEL_DISABLED() GC_ASSERT(GC_cancel_disable_count > 0)
6191#else
6192#define INCR_CANCEL_DISABLE()
6193#define DECR_CANCEL_DISABLE()
6194#define ASSERT_CANCEL_DISABLED() (void)0
6195#endif
6196#define DISABLE_CANCEL(state) \
6197 do { pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); \
6198 INCR_CANCEL_DISABLE(); } while (0)
6199#define RESTORE_CANCEL(state) \
6200 do { ASSERT_CANCEL_DISABLED(); \
6201 pthread_setcancelstate(state, NULL); \
6202 DECR_CANCEL_DISABLE(); } while (0)
6203#else
6204#define DISABLE_CANCEL(state) (void)0
6205#define RESTORE_CANCEL(state) (void)0
6206#define ASSERT_CANCEL_DISABLED() (void)0
6207#endif
6208EXTERN_C_END
6209#endif
6210#ifdef KEEP_BACK_PTRS
6211#ifndef GC_BACKPTR_H
6212#define GC_BACKPTR_H
6213#ifndef GC_H
6214#endif
6215#ifdef __cplusplus
6216 extern "C" {
6217#endif
6218typedef enum {
6219 GC_UNREFERENCED,
6220 GC_NO_SPACE,
6221 GC_REFD_FROM_ROOT,
6222 GC_REFD_FROM_REG,
6223 GC_REFD_FROM_HEAP,
6224 GC_FINALIZER_REFD
6225} GC_ref_kind;
6226GC_API GC_ref_kind GC_CALL GC_get_back_ptr_info(void * ,
6227 void ** , size_t * )
6228 GC_ATTR_NONNULL(1);
6229GC_API void * GC_CALL GC_generate_random_heap_address(void);
6230GC_API void * GC_CALL GC_generate_random_valid_address(void);
6231GC_API void GC_CALL GC_generate_random_backtrace(void);
6232GC_API void GC_CALL GC_print_backtrace(void *) GC_ATTR_NONNULL(1);
6233#ifdef __cplusplus
6234 }
6235#endif
6236#endif
6237#endif
6238EXTERN_C_BEGIN
6239#if CPP_WORDSZ == 32
6240#define START_FLAG (word)0xfedcedcb
6241#define END_FLAG (word)0xbcdecdef
6242#else
6243#define START_FLAG GC_WORD_C(0xFEDCEDCBfedcedcb)
6244#define END_FLAG GC_WORD_C(0xBCDECDEFbcdecdef)
6245#endif
6246#if defined(KEEP_BACK_PTRS) || defined(PRINT_BLACK_LIST) \
6247 || defined(MAKE_BACK_GRAPH)
6248#define NOT_MARKED (ptr_t)0
6249#define MARKED_FOR_FINALIZATION ((ptr_t)(word)2)
6250#define MARKED_FROM_REGISTER ((ptr_t)(word)4)
6251#endif
6252typedef struct {
6253#if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
6254#if ALIGNMENT == 1
6255#define HIDE_BACK_PTR(p) GC_HIDE_POINTER(~1 & (word)(p))
6256#else
6257#define HIDE_BACK_PTR(p) GC_HIDE_POINTER(p)
6258#endif
6259#ifdef KEEP_BACK_PTRS
6260 GC_hidden_pointer oh_back_ptr;
6261#endif
6262#ifdef MAKE_BACK_GRAPH
6263 GC_hidden_pointer oh_bg_ptr;
6264#endif
6265#if defined(KEEP_BACK_PTRS) != defined(MAKE_BACK_GRAPH)
6266 word oh_dummy;
6267#endif
6268#endif
6269 const char * oh_string;
6270 signed_word oh_int;
6271#ifdef NEED_CALLINFO
6272 struct callinfo oh_ci[NFRAMES];
6273#endif
6274#ifndef SHORT_DBG_HDRS
6275 word oh_sz;
6276 word oh_sf;
6277#endif
6278} oh;
6279#ifdef SHORT_DBG_HDRS
6280#define DEBUG_BYTES (sizeof (oh))
6281#define UNCOLLECTABLE_DEBUG_BYTES DEBUG_BYTES
6282#else
6283#define UNCOLLECTABLE_DEBUG_BYTES (sizeof (oh) + sizeof (word))
6284#define DEBUG_BYTES (UNCOLLECTABLE_DEBUG_BYTES - EXTRA_BYTES)
6285#endif
6286#define SIMPLE_ROUNDED_UP_WORDS(n) BYTES_TO_WORDS((n) + WORDS_TO_BYTES(1) - 1)
6287#if defined(SAVE_CALL_CHAIN)
6288 struct callinfo;
6289 GC_INNER void GC_save_callers(struct callinfo info[NFRAMES]);
6290 GC_INNER void GC_print_callers(struct callinfo info[NFRAMES]);
6291#define ADD_CALL_CHAIN(base, ra) GC_save_callers(((oh *)(base)) -> oh_ci)
6292#define PRINT_CALL_CHAIN(base) GC_print_callers(((oh *)(base)) -> oh_ci)
6293#elif defined(GC_ADD_CALLER)
6294 struct callinfo;
6295 GC_INNER void GC_print_callers(struct callinfo info[NFRAMES]);
6296#define ADD_CALL_CHAIN(base, ra) ((oh *)(base)) -> oh_ci[0].ci_pc = (ra)
6297#define PRINT_CALL_CHAIN(base) GC_print_callers(((oh *)(base)) -> oh_ci)
6298#else
6299#define ADD_CALL_CHAIN(base, ra)
6300#define PRINT_CALL_CHAIN(base)
6301#endif
6302#ifdef GC_ADD_CALLER
6303#define OPT_RA ra,
6304#else
6305#define OPT_RA
6306#endif
6307#ifdef SHORT_DBG_HDRS
6308#define GC_has_other_debug_info(p) 1
6309#else
6310 GC_INNER int GC_has_other_debug_info(ptr_t p);
6311#endif
6312#if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
6313#if defined(SHORT_DBG_HDRS) && !defined(CPPCHECK)
6314#error Non-ptr stored in object results in GC_HAS_DEBUG_INFO malfunction
6315#endif
6316#if defined(PARALLEL_MARK) && defined(KEEP_BACK_PTRS)
6317#define GC_HAS_DEBUG_INFO(p) \
6318 ((AO_load((volatile AO_t *)(p)) & 1) != 0 \
6319 && GC_has_other_debug_info(p) > 0)
6320#else
6321#define GC_HAS_DEBUG_INFO(p) \
6322 ((*(word *)(p) & 1) && GC_has_other_debug_info(p) > 0)
6323#endif
6324#else
6325#define GC_HAS_DEBUG_INFO(p) (GC_has_other_debug_info(p) > 0)
6326#endif
6327EXTERN_C_END
6328#endif
6329#ifdef MAKE_BACK_GRAPH
6330#define MAX_IN 10
6331#if (!defined(DBG_HDRS_ALL) || (ALIGNMENT != CPP_WORDSZ/8) \
6332 ) && !defined(CPPCHECK)
6333#error The configuration does not support MAKE_BACK_GRAPH
6334#endif
6335#define FLAG_MANY 2
6336typedef struct back_edges_struct {
6337 word n_edges;
6338 unsigned short flags;
6339#define RETAIN 1
6340 unsigned short height_gc_no;
6341 signed_word height;
6342#define HEIGHT_UNKNOWN (-2)
6343#define HEIGHT_IN_PROGRESS (-1)
6344 ptr_t edges[MAX_IN];
6345 struct back_edges_struct *cont;
6346} back_edges;
6347#define MAX_BACK_EDGE_STRUCTS 100000
6348static back_edges *back_edge_space = 0;
6349STATIC int GC_n_back_edge_structs = 0;
6350static back_edges *avail_back_edges = 0;
6351static back_edges * new_back_edges(void)
6352{
6353 if (0 == back_edge_space) {
6354 size_t bytes_to_get = ROUNDUP_PAGESIZE_IF_MMAP(MAX_BACK_EDGE_STRUCTS
6355 * sizeof(back_edges));
6356 GC_ASSERT(GC_page_size != 0);
6357 back_edge_space = (back_edges *)GET_MEM(bytes_to_get);
6358 if (NULL == back_edge_space)
6359 ABORT("Insufficient memory for back edges");
6360 GC_add_to_our_memory((ptr_t)back_edge_space, bytes_to_get);
6361 }
6362 if (0 != avail_back_edges) {
6363 back_edges * result = avail_back_edges;
6364 avail_back_edges = result -> cont;
6365 result -> cont = 0;
6366 return result;
6367 }
6368 if (GC_n_back_edge_structs >= MAX_BACK_EDGE_STRUCTS - 1) {
6369 ABORT("Needed too much space for back edges: adjust "
6370 "MAX_BACK_EDGE_STRUCTS");
6371 }
6372 return back_edge_space + (GC_n_back_edge_structs++);
6373}
6374static void deallocate_back_edges(back_edges *p)
6375{
6376 back_edges *last = p;
6377 while (0 != last -> cont) last = last -> cont;
6378 last -> cont = avail_back_edges;
6379 avail_back_edges = p;
6380}
6381#define INITIAL_IN_PROGRESS 10000
6382static ptr_t * in_progress_space = 0;
6383static size_t in_progress_size = 0;
6384static size_t n_in_progress = 0;
6385static void push_in_progress(ptr_t p)
6386{
6387 if (n_in_progress >= in_progress_size) {
6388 ptr_t * new_in_progress_space;
6389 GC_ASSERT(GC_page_size != 0);
6390 if (NULL == in_progress_space) {
6391 in_progress_size = ROUNDUP_PAGESIZE_IF_MMAP(INITIAL_IN_PROGRESS
6392 * sizeof(ptr_t))
6393 / sizeof(ptr_t);
6394 new_in_progress_space =
6395 (ptr_t *)GET_MEM(in_progress_size * sizeof(ptr_t));
6396 } else {
6397 in_progress_size *= 2;
6398 new_in_progress_space = (ptr_t *)
6399 GET_MEM(in_progress_size * sizeof(ptr_t));
6400 if (new_in_progress_space != NULL)
6401 BCOPY(in_progress_space, new_in_progress_space,
6402 n_in_progress * sizeof(ptr_t));
6403 }
6404 if (EXPECT(new_in_progress_space != NULL, TRUE))
6405 GC_add_to_our_memory((ptr_t)new_in_progress_space,
6406 in_progress_size * sizeof(ptr_t));
6407#ifndef GWW_VDB
6408 GC_scratch_recycle_no_gww(in_progress_space,
6409 n_in_progress * sizeof(ptr_t));
6410#elif defined(LINT2)
6411 GC_noop1((word)in_progress_space);
6412#endif
6413 in_progress_space = new_in_progress_space;
6414 }
6415 if (in_progress_space == 0)
6416 ABORT("MAKE_BACK_GRAPH: Out of in-progress space: "
6417 "Huge linear data structure?");
6418 in_progress_space[n_in_progress++] = p;
6419}
6420static GC_bool is_in_progress(ptr_t p)
6421{
6422 size_t i;
6423 for (i = 0; i < n_in_progress; ++i) {
6424 if (in_progress_space[i] == p) return TRUE;
6425 }
6426 return FALSE;
6427}
6428GC_INLINE void pop_in_progress(ptr_t p GC_ATTR_UNUSED)
6429{
6430 --n_in_progress;
6431 GC_ASSERT(in_progress_space[n_in_progress] == p);
6432}
6433#define GET_OH_BG_PTR(p) \
6434 (ptr_t)GC_REVEAL_POINTER(((oh *)(p)) -> oh_bg_ptr)
6435#define SET_OH_BG_PTR(p,q) (((oh *)(p)) -> oh_bg_ptr = GC_HIDE_POINTER(q))
6436static void ensure_struct(ptr_t p)
6437{
6438 ptr_t old_back_ptr = GET_OH_BG_PTR(p);
6439 if (!((word)old_back_ptr & FLAG_MANY)) {
6440 back_edges *be = new_back_edges();
6441 be -> flags = 0;
6442 if (0 == old_back_ptr) {
6443 be -> n_edges = 0;
6444 } else {
6445 be -> n_edges = 1;
6446 be -> edges[0] = old_back_ptr;
6447 }
6448 be -> height = HEIGHT_UNKNOWN;
6449 be -> height_gc_no = (unsigned short)(GC_gc_no - 1);
6450 GC_ASSERT((word)be >= (word)back_edge_space);
6451 SET_OH_BG_PTR(p, (word)be | FLAG_MANY);
6452 }
6453}
6454static void add_edge(ptr_t p, ptr_t q)
6455{
6456 ptr_t pred = GET_OH_BG_PTR(q);
6457 back_edges * be, *be_cont;
6458 word i;
6459 GC_ASSERT(p == GC_base(p) && q == GC_base(q));
6460 if (!GC_HAS_DEBUG_INFO(q) || !GC_HAS_DEBUG_INFO(p)) {
6461 return;
6462 }
6463 if (NULL == pred) {
6464 static unsigned random_number = 13;
6465#define GOT_LUCKY_NUMBER (((++random_number) & 0x7f) == 0)
6466 SET_OH_BG_PTR(q, p);
6467 if (GOT_LUCKY_NUMBER) ensure_struct(q);
6468 return;
6469 }
6470 {
6471 back_edges *e = (back_edges *)((word)pred & ~FLAG_MANY);
6472 word n_edges;
6473 word total;
6474 int local = 0;
6475 if (((word)pred & FLAG_MANY) != 0) {
6476 n_edges = e -> n_edges;
6477 } else if (((word)COVERT_DATAFLOW(pred) & 1) == 0) {
6478 n_edges = 1;
6479 local = -1;
6480 } else {
6481 n_edges = 0;
6482 }
6483 for (total = 0; total < n_edges; ++total) {
6484 if (local == MAX_IN) {
6485 e = e -> cont;
6486 local = 0;
6487 }
6488 if (local >= 0)
6489 pred = e -> edges[local++];
6490 if (pred == p)
6491 return;
6492 }
6493 }
6494 ensure_struct(q);
6495 be = (back_edges *)((word)GET_OH_BG_PTR(q) & ~FLAG_MANY);
6496 for (i = be -> n_edges, be_cont = be; i > MAX_IN; i -= MAX_IN)
6497 be_cont = be_cont -> cont;
6498 if (i == MAX_IN) {
6499 be_cont -> cont = new_back_edges();
6500 be_cont = be_cont -> cont;
6501 i = 0;
6502 }
6503 be_cont -> edges[i] = p;
6504 be -> n_edges++;
6505#ifdef DEBUG_PRINT_BIG_N_EDGES
6506 if (GC_print_stats == VERBOSE && be -> n_edges == 100) {
6507 GC_err_printf("The following object has big in-degree:\n");
6508 GC_print_heap_obj(q);
6509 }
6510#endif
6511}
6512typedef void (*per_object_func)(ptr_t p, size_t n_bytes, word gc_descr);
6513static void per_object_helper(struct hblk *h, word fn)
6514{
6515 hdr * hhdr = HDR(h);
6516 size_t sz = (size_t)hhdr->hb_sz;
6517 word descr = hhdr -> hb_descr;
6518 per_object_func f = (per_object_func)fn;
6519 size_t i = 0;
6520 do {
6521 f((ptr_t)(h -> hb_body + i), sz, descr);
6522 i += sz;
6523 } while (i + sz <= BYTES_TO_WORDS(HBLKSIZE));
6524}
6525GC_INLINE void GC_apply_to_each_object(per_object_func f)
6526{
6527 GC_apply_to_all_blocks(per_object_helper, (word)f);
6528}
6529static void reset_back_edge(ptr_t p, size_t n_bytes GC_ATTR_UNUSED,
6530 word gc_descr GC_ATTR_UNUSED)
6531{
6532 if (GC_HAS_DEBUG_INFO(p)) {
6533 ptr_t old_back_ptr = GET_OH_BG_PTR(p);
6534 if ((word)old_back_ptr & FLAG_MANY) {
6535 back_edges *be = (back_edges *)((word)old_back_ptr & ~FLAG_MANY);
6536 if (!(be -> flags & RETAIN)) {
6537 deallocate_back_edges(be);
6538 SET_OH_BG_PTR(p, 0);
6539 } else {
6540 GC_ASSERT(GC_is_marked(p));
6541 be -> n_edges = 0;
6542 if (0 != be -> cont) {
6543 deallocate_back_edges(be -> cont);
6544 be -> cont = 0;
6545 }
6546 GC_ASSERT(GC_is_marked(p));
6547 be -> flags &= ~RETAIN;
6548 }
6549 } else {
6550 SET_OH_BG_PTR(p, 0);
6551 }
6552 }
6553}
6554static void add_back_edges(ptr_t p, size_t n_bytes, word gc_descr)
6555{
6556 word *currentp = (word *)(p + sizeof(oh));
6557 if((gc_descr & GC_DS_TAGS) != GC_DS_LENGTH) {
6558 gc_descr = n_bytes;
6559 }
6560 while ((word)currentp < (word)(p + gc_descr)) {
6561 word current = *currentp++;
6562 FIXUP_POINTER(current);
6563 if (current >= (word)GC_least_plausible_heap_addr &&
6564 current <= (word)GC_greatest_plausible_heap_addr) {
6565 ptr_t target = (ptr_t)GC_base((void *)current);
6566 if (0 != target) {
6567 add_edge(p, target);
6568 }
6569 }
6570 }
6571}
6572GC_INNER void GC_build_back_graph(void)
6573{
6574 GC_ASSERT(I_HOLD_LOCK());
6575 GC_apply_to_each_object(add_back_edges);
6576}
6577static word backwards_height(ptr_t p)
6578{
6579 word result;
6580 ptr_t pred = GET_OH_BG_PTR(p);
6581 back_edges *be;
6582 if (NULL == pred)
6583 return 1;
6584 if (((word)pred & FLAG_MANY) == 0) {
6585 if (is_in_progress(p)) return 0;
6586 push_in_progress(p);
6587 result = backwards_height(pred) + 1;
6588 pop_in_progress(p);
6589 return result;
6590 }
6591 be = (back_edges *)((word)pred & ~FLAG_MANY);
6592 if (be -> height >= 0 && be -> height_gc_no == (unsigned short)GC_gc_no)
6593 return be -> height;
6594 if (be -> height == HEIGHT_IN_PROGRESS) return 0;
6595 result = (be -> height > 0? be -> height : 1);
6596 be -> height = HEIGHT_IN_PROGRESS;
6597 {
6598 back_edges *e = be;
6599 word n_edges;
6600 word total;
6601 int local = 0;
6602 if (((word)pred & FLAG_MANY) != 0) {
6603 n_edges = e -> n_edges;
6604 } else if (((word)pred & 1) == 0) {
6605 n_edges = 1;
6606 local = -1;
6607 } else {
6608 n_edges = 0;
6609 }
6610 for (total = 0; total < n_edges; ++total) {
6611 word this_height;
6612 if (local == MAX_IN) {
6613 e = e -> cont;
6614 local = 0;
6615 }
6616 if (local >= 0)
6617 pred = e -> edges[local++];
6618 if (GC_is_marked(pred) && ((word)GET_OH_BG_PTR(p) & FLAG_MANY) == 0) {
6619 GC_COND_LOG_PRINTF("Found bogus pointer from %p to %p\n",
6620 (void *)pred, (void *)p);
6621 this_height = 1;
6622 } else {
6623 this_height = backwards_height(pred);
6624 }
6625 if (this_height >= result)
6626 result = this_height + 1;
6627 }
6628 }
6629 be -> height = result;
6630 be -> height_gc_no = (unsigned short)GC_gc_no;
6631 return result;
6632}
6633STATIC word GC_max_height = 0;
6634STATIC ptr_t GC_deepest_obj = NULL;
6635static void update_max_height(ptr_t p, size_t n_bytes GC_ATTR_UNUSED,
6636 word gc_descr GC_ATTR_UNUSED)
6637{
6638 if (GC_is_marked(p) && GC_HAS_DEBUG_INFO(p)) {
6639 word p_height = 0;
6640 ptr_t p_deepest_obj = 0;
6641 ptr_t back_ptr;
6642 back_edges *be = 0;
6643 back_ptr = GET_OH_BG_PTR(p);
6644 if (0 != back_ptr && ((word)back_ptr & FLAG_MANY)) {
6645 be = (back_edges *)((word)back_ptr & ~FLAG_MANY);
6646 if (be -> height != HEIGHT_UNKNOWN) p_height = be -> height;
6647 }
6648 {
6649 ptr_t pred = GET_OH_BG_PTR(p);
6650 back_edges *e = (back_edges *)((word)pred & ~FLAG_MANY);
6651 word n_edges;
6652 word total;
6653 int local = 0;
6654 if (((word)pred & FLAG_MANY) != 0) {
6655 n_edges = e -> n_edges;
6656 } else if (pred != NULL && ((word)pred & 1) == 0) {
6657 n_edges = 1;
6658 local = -1;
6659 } else {
6660 n_edges = 0;
6661 }
6662 for (total = 0; total < n_edges; ++total) {
6663 if (local == MAX_IN) {
6664 e = e -> cont;
6665 local = 0;
6666 }
6667 if (local >= 0)
6668 pred = e -> edges[local++];
6669 if (!GC_is_marked(pred) && GC_HAS_DEBUG_INFO(pred)) {
6670 word this_height = backwards_height(pred);
6671 if (this_height > p_height) {
6672 p_height = this_height;
6673 p_deepest_obj = pred;
6674 }
6675 }
6676 }
6677 }
6678 if (p_height > 0) {
6679 if (be == 0) {
6680 ensure_struct(p);
6681 back_ptr = GET_OH_BG_PTR(p);
6682 be = (back_edges *)((word)back_ptr & ~FLAG_MANY);
6683 }
6684 be -> flags |= RETAIN;
6685 be -> height = p_height;
6686 be -> height_gc_no = (unsigned short)GC_gc_no;
6687 }
6688 if (p_height > GC_max_height) {
6689 GC_max_height = p_height;
6690 GC_deepest_obj = p_deepest_obj;
6691 }
6692 }
6693}
6694STATIC word GC_max_max_height = 0;
6695GC_INNER void GC_traverse_back_graph(void)
6696{
6697 GC_ASSERT(I_HOLD_LOCK());
6698 GC_max_height = 0;
6699 GC_apply_to_each_object(update_max_height);
6700 if (0 != GC_deepest_obj)
6701 GC_set_mark_bit(GC_deepest_obj);
6702}
6703void GC_print_back_graph_stats(void)
6704{
6705 GC_ASSERT(I_HOLD_LOCK());
6706 GC_printf("Maximum backwards height of reachable objects"
6707 " at GC #%lu is %lu\n",
6708 (unsigned long)GC_gc_no, (unsigned long)GC_max_height);
6709 if (GC_max_height > GC_max_max_height) {
6710 ptr_t obj = GC_deepest_obj;
6711 GC_max_max_height = GC_max_height;
6712 UNLOCK();
6713 GC_err_printf(
6714 "The following unreachable object is last in a longest chain "
6715 "of unreachable objects:\n");
6716 GC_print_heap_obj(obj);
6717 LOCK();
6718 }
6719 GC_COND_LOG_PRINTF("Needed max total of %d back-edge structs\n",
6720 GC_n_back_edge_structs);
6721 GC_apply_to_each_object(reset_back_edge);
6722 GC_deepest_obj = 0;
6723}
6724#endif
6725STATIC word * GC_old_normal_bl = NULL;
6726STATIC word * GC_incomplete_normal_bl = NULL;
6727STATIC word * GC_old_stack_bl = NULL;
6728STATIC word * GC_incomplete_stack_bl = NULL;
6729STATIC word GC_total_stack_black_listed = 0;
6730GC_INNER word GC_black_list_spacing = MINHINCR * HBLKSIZE;
6731STATIC void GC_clear_bl(word *);
6732GC_INNER void GC_default_print_heap_obj_proc(ptr_t p)
6733{
6734 ptr_t base = (ptr_t)GC_base(p);
6735 int kind = HDR(base)->hb_obj_kind;
6736 GC_err_printf("object at %p of appr. %lu bytes (%s)\n",
6737 (void *)base, (unsigned long)GC_size(base),
6738 kind == PTRFREE ? "atomic" :
6739 IS_UNCOLLECTABLE(kind) ? "uncollectable" : "composite");
6740}
6741GC_INNER void (*GC_print_heap_obj)(ptr_t p) = GC_default_print_heap_obj_proc;
6742#ifdef PRINT_BLACK_LIST
6743 STATIC void GC_print_blacklisted_ptr(word p, ptr_t source,
6744 const char *kind_str)
6745 {
6746 ptr_t base = (ptr_t)GC_base(source);
6747 if (0 == base) {
6748 GC_err_printf("Black listing (%s) %p referenced from %p in %s\n",
6749 kind_str, (void *)p, (void *)source,
6750 NULL != source ? "root set" : "register");
6751 } else {
6752 GC_err_printf("Black listing (%s) %p referenced from %p in"
6753 " object at %p of appr. %lu bytes\n",
6754 kind_str, (void *)p, (void *)source,
6755 (void *)base, (unsigned long)GC_size(base));
6756 }
6757 }
6758#endif
6759GC_INNER void GC_bl_init_no_interiors(void)
6760{
6761 if (GC_incomplete_normal_bl == 0) {
6762 GC_old_normal_bl = (word *)GC_scratch_alloc(sizeof(page_hash_table));
6763 GC_incomplete_normal_bl = (word *)GC_scratch_alloc(
6764 sizeof(page_hash_table));
6765 if (GC_old_normal_bl == 0 || GC_incomplete_normal_bl == 0) {
6766 GC_err_printf("Insufficient memory for black list\n");
6767 EXIT();
6768 }
6769 GC_clear_bl(GC_old_normal_bl);
6770 GC_clear_bl(GC_incomplete_normal_bl);
6771 }
6772}
6773GC_INNER void GC_bl_init(void)
6774{
6775 if (!GC_all_interior_pointers) {
6776 GC_bl_init_no_interiors();
6777 }
6778 GC_ASSERT(NULL == GC_old_stack_bl && NULL == GC_incomplete_stack_bl);
6779 GC_old_stack_bl = (word *)GC_scratch_alloc(sizeof(page_hash_table));
6780 GC_incomplete_stack_bl = (word *)GC_scratch_alloc(sizeof(page_hash_table));
6781 if (GC_old_stack_bl == 0 || GC_incomplete_stack_bl == 0) {
6782 GC_err_printf("Insufficient memory for black list\n");
6783 EXIT();
6784 }
6785 GC_clear_bl(GC_old_stack_bl);
6786 GC_clear_bl(GC_incomplete_stack_bl);
6787}
6788STATIC void GC_clear_bl(word *doomed)
6789{
6790 BZERO(doomed, sizeof(page_hash_table));
6791}
6792STATIC void GC_copy_bl(word *old, word *dest)
6793{
6794 BCOPY(old, dest, sizeof(page_hash_table));
6795}
6796static word total_stack_black_listed(void);
6797GC_INNER void GC_promote_black_lists(void)
6798{
6799 word * very_old_normal_bl = GC_old_normal_bl;
6800 word * very_old_stack_bl = GC_old_stack_bl;
6801 GC_old_normal_bl = GC_incomplete_normal_bl;
6802 GC_old_stack_bl = GC_incomplete_stack_bl;
6803 if (!GC_all_interior_pointers) {
6804 GC_clear_bl(very_old_normal_bl);
6805 }
6806 GC_clear_bl(very_old_stack_bl);
6807 GC_incomplete_normal_bl = very_old_normal_bl;
6808 GC_incomplete_stack_bl = very_old_stack_bl;
6809 GC_total_stack_black_listed = total_stack_black_listed();
6810 GC_VERBOSE_LOG_PRINTF(
6811 "%lu bytes in heap blacklisted for interior pointers\n",
6812 (unsigned long)GC_total_stack_black_listed);
6813 if (GC_total_stack_black_listed != 0) {
6814 GC_black_list_spacing =
6815 HBLKSIZE*(GC_heapsize/GC_total_stack_black_listed);
6816 }
6817 if (GC_black_list_spacing < 3 * HBLKSIZE) {
6818 GC_black_list_spacing = 3 * HBLKSIZE;
6819 }
6820 if (GC_black_list_spacing > MAXHINCR * HBLKSIZE) {
6821 GC_black_list_spacing = MAXHINCR * HBLKSIZE;
6822 }
6823}
6824GC_INNER void GC_unpromote_black_lists(void)
6825{
6826 if (!GC_all_interior_pointers) {
6827 GC_copy_bl(GC_old_normal_bl, GC_incomplete_normal_bl);
6828 }
6829 GC_copy_bl(GC_old_stack_bl, GC_incomplete_stack_bl);
6830}
6831#if defined(PARALLEL_MARK) && defined(THREAD_SANITIZER)
6832#define backlist_set_pht_entry_from_index(db, index) \
6833 set_pht_entry_from_index_concurrent(db, index)
6834#else
6835#define backlist_set_pht_entry_from_index(bl, index) \
6836 set_pht_entry_from_index(bl, index)
6837#endif
6838#ifdef PRINT_BLACK_LIST
6839 GC_INNER void GC_add_to_black_list_normal(word p, ptr_t source)
6840#else
6841 GC_INNER void GC_add_to_black_list_normal(word p)
6842#endif
6843{
6844 if (GC_modws_valid_offsets[p & (sizeof(word)-1)]) {
6845 word index = PHT_HASH((word)p);
6846 if (HDR(p) == 0 || get_pht_entry_from_index(GC_old_normal_bl, index)) {
6847#ifdef PRINT_BLACK_LIST
6848 if (!get_pht_entry_from_index(GC_incomplete_normal_bl, index)) {
6849 GC_print_blacklisted_ptr(p, source, "normal");
6850 }
6851#endif
6852 backlist_set_pht_entry_from_index(GC_incomplete_normal_bl, index);
6853 }
6854 }
6855}
6856#ifdef PRINT_BLACK_LIST
6857 GC_INNER void GC_add_to_black_list_stack(word p, ptr_t source)
6858#else
6859 GC_INNER void GC_add_to_black_list_stack(word p)
6860#endif
6861{
6862 word index = PHT_HASH((word)p);
6863 if (HDR(p) == 0 || get_pht_entry_from_index(GC_old_stack_bl, index)) {
6864#ifdef PRINT_BLACK_LIST
6865 if (!get_pht_entry_from_index(GC_incomplete_stack_bl, index)) {
6866 GC_print_blacklisted_ptr(p, source, "stack");
6867 }
6868#endif
6869 backlist_set_pht_entry_from_index(GC_incomplete_stack_bl, index);
6870 }
6871}
6872struct hblk * GC_is_black_listed(struct hblk *h, word len)
6873{
6874 word index = PHT_HASH((word)h);
6875 word i;
6876 word nblocks;
6877 if (!GC_all_interior_pointers
6878 && (get_pht_entry_from_index(GC_old_normal_bl, index)
6879 || get_pht_entry_from_index(GC_incomplete_normal_bl, index))) {
6880 return (h+1);
6881 }
6882 nblocks = divHBLKSZ(len);
6883 for (i = 0;;) {
6884 if (GC_old_stack_bl[divWORDSZ(index)] == 0
6885 && GC_incomplete_stack_bl[divWORDSZ(index)] == 0) {
6886 i += WORDSZ - modWORDSZ(index);
6887 } else {
6888 if (get_pht_entry_from_index(GC_old_stack_bl, index)
6889 || get_pht_entry_from_index(GC_incomplete_stack_bl, index)) {
6890 return(h+i+1);
6891 }
6892 i++;
6893 }
6894 if (i >= nblocks) break;
6895 index = PHT_HASH((word)(h+i));
6896 }
6897 return(0);
6898}
6899STATIC word GC_number_stack_black_listed(struct hblk *start,
6900 struct hblk *endp1)
6901{
6902 struct hblk * h;
6903 word result = 0;
6904 for (h = start; (word)h < (word)endp1; h++) {
6905 word index = PHT_HASH((word)h);
6906 if (get_pht_entry_from_index(GC_old_stack_bl, index)) result++;
6907 }
6908 return(result);
6909}
6910static word total_stack_black_listed(void)
6911{
6912 unsigned i;
6913 word total = 0;
6914 for (i = 0; i < GC_n_heap_sects; i++) {
6915 struct hblk * start = (struct hblk *) GC_heap_sects[i].hs_start;
6916 struct hblk * endp1 = start + divHBLKSZ(GC_heap_sects[i].hs_bytes);
6917 total += GC_number_stack_black_listed(start, endp1);
6918 }
6919 return(total * HBLKSIZE);
6920}
6921#ifdef CHECKSUMS
6922#define NSUMS 10000
6923#define OFFSET 0x10000
6924typedef struct {
6925 GC_bool new_valid;
6926 word old_sum;
6927 word new_sum;
6928 struct hblk * block;
6929} page_entry;
6930page_entry GC_sums[NSUMS];
6931STATIC word GC_faulted[NSUMS] = { 0 };
6932STATIC size_t GC_n_faulted = 0;
6933#if defined(MPROTECT_VDB) && !defined(DARWIN)
6934 void GC_record_fault(struct hblk * h)
6935 {
6936 word page = (word)h & ~(GC_page_size - 1);
6937 GC_ASSERT(GC_page_size != 0);
6938 if (GC_n_faulted >= NSUMS) ABORT("write fault log overflowed");
6939 GC_faulted[GC_n_faulted++] = page;
6940 }
6941#endif
6942STATIC GC_bool GC_was_faulted(struct hblk *h)
6943{
6944 size_t i;
6945 word page = (word)h & ~(GC_page_size - 1);
6946 for (i = 0; i < GC_n_faulted; ++i) {
6947 if (GC_faulted[i] == page) return TRUE;
6948 }
6949 return FALSE;
6950}
6951STATIC word GC_checksum(struct hblk *h)
6952{
6953 word *p = (word *)h;
6954 word *lim = (word *)(h+1);
6955 word result = 0;
6956 while ((word)p < (word)lim) {
6957 result += *p++;
6958 }
6959 return(result | 0x80000000 );
6960}
6961int GC_n_dirty_errors = 0;
6962int GC_n_faulted_dirty_errors = 0;
6963unsigned long GC_n_clean = 0;
6964unsigned long GC_n_dirty = 0;
6965STATIC void GC_update_check_page(struct hblk *h, int index)
6966{
6967 page_entry *pe = GC_sums + index;
6968 hdr * hhdr = HDR(h);
6969 struct hblk *b;
6970 if (pe -> block != 0 && pe -> block != h + OFFSET) ABORT("goofed");
6971 pe -> old_sum = pe -> new_sum;
6972 pe -> new_sum = GC_checksum(h);
6973#if !defined(MSWIN32) && !defined(MSWINCE)
6974 if (pe -> new_sum != 0x80000000 && !GC_page_was_ever_dirty(h)) {
6975 GC_err_printf("GC_page_was_ever_dirty(%p) is wrong\n", (void *)h);
6976 }
6977#endif
6978 if (GC_page_was_dirty(h)) {
6979 GC_n_dirty++;
6980 } else {
6981 GC_n_clean++;
6982 }
6983 b = h;
6984 while (IS_FORWARDING_ADDR_OR_NIL(hhdr) && hhdr != 0) {
6985 b -= (word)hhdr;
6986 hhdr = HDR(b);
6987 }
6988 if (pe -> new_valid
6989 && hhdr != 0 && hhdr -> hb_descr != 0
6990 && pe -> old_sum != pe -> new_sum) {
6991 if (!GC_page_was_dirty(h) || !GC_page_was_ever_dirty(h)) {
6992 GC_bool was_faulted = GC_was_faulted(h);
6993 GC_n_dirty_errors++;
6994 if (was_faulted) GC_n_faulted_dirty_errors++;
6995 }
6996 }
6997 pe -> new_valid = TRUE;
6998 pe -> block = h + OFFSET;
6999}
7000word GC_bytes_in_used_blocks = 0;
7001STATIC void GC_add_block(struct hblk *h, word dummy GC_ATTR_UNUSED)
7002{
7003 hdr * hhdr = HDR(h);
7004 GC_bytes_in_used_blocks += (hhdr->hb_sz + HBLKSIZE-1) & ~(HBLKSIZE-1);
7005}
7006STATIC void GC_check_blocks(void)
7007{
7008 word bytes_in_free_blocks = GC_large_free_bytes;
7009 GC_bytes_in_used_blocks = 0;
7010 GC_apply_to_all_blocks(GC_add_block, (word)0);
7011 GC_COND_LOG_PRINTF("GC_bytes_in_used_blocks= %lu,"
7012 " bytes_in_free_blocks= %lu, heapsize= %lu\n",
7013 (unsigned long)GC_bytes_in_used_blocks,
7014 (unsigned long)bytes_in_free_blocks,
7015 (unsigned long)GC_heapsize);
7016 if (GC_bytes_in_used_blocks + bytes_in_free_blocks != GC_heapsize) {
7017 GC_err_printf("LOST SOME BLOCKS!!\n");
7018 }
7019}
7020void GC_check_dirty(void)
7021{
7022 int index;
7023 unsigned i;
7024 struct hblk *h;
7025 ptr_t start;
7026 GC_check_blocks();
7027 GC_n_dirty_errors = 0;
7028 GC_n_faulted_dirty_errors = 0;
7029 GC_n_clean = 0;
7030 GC_n_dirty = 0;
7031 index = 0;
7032 for (i = 0; i < GC_n_heap_sects; i++) {
7033 start = GC_heap_sects[i].hs_start;
7034 for (h = (struct hblk *)start;
7035 (word)h < (word)(start + GC_heap_sects[i].hs_bytes); h++) {
7036 GC_update_check_page(h, index);
7037 index++;
7038 if (index >= NSUMS) goto out;
7039 }
7040 }
7041out:
7042 GC_COND_LOG_PRINTF("Checked %lu clean and %lu dirty pages\n",
7043 GC_n_clean, GC_n_dirty);
7044 if (GC_n_dirty_errors > 0) {
7045 GC_err_printf("Found %d dirty bit errors (%d were faulted)\n",
7046 GC_n_dirty_errors, GC_n_faulted_dirty_errors);
7047 }
7048 for (i = 0; i < GC_n_faulted; ++i) {
7049 GC_faulted[i] = 0;
7050 }
7051 GC_n_faulted = 0;
7052}
7053#endif
7054#ifndef GC_PMARK_H
7055#define GC_PMARK_H
7056#if defined(HAVE_CONFIG_H) && !defined(GC_PRIVATE_H)
7057#endif
7058#ifndef GC_BUILD
7059#define GC_BUILD
7060#endif
7061#if (defined(__linux__) || defined(__GLIBC__) || defined(__GNU__)) \
7062 && !defined(_GNU_SOURCE) && defined(GC_PTHREADS) \
7063 && !defined(GC_NO_PTHREAD_SIGMASK)
7064#define _GNU_SOURCE 1
7065#endif
7066#if defined(KEEP_BACK_PTRS) || defined(PRINT_BLACK_LIST)
7067#endif
7068EXTERN_C_BEGIN
7069#ifndef MARK_DESCR_OFFSET
7070#define MARK_DESCR_OFFSET sizeof(word)
7071#endif
7072#define BITMAP_BITS (WORDSZ - GC_DS_TAG_BITS)
7073#define PROC(descr) \
7074 (GC_mark_procs[((descr) >> GC_DS_TAG_BITS) & (GC_MAX_MARK_PROCS-1)])
7075#define ENV(descr) \
7076 ((descr) >> (GC_DS_TAG_BITS + GC_LOG_MAX_MARK_PROCS))
7077#define MAX_ENV \
7078 (((word)1 << (WORDSZ - GC_DS_TAG_BITS - GC_LOG_MAX_MARK_PROCS)) - 1)
7079GC_EXTERN unsigned GC_n_mark_procs;
7080#define GC_MARK_STACK_DISCARDS (INITIAL_MARK_STACK_SIZE/8)
7081#ifdef PARALLEL_MARK
7082#endif
7083GC_INNER mse * GC_signal_mark_stack_overflow(mse *msp);
7084GC_INLINE mse * GC_push_obj(ptr_t obj, hdr * hhdr, mse * mark_stack_top,
7085 mse * mark_stack_limit)
7086{
7087 word descr = hhdr -> hb_descr;
7088 GC_ASSERT(!HBLK_IS_FREE(hhdr));
7089 if (descr != 0) {
7090 mark_stack_top++;
7091 if ((word)mark_stack_top >= (word)mark_stack_limit) {
7092 mark_stack_top = GC_signal_mark_stack_overflow(mark_stack_top);
7093 }
7094 mark_stack_top -> mse_start = obj;
7095 mark_stack_top -> mse_descr.w = descr;
7096 }
7097 return mark_stack_top;
7098}
7099#define PUSH_CONTENTS(current, mark_stack_top, mark_stack_limit, source) \
7100 do { \
7101 hdr * my_hhdr; \
7102 HC_GET_HDR(current, my_hhdr, source); \
7103 mark_stack_top = GC_push_contents_hdr(current, mark_stack_top, \
7104 mark_stack_limit, \
7105 source, my_hhdr, TRUE); \
7106 } while (0)
7107#ifdef USE_MARK_BYTES
7108#if defined(PARALLEL_MARK) && defined(AO_HAVE_char_store) \
7109 && !defined(BASE_ATOMIC_OPS_EMULATED)
7110#define SET_MARK_BIT_EXIT_IF_SET(hhdr, bit_no) \
7111 { \
7112 volatile unsigned char * mark_byte_addr = \
7113 (unsigned char *)(hhdr)->hb_marks + (bit_no); \
7114 \
7115 if (AO_char_load(mark_byte_addr) != 0) \
7116 break; \
7117 AO_char_store(mark_byte_addr, 1); \
7118 }
7119#else
7120#define SET_MARK_BIT_EXIT_IF_SET(hhdr, bit_no) \
7121 { \
7122 char * mark_byte_addr = (char *)(hhdr)->hb_marks + (bit_no); \
7123 if (*mark_byte_addr != 0) break; \
7124 *mark_byte_addr = 1; \
7125 }
7126#endif
7127#else
7128#ifdef PARALLEL_MARK
7129#ifdef THREAD_SANITIZER
7130#define OR_WORD_EXIT_IF_SET(addr, bits) \
7131 { \
7132 if (!((word)AO_load((volatile AO_t *)(addr)) & (bits))) { \
7133 \
7134 AO_or((volatile AO_t *)(addr), (AO_t)(bits)); \
7135 } else { \
7136 break; \
7137 } \
7138 }
7139#else
7140#define OR_WORD_EXIT_IF_SET(addr, bits) \
7141 { \
7142 if (!(*(addr) & (bits))) { \
7143 AO_or((volatile AO_t *)(addr), (AO_t)(bits)); \
7144 } else { \
7145 break; \
7146 } \
7147 }
7148#endif
7149#else
7150#define OR_WORD_EXIT_IF_SET(addr, bits) \
7151 { \
7152 word old = *(addr); \
7153 word my_bits = (bits); \
7154 if ((old & my_bits) != 0) \
7155 break; \
7156 *(addr) = old | my_bits; \
7157 }
7158#endif
7159#define SET_MARK_BIT_EXIT_IF_SET(hhdr, bit_no) \
7160 { \
7161 word * mark_word_addr = (hhdr)->hb_marks + divWORDSZ(bit_no); \
7162 OR_WORD_EXIT_IF_SET(mark_word_addr, \
7163 (word)1 << modWORDSZ(bit_no)); \
7164 }
7165#endif
7166#ifdef PARALLEL_MARK
7167#define INCR_MARKS(hhdr) \
7168 AO_store(&hhdr->hb_n_marks, AO_load(&hhdr->hb_n_marks) + 1)
7169#else
7170#define INCR_MARKS(hhdr) (void)(++hhdr->hb_n_marks)
7171#endif
7172#ifdef ENABLE_TRACE
7173#define TRACE(source, cmd) \
7174 if (GC_trace_addr != 0 && (ptr_t)(source) == GC_trace_addr) cmd
7175#define TRACE_TARGET(target, cmd) \
7176 if (GC_trace_addr != 0 && (target) == *(ptr_t *)GC_trace_addr) cmd
7177#else
7178#define TRACE(source, cmd)
7179#define TRACE_TARGET(source, cmd)
7180#endif
7181#if defined(I386) && defined(__GNUC__) && !defined(NACL)
7182#define LONG_MULT(hprod, lprod, x, y) \
7183 do { \
7184 __asm__ __volatile__("mull %2" : "=a"(lprod), "=d"(hprod) \
7185 : "g"(y), "0"(x)); \
7186 } while (0)
7187#else
7188#if defined(__int64) && !defined(__GNUC__) && !defined(CPPCHECK)
7189#define ULONG_MULT_T unsigned __int64
7190#else
7191#define ULONG_MULT_T unsigned long long
7192#endif
7193#define LONG_MULT(hprod, lprod, x, y) \
7194 do { \
7195 ULONG_MULT_T prod = (ULONG_MULT_T)(x) * (ULONG_MULT_T)(y); \
7196 GC_STATIC_ASSERT(sizeof(x) + sizeof(y) <= sizeof(prod)); \
7197 hprod = prod >> 32; \
7198 lprod = (unsigned32)prod; \
7199 } while (0)
7200#endif
7201GC_INLINE mse * GC_push_contents_hdr(ptr_t current, mse * mark_stack_top,
7202 mse * mark_stack_limit, ptr_t source,
7203 hdr * hhdr, GC_bool do_offset_check)
7204{
7205 do {
7206 size_t displ = HBLKDISPL(current);
7207 ptr_t base = current;
7208#ifdef MARK_BIT_PER_GRANULE
7209 size_t gran_displ = BYTES_TO_GRANULES(displ);
7210 size_t gran_offset = hhdr -> hb_map[gran_displ];
7211 size_t byte_offset = displ & (GRANULE_BYTES - 1);
7212 if (EXPECT((gran_offset | byte_offset) != 0, FALSE))
7213#else
7214 unsigned32 gran_displ;
7215 unsigned32 inv_sz = hhdr -> hb_inv_sz;
7216#endif
7217 {
7218#ifdef MARK_BIT_PER_GRANULE
7219 if ((hhdr -> hb_flags & LARGE_BLOCK) != 0)
7220#else
7221 if (EXPECT(inv_sz == LARGE_INV_SZ, FALSE))
7222#endif
7223 {
7224 size_t obj_displ;
7225 base = (ptr_t)hhdr->hb_block;
7226 obj_displ = current - base;
7227 if (obj_displ != displ) {
7228 GC_ASSERT(obj_displ < hhdr -> hb_sz);
7229 } else if (do_offset_check && !GC_valid_offsets[obj_displ]) {
7230 GC_ADD_TO_BLACK_LIST_NORMAL(current, source);
7231 break;
7232 }
7233 GC_ASSERT(hhdr -> hb_sz > HBLKSIZE
7234 || hhdr -> hb_block == HBLKPTR(current));
7235 GC_ASSERT((word)hhdr->hb_block <= (word)current);
7236 gran_displ = 0;
7237 } else {
7238#ifdef MARK_BIT_PER_GRANULE
7239 size_t obj_displ = GRANULES_TO_BYTES(gran_offset) + byte_offset;
7240#else
7241 unsigned32 low_prod;
7242 LONG_MULT(gran_displ, low_prod, (unsigned32)displ, inv_sz);
7243 if ((low_prod >> 16) != 0)
7244#endif
7245 {
7246#if defined(MARK_BIT_PER_OBJ) \
7247 && !defined(MARK_BIT_PER_GRANULE)
7248 size_t obj_displ;
7249 GC_STATIC_ASSERT(HBLKSIZE <= (1 << 15));
7250 obj_displ = (((low_prod >> 16) + 1) * (size_t)hhdr->hb_sz) >> 16;
7251#endif
7252 if (do_offset_check && !GC_valid_offsets[obj_displ]) {
7253 GC_ADD_TO_BLACK_LIST_NORMAL(current, source);
7254 break;
7255 }
7256#ifdef MARK_BIT_PER_GRANULE
7257 gran_displ -= gran_offset;
7258#endif
7259 base -= obj_displ;
7260 }
7261 }
7262 }
7263#ifdef MARK_BIT_PER_GRANULE
7264 GC_ASSERT(hhdr == GC_find_header(base));
7265 GC_ASSERT(gran_displ % BYTES_TO_GRANULES(hhdr -> hb_sz) == 0);
7266#else
7267 GC_ASSERT(gran_displ <= HBLK_OBJS(hhdr -> hb_sz));
7268#endif
7269 TRACE(source, GC_log_printf("GC #%lu: passed validity tests\n",
7270 (unsigned long)GC_gc_no));
7271 SET_MARK_BIT_EXIT_IF_SET(hhdr, gran_displ);
7272 TRACE(source, GC_log_printf("GC #%lu: previously unmarked\n",
7273 (unsigned long)GC_gc_no));
7274 TRACE_TARGET(base, GC_log_printf("GC #%lu: marking %p from %p instead\n",
7275 (unsigned long)GC_gc_no, (void *)base,
7276 (void *)source));
7277 INCR_MARKS(hhdr);
7278 GC_STORE_BACK_PTR(source, base);
7279 mark_stack_top = GC_push_obj(base, hhdr, mark_stack_top,
7280 mark_stack_limit);
7281 } while (0);
7282 return mark_stack_top;
7283}
7284#if defined(PRINT_BLACK_LIST) || defined(KEEP_BACK_PTRS)
7285#define PUSH_ONE_CHECKED_STACK(p, source) \
7286 GC_mark_and_push_stack((ptr_t)(p), (ptr_t)(source))
7287#else
7288#define PUSH_ONE_CHECKED_STACK(p, source) \
7289 GC_mark_and_push_stack((ptr_t)(p))
7290#endif
7291#ifdef NEED_FIXUP_POINTER
7292#define GC_PUSH_ONE_STACK(p, source) \
7293 do { \
7294 if ((word)(p) >= (word)GC_least_plausible_heap_addr \
7295 && (word)(p) < (word)GC_greatest_plausible_heap_addr) { \
7296 PUSH_ONE_CHECKED_STACK(p, source); \
7297 } \
7298 FIXUP_POINTER(p); \
7299 if ((word)(p) >= (word)GC_least_plausible_heap_addr \
7300 && (word)(p) < (word)GC_greatest_plausible_heap_addr) { \
7301 PUSH_ONE_CHECKED_STACK(p, source); \
7302 } \
7303 } while (0)
7304#else
7305#define GC_PUSH_ONE_STACK(p, source) \
7306 do { \
7307 if ((word)(p) >= (word)GC_least_plausible_heap_addr \
7308 && (word)(p) < (word)GC_greatest_plausible_heap_addr) { \
7309 PUSH_ONE_CHECKED_STACK(p, source); \
7310 } \
7311 } while (0)
7312#endif
7313#define GC_PUSH_ONE_HEAP(p,source,mark_stack_top) \
7314 do { \
7315 FIXUP_POINTER(p); \
7316 if ((word)(p) >= (word)GC_least_plausible_heap_addr \
7317 && (word)(p) < (word)GC_greatest_plausible_heap_addr) \
7318 mark_stack_top = GC_mark_and_push((void *)(p), mark_stack_top, \
7319 GC_mark_stack_limit, (void * *)(source)); \
7320 } while (0)
7321GC_INNER mse * GC_mark_from(mse * top, mse * bottom, mse *limit);
7322#define MARK_FROM_MARK_STACK() \
7323 GC_mark_stack_top = GC_mark_from(GC_mark_stack_top, \
7324 GC_mark_stack, \
7325 GC_mark_stack + GC_mark_stack_size);
7326#define GC_mark_stack_empty() ((word)GC_mark_stack_top < (word)GC_mark_stack)
7327#define GC_MARK_FO(real_ptr, mark_proc) \
7328 do { \
7329 (*(mark_proc))(real_ptr); \
7330 while (!GC_mark_stack_empty()) MARK_FROM_MARK_STACK(); \
7331 if (GC_mark_state != MS_NONE) { \
7332 GC_set_mark_bit(real_ptr); \
7333 while (!GC_mark_some((ptr_t)0)) { } \
7334 } \
7335 } while (0)
7336#define MS_NONE 0
7337#define MS_PUSH_RESCUERS 1
7338#define MS_PUSH_UNCOLLECTABLE 2
7339#define MS_ROOTS_PUSHED 3
7340#define MS_PARTIALLY_INVALID 4
7341#define MS_INVALID 5
7342EXTERN_C_END
7343#endif
7344#ifdef GC_GCJ_SUPPORT
7345#ifndef GC_GCJ_H
7346#define GC_GCJ_H
7347#ifndef GC_H
7348#endif
7349#ifdef __cplusplus
7350 extern "C" {
7351#endif
7352GC_API void GC_CALL GC_init_gcj_malloc(int ,
7353 void * );
7354GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
7355 GC_gcj_malloc(size_t ,
7356 void * );
7357GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
7358 GC_debug_gcj_malloc(size_t ,
7359 void * ,
7360 GC_EXTRA_PARAMS);
7361GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
7362 GC_gcj_malloc_ignore_off_page(size_t ,
7363 void * );
7364GC_API int GC_gcj_kind;
7365GC_API int GC_gcj_debug_kind;
7366#ifdef GC_DEBUG
7367#define GC_GCJ_MALLOC(s,d) GC_debug_gcj_malloc(s,d,GC_EXTRAS)
7368#define GC_GCJ_MALLOC_IGNORE_OFF_PAGE(s,d) GC_debug_gcj_malloc(s,d,GC_EXTRAS)
7369#else
7370#define GC_GCJ_MALLOC(s,d) GC_gcj_malloc(s,d)
7371#define GC_GCJ_MALLOC_IGNORE_OFF_PAGE(s,d) GC_gcj_malloc_ignore_off_page(s,d)
7372#endif
7373#ifdef __cplusplus
7374 }
7375#endif
7376#endif
7377int GC_gcj_kind = 0;
7378int GC_gcj_debug_kind = 0;
7379STATIC struct GC_ms_entry * GC_gcj_fake_mark_proc(word * addr GC_ATTR_UNUSED,
7380 struct GC_ms_entry *mark_stack_ptr,
7381 struct GC_ms_entry * mark_stack_limit GC_ATTR_UNUSED,
7382 word env GC_ATTR_UNUSED)
7383{
7384 ABORT_RET("No client gcj mark proc is specified");
7385 return mark_stack_ptr;
7386}
7387GC_API void GC_CALL GC_init_gcj_malloc(int mp_index,
7388 void * mp)
7389{
7390#ifndef GC_IGNORE_GCJ_INFO
7391 GC_bool ignore_gcj_info;
7392#endif
7393 DCL_LOCK_STATE;
7394 if (mp == 0)
7395 mp = (void *)(word)GC_gcj_fake_mark_proc;
7396 GC_init();
7397 LOCK();
7398 if (GC_gcjobjfreelist != NULL) {
7399 UNLOCK();
7400 return;
7401 }
7402#ifdef GC_IGNORE_GCJ_INFO
7403#define ignore_gcj_info TRUE
7404#else
7405 ignore_gcj_info = (0 != GETENV("GC_IGNORE_GCJ_INFO"));
7406#endif
7407 if (ignore_gcj_info) {
7408 GC_COND_LOG_PRINTF("Gcj-style type information is disabled!\n");
7409 }
7410 GC_ASSERT(GC_mark_procs[mp_index] == (GC_mark_proc)0);
7411 GC_mark_procs[mp_index] = (GC_mark_proc)(word)mp;
7412 if ((unsigned)mp_index >= GC_n_mark_procs)
7413 ABORT("GC_init_gcj_malloc: bad index");
7414 GC_gcjobjfreelist = (ptr_t *)GC_new_free_list_inner();
7415 if (ignore_gcj_info) {
7416 GC_gcj_kind = GC_new_kind_inner((void **)GC_gcjobjfreelist,
7417 GC_DS_LENGTH,
7418 TRUE, TRUE);
7419 GC_gcj_debug_kind = GC_gcj_kind;
7420 } else {
7421 GC_gcj_kind = GC_new_kind_inner(
7422 (void **)GC_gcjobjfreelist,
7423 (((word)(-(signed_word)MARK_DESCR_OFFSET
7424 - GC_INDIR_PER_OBJ_BIAS))
7425 | GC_DS_PER_OBJECT),
7426 FALSE, TRUE);
7427 GC_gcj_debug_kind = GC_new_kind_inner(GC_new_free_list_inner(),
7428 GC_MAKE_PROC(mp_index,
7429 1 ),
7430 FALSE, TRUE);
7431 }
7432 UNLOCK();
7433#undef ignore_gcj_info
7434}
7435#define GENERAL_MALLOC_INNER(lb,k) \
7436 GC_clear_stack(GC_generic_malloc_inner(lb, k))
7437#define GENERAL_MALLOC_INNER_IOP(lb,k) \
7438 GC_clear_stack(GC_generic_malloc_inner_ignore_off_page(lb, k))
7439static void maybe_finalize(void)
7440{
7441 static word last_finalized_no = 0;
7442 DCL_LOCK_STATE;
7443 if (GC_gc_no == last_finalized_no ||
7444 !EXPECT(GC_is_initialized, TRUE)) return;
7445 UNLOCK();
7446 GC_INVOKE_FINALIZERS();
7447 LOCK();
7448 last_finalized_no = GC_gc_no;
7449}
7450#ifdef THREAD_LOCAL_ALLOC
7451 GC_INNER void * GC_core_gcj_malloc(size_t lb,
7452 void * ptr_to_struct_containing_descr)
7453#else
7454 GC_API GC_ATTR_MALLOC void * GC_CALL GC_gcj_malloc(size_t lb,
7455 void * ptr_to_struct_containing_descr)
7456#endif
7457{
7458 ptr_t op;
7459 DCL_LOCK_STATE;
7460 GC_DBG_COLLECT_AT_MALLOC(lb);
7461 if(SMALL_OBJ(lb)) {
7462 word lg;
7463 LOCK();
7464 lg = GC_size_map[lb];
7465 op = GC_gcjobjfreelist[lg];
7466 if(EXPECT(0 == op, FALSE)) {
7467 maybe_finalize();
7468 op = (ptr_t)GENERAL_MALLOC_INNER((word)lb, GC_gcj_kind);
7469 if (0 == op) {
7470 GC_oom_func oom_fn = GC_oom_fn;
7471 UNLOCK();
7472 return((*oom_fn)(lb));
7473 }
7474 } else {
7475 GC_gcjobjfreelist[lg] = (ptr_t)obj_link(op);
7476 GC_bytes_allocd += GRANULES_TO_BYTES((word)lg);
7477 }
7478 GC_ASSERT(((void **)op)[1] == 0);
7479 } else {
7480 LOCK();
7481 maybe_finalize();
7482 op = (ptr_t)GENERAL_MALLOC_INNER((word)lb, GC_gcj_kind);
7483 if (0 == op) {
7484 GC_oom_func oom_fn = GC_oom_fn;
7485 UNLOCK();
7486 return((*oom_fn)(lb));
7487 }
7488 }
7489 *(void **)op = ptr_to_struct_containing_descr;
7490 UNLOCK();
7491 GC_dirty(op);
7492 REACHABLE_AFTER_DIRTY(ptr_to_struct_containing_descr);
7493 return (void *)op;
7494}
7495GC_API GC_ATTR_MALLOC void * GC_CALL GC_debug_gcj_malloc(size_t lb,
7496 void * ptr_to_struct_containing_descr, GC_EXTRA_PARAMS)
7497{
7498 void * result;
7499 DCL_LOCK_STATE;
7500 LOCK();
7501 maybe_finalize();
7502 result = GC_generic_malloc_inner(SIZET_SAT_ADD(lb, DEBUG_BYTES),
7503 GC_gcj_debug_kind);
7504 if (result == 0) {
7505 GC_oom_func oom_fn = GC_oom_fn;
7506 UNLOCK();
7507 GC_err_printf("GC_debug_gcj_malloc(%lu, %p) returning NULL (%s:%d)\n",
7508 (unsigned long)lb, ptr_to_struct_containing_descr, s, i);
7509 return((*oom_fn)(lb));
7510 }
7511 *((void **)((ptr_t)result + sizeof(oh))) = ptr_to_struct_containing_descr;
7512 if (!GC_debugging_started) {
7513 GC_start_debugging_inner();
7514 }
7515 ADD_CALL_CHAIN(result, ra);
7516 result = GC_store_debug_info_inner(result, (word)lb, s, i);
7517 UNLOCK();
7518 GC_dirty(result);
7519 REACHABLE_AFTER_DIRTY(ptr_to_struct_containing_descr);
7520 return result;
7521}
7522GC_API GC_ATTR_MALLOC void * GC_CALL GC_gcj_malloc_ignore_off_page(size_t lb,
7523 void * ptr_to_struct_containing_descr)
7524{
7525 ptr_t op;
7526 DCL_LOCK_STATE;
7527 GC_DBG_COLLECT_AT_MALLOC(lb);
7528 if(SMALL_OBJ(lb)) {
7529 word lg;
7530 LOCK();
7531 lg = GC_size_map[lb];
7532 op = GC_gcjobjfreelist[lg];
7533 if (EXPECT(0 == op, FALSE)) {
7534 maybe_finalize();
7535 op = (ptr_t)GENERAL_MALLOC_INNER_IOP(lb, GC_gcj_kind);
7536 if (0 == op) {
7537 GC_oom_func oom_fn = GC_oom_fn;
7538 UNLOCK();
7539 return((*oom_fn)(lb));
7540 }
7541 } else {
7542 GC_gcjobjfreelist[lg] = (ptr_t)obj_link(op);
7543 GC_bytes_allocd += GRANULES_TO_BYTES((word)lg);
7544 }
7545 } else {
7546 LOCK();
7547 maybe_finalize();
7548 op = (ptr_t)GENERAL_MALLOC_INNER_IOP(lb, GC_gcj_kind);
7549 if (0 == op) {
7550 GC_oom_func oom_fn = GC_oom_fn;
7551 UNLOCK();
7552 return((*oom_fn)(lb));
7553 }
7554 }
7555 *(void **)op = ptr_to_struct_containing_descr;
7556 UNLOCK();
7557 GC_dirty(op);
7558 REACHABLE_AFTER_DIRTY(ptr_to_struct_containing_descr);
7559 return (void *)op;
7560}
7561#endif
7562GC_INNER hdr * GC_find_header(ptr_t h)
7563{
7564#ifdef HASH_TL
7565 hdr * result;
7566 GET_HDR(h, result);
7567 return(result);
7568#else
7569 return(HDR_INNER(h));
7570#endif
7571}
7572GC_INNER hdr *
7573#ifdef PRINT_BLACK_LIST
7574 GC_header_cache_miss(ptr_t p, hdr_cache_entry *hce, ptr_t source)
7575#else
7576 GC_header_cache_miss(ptr_t p, hdr_cache_entry *hce)
7577#endif
7578{
7579 hdr *hhdr;
7580 HC_MISS();
7581 GET_HDR(p, hhdr);
7582 if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
7583 if (GC_all_interior_pointers) {
7584 if (hhdr != 0) {
7585 ptr_t current = p;
7586 current = (ptr_t)HBLKPTR(current);
7587 do {
7588 current = current - HBLKSIZE*(word)hhdr;
7589 hhdr = HDR(current);
7590 } while(IS_FORWARDING_ADDR_OR_NIL(hhdr));
7591 if (hhdr -> hb_flags & IGNORE_OFF_PAGE)
7592 return 0;
7593 if (HBLK_IS_FREE(hhdr)
7594 || p - current >= (ptrdiff_t)(hhdr->hb_sz)) {
7595 GC_ADD_TO_BLACK_LIST_NORMAL(p, source);
7596 return 0;
7597 }
7598 } else {
7599 GC_ADD_TO_BLACK_LIST_NORMAL(p, source);
7600 }
7601 GC_ASSERT(hhdr == 0 || !HBLK_IS_FREE(hhdr));
7602 return hhdr;
7603 } else {
7604 if (hhdr == 0) {
7605 GC_ADD_TO_BLACK_LIST_NORMAL(p, source);
7606 }
7607 return 0;
7608 }
7609 } else {
7610 if (HBLK_IS_FREE(hhdr)) {
7611 GC_ADD_TO_BLACK_LIST_NORMAL(p, source);
7612 return 0;
7613 } else {
7614 hce -> block_addr = (word)(p) >> LOG_HBLKSIZE;
7615 hce -> hce_hdr = hhdr;
7616 return hhdr;
7617 }
7618 }
7619}
7620GC_INNER ptr_t GC_scratch_alloc(size_t bytes)
7621{
7622 ptr_t result = GC_scratch_free_ptr;
7623 size_t bytes_to_get;
7624 bytes = ROUNDUP_GRANULE_SIZE(bytes);
7625 for (;;) {
7626 GC_ASSERT((word)GC_scratch_end_ptr >= (word)result);
7627 if (bytes <= (word)GC_scratch_end_ptr - (word)result) {
7628 GC_scratch_free_ptr = result + bytes;
7629 return result;
7630 }
7631 GC_ASSERT(GC_page_size != 0);
7632 if (bytes >= MINHINCR * HBLKSIZE) {
7633 bytes_to_get = ROUNDUP_PAGESIZE_IF_MMAP(bytes);
7634 result = (ptr_t)GET_MEM(bytes_to_get);
7635 if (result != NULL) {
7636 GC_add_to_our_memory(result, bytes_to_get);
7637#ifdef USE_SCRATCH_LAST_END_PTR
7638 GC_scratch_last_end_ptr = result + bytes;
7639#endif
7640 }
7641 return result;
7642 }
7643 bytes_to_get = ROUNDUP_PAGESIZE_IF_MMAP(MINHINCR * HBLKSIZE);
7644 result = (ptr_t)GET_MEM(bytes_to_get);
7645 if (EXPECT(NULL == result, FALSE)) {
7646 WARN("Out of memory - trying to allocate requested amount"
7647 " (%" WARN_PRIdPTR " bytes)...\n", (word)bytes);
7648 bytes_to_get = ROUNDUP_PAGESIZE_IF_MMAP(bytes);
7649 result = (ptr_t)GET_MEM(bytes_to_get);
7650 if (result != NULL) {
7651 GC_add_to_our_memory(result, bytes_to_get);
7652#ifdef USE_SCRATCH_LAST_END_PTR
7653 GC_scratch_last_end_ptr = result + bytes;
7654#endif
7655 }
7656 return result;
7657 }
7658 GC_add_to_our_memory(result, bytes_to_get);
7659 GC_scratch_free_ptr = result;
7660 GC_scratch_end_ptr = GC_scratch_free_ptr + bytes_to_get;
7661#ifdef USE_SCRATCH_LAST_END_PTR
7662 GC_scratch_last_end_ptr = GC_scratch_end_ptr;
7663#endif
7664 }
7665}
7666static hdr * alloc_hdr(void)
7667{
7668 hdr * result;
7669 if (NULL == GC_hdr_free_list) {
7670 result = (hdr *)GC_scratch_alloc(sizeof(hdr));
7671 } else {
7672 result = GC_hdr_free_list;
7673 GC_hdr_free_list = (hdr *) result -> hb_next;
7674 }
7675 return(result);
7676}
7677GC_INLINE void free_hdr(hdr * hhdr)
7678{
7679 hhdr -> hb_next = (struct hblk *) GC_hdr_free_list;
7680 GC_hdr_free_list = hhdr;
7681}
7682#ifdef COUNT_HDR_CACHE_HITS
7683 word GC_hdr_cache_hits = 0;
7684 word GC_hdr_cache_misses = 0;
7685#endif
7686GC_INNER void GC_init_headers(void)
7687{
7688 unsigned i;
7689 GC_ASSERT(NULL == GC_all_nils);
7690 GC_all_nils = (bottom_index *)GC_scratch_alloc(sizeof(bottom_index));
7691 if (GC_all_nils == NULL) {
7692 GC_err_printf("Insufficient memory for GC_all_nils\n");
7693 EXIT();
7694 }
7695 BZERO(GC_all_nils, sizeof(bottom_index));
7696 for (i = 0; i < TOP_SZ; i++) {
7697 GC_top_index[i] = GC_all_nils;
7698 }
7699}
7700static GC_bool get_index(word addr)
7701{
7702 word hi = (word)(addr) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE);
7703 bottom_index * r;
7704 bottom_index * p;
7705 bottom_index ** prev;
7706 bottom_index *pi;
7707 word i;
7708 GC_ASSERT(I_HOLD_LOCK());
7709#ifdef HASH_TL
7710 i = TL_HASH(hi);
7711 pi = p = GC_top_index[i];
7712 while(p != GC_all_nils) {
7713 if (p -> key == hi) return(TRUE);
7714 p = p -> hash_link;
7715 }
7716#else
7717 if (GC_top_index[hi] != GC_all_nils)
7718 return TRUE;
7719 i = hi;
7720#endif
7721 r = (bottom_index *)GC_scratch_alloc(sizeof(bottom_index));
7722 if (EXPECT(NULL == r, FALSE))
7723 return FALSE;
7724 BZERO(r, sizeof(bottom_index));
7725 r -> key = hi;
7726#ifdef HASH_TL
7727 r -> hash_link = pi;
7728#endif
7729 prev = &GC_all_bottom_indices;
7730 pi = 0;
7731 while ((p = *prev) != 0 && p -> key < hi) {
7732 pi = p;
7733 prev = &(p -> asc_link);
7734 }
7735 r -> desc_link = pi;
7736 if (0 == p) {
7737 GC_all_bottom_indices_end = r;
7738 } else {
7739 p -> desc_link = r;
7740 }
7741 r -> asc_link = p;
7742 *prev = r;
7743 GC_top_index[i] = r;
7744 return(TRUE);
7745}
7746GC_INNER struct hblkhdr * GC_install_header(struct hblk *h)
7747{
7748 hdr * result;
7749 if (!get_index((word) h)) return(0);
7750 result = alloc_hdr();
7751 if (result) {
7752 SET_HDR(h, result);
7753#ifdef USE_MUNMAP
7754 result -> hb_last_reclaimed = (unsigned short)GC_gc_no;
7755#endif
7756 }
7757 return(result);
7758}
7759GC_INNER GC_bool GC_install_counts(struct hblk *h, size_t sz)
7760{
7761 struct hblk * hbp;
7762 for (hbp = h; (word)hbp < (word)h + sz; hbp += BOTTOM_SZ) {
7763 if (!get_index((word)hbp))
7764 return FALSE;
7765 if ((word)hbp > GC_WORD_MAX - (word)BOTTOM_SZ * HBLKSIZE)
7766 break;
7767 }
7768 if (!get_index((word)h + sz - 1))
7769 return FALSE;
7770 for (hbp = h + 1; (word)hbp < (word)h + sz; hbp += 1) {
7771 word i = HBLK_PTR_DIFF(hbp, h);
7772 SET_HDR(hbp, (hdr *)(i > MAX_JUMP? MAX_JUMP : i));
7773 }
7774 return TRUE;
7775}
7776GC_INNER void GC_remove_header(struct hblk *h)
7777{
7778 hdr **ha;
7779 GET_HDR_ADDR(h, ha);
7780 free_hdr(*ha);
7781 *ha = 0;
7782}
7783GC_INNER void GC_remove_counts(struct hblk *h, size_t sz)
7784{
7785 struct hblk * hbp;
7786 for (hbp = h+1; (word)hbp < (word)h + sz; hbp += 1) {
7787 SET_HDR(hbp, 0);
7788 }
7789}
7790void GC_apply_to_all_blocks(void (*fn)(struct hblk *h, word client_data),
7791 word client_data)
7792{
7793 signed_word j;
7794 bottom_index * index_p;
7795 for (index_p = GC_all_bottom_indices; index_p != 0;
7796 index_p = index_p -> asc_link) {
7797 for (j = BOTTOM_SZ-1; j >= 0;) {
7798 if (!IS_FORWARDING_ADDR_OR_NIL(index_p->index[j])) {
7799 if (!HBLK_IS_FREE(index_p->index[j])) {
7800 (*fn)(((struct hblk *)
7801 (((index_p->key << LOG_BOTTOM_SZ) + (word)j)
7802 << LOG_HBLKSIZE)),
7803 client_data);
7804 }
7805 j--;
7806 } else if (index_p->index[j] == 0) {
7807 j--;
7808 } else {
7809 j -= (signed_word)(index_p->index[j]);
7810 }
7811 }
7812 }
7813}
7814GC_INNER struct hblk * GC_next_block(struct hblk *h, GC_bool allow_free)
7815{
7816 REGISTER bottom_index * bi;
7817 REGISTER word j = ((word)h >> LOG_HBLKSIZE) & (BOTTOM_SZ-1);
7818 GC_ASSERT(I_HOLD_LOCK());
7819 GET_BI(h, bi);
7820 if (bi == GC_all_nils) {
7821 REGISTER word hi = (word)h >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE);
7822 bi = GC_all_bottom_indices;
7823 while (bi != 0 && bi -> key < hi) bi = bi -> asc_link;
7824 j = 0;
7825 }
7826 while (bi != 0) {
7827 while (j < BOTTOM_SZ) {
7828 hdr * hhdr = bi -> index[j];
7829 if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
7830 j++;
7831 } else {
7832 if (allow_free || !HBLK_IS_FREE(hhdr)) {
7833 return ((struct hblk *)
7834 (((bi -> key << LOG_BOTTOM_SZ) + j)
7835 << LOG_HBLKSIZE));
7836 } else {
7837 j += divHBLKSZ(hhdr -> hb_sz);
7838 }
7839 }
7840 }
7841 j = 0;
7842 bi = bi -> asc_link;
7843 }
7844 return(0);
7845}
7846GC_INNER struct hblk * GC_prev_block(struct hblk *h)
7847{
7848 bottom_index * bi;
7849 signed_word j = ((word)h >> LOG_HBLKSIZE) & (BOTTOM_SZ-1);
7850 GC_ASSERT(I_HOLD_LOCK());
7851 GET_BI(h, bi);
7852 if (bi == GC_all_nils) {
7853 word hi = (word)h >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE);
7854 bi = GC_all_bottom_indices_end;
7855 while (bi != 0 && bi -> key > hi) bi = bi -> desc_link;
7856 j = BOTTOM_SZ - 1;
7857 }
7858 while(bi != 0) {
7859 while (j >= 0) {
7860 hdr * hhdr = bi -> index[j];
7861 if (0 == hhdr) {
7862 --j;
7863 } else if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
7864 j -= (signed_word)hhdr;
7865 } else {
7866 return((struct hblk *)
7867 (((bi -> key << LOG_BOTTOM_SZ) + j)
7868 << LOG_HBLKSIZE));
7869 }
7870 }
7871 j = BOTTOM_SZ - 1;
7872 bi = bi -> desc_link;
7873 }
7874 return(0);
7875}
7876#include <stdio.h>
7877#ifndef SMALL_CONFIG
7878 STATIC ptr_t GC_build_fl_clear2(struct hblk *h, ptr_t ofl)
7879 {
7880 word * p = (word *)(h -> hb_body);
7881 word * lim = (word *)(h + 1);
7882 p[0] = (word)ofl;
7883 p[1] = 0;
7884 p[2] = (word)p;
7885 p[3] = 0;
7886 p += 4;
7887 for (; (word)p < (word)lim; p += 4) {
7888 p[0] = (word)(p-2);
7889 p[1] = 0;
7890 p[2] = (word)p;
7891 p[3] = 0;
7892 }
7893 return((ptr_t)(p-2));
7894 }
7895 STATIC ptr_t GC_build_fl_clear4(struct hblk *h, ptr_t ofl)
7896 {
7897 word * p = (word *)(h -> hb_body);
7898 word * lim = (word *)(h + 1);
7899 p[0] = (word)ofl;
7900 p[1] = 0;
7901 p[2] = 0;
7902 p[3] = 0;
7903 p += 4;
7904 for (; (word)p < (word)lim; p += 4) {
7905 GC_PREFETCH_FOR_WRITE((ptr_t)(p + 64));
7906 p[0] = (word)(p-4);
7907 p[1] = 0;
7908 CLEAR_DOUBLE(p+2);
7909 }
7910 return((ptr_t)(p-4));
7911 }
7912 STATIC ptr_t GC_build_fl2(struct hblk *h, ptr_t ofl)
7913 {
7914 word * p = (word *)(h -> hb_body);
7915 word * lim = (word *)(h + 1);
7916 p[0] = (word)ofl;
7917 p[2] = (word)p;
7918 p += 4;
7919 for (; (word)p < (word)lim; p += 4) {
7920 p[0] = (word)(p-2);
7921 p[2] = (word)p;
7922 }
7923 return((ptr_t)(p-2));
7924 }
7925 STATIC ptr_t GC_build_fl4(struct hblk *h, ptr_t ofl)
7926 {
7927 word * p = (word *)(h -> hb_body);
7928 word * lim = (word *)(h + 1);
7929 p[0] = (word)ofl;
7930 p[4] = (word)p;
7931 p += 8;
7932 for (; (word)p < (word)lim; p += 8) {
7933 GC_PREFETCH_FOR_WRITE((ptr_t)(p + 64));
7934 p[0] = (word)(p-4);
7935 p[4] = (word)p;
7936 }
7937 return((ptr_t)(p-4));
7938 }
7939#endif
7940GC_INNER ptr_t GC_build_fl(struct hblk *h, size_t sz, GC_bool clear,
7941 ptr_t list)
7942{
7943 word *p, *prev;
7944 word *last_object;
7945 GC_PREFETCH_FOR_WRITE((ptr_t)h);
7946 GC_PREFETCH_FOR_WRITE((ptr_t)h + 128);
7947 GC_PREFETCH_FOR_WRITE((ptr_t)h + 256);
7948 GC_PREFETCH_FOR_WRITE((ptr_t)h + 378);
7949#ifndef SMALL_CONFIG
7950 switch (sz) {
7951 case 2: if (clear) {
7952 return GC_build_fl_clear2(h, list);
7953 } else {
7954 return GC_build_fl2(h, list);
7955 }
7956 case 4: if (clear) {
7957 return GC_build_fl_clear4(h, list);
7958 } else {
7959 return GC_build_fl4(h, list);
7960 }
7961 default:
7962 break;
7963 }
7964#endif
7965 if (clear) BZERO(h, HBLKSIZE);
7966 p = (word *)(h -> hb_body) + sz;
7967 prev = (word *)(h -> hb_body);
7968 last_object = (word *)((char *)h + HBLKSIZE);
7969 last_object -= sz;
7970 while ((word)p <= (word)last_object) {
7971 obj_link(p) = (ptr_t)prev;
7972 prev = p;
7973 p += sz;
7974 }
7975 p -= sz;
7976 *(ptr_t *)h = list;
7977 return ((ptr_t)p);
7978}
7979GC_INNER void GC_new_hblk(size_t gran, int kind)
7980{
7981 struct hblk *h;
7982 GC_bool clear = GC_obj_kinds[kind].ok_init;
7983 GC_STATIC_ASSERT((sizeof (struct hblk)) == HBLKSIZE);
7984 GC_ASSERT(I_HOLD_LOCK());
7985 if (GC_debugging_started) clear = TRUE;
7986 h = GC_allochblk(GRANULES_TO_BYTES(gran), kind, 0);
7987 if (h == 0) return;
7988 if (IS_UNCOLLECTABLE(kind)) GC_set_hdr_marks(HDR(h));
7989 GC_obj_kinds[kind].ok_freelist[gran] =
7990 GC_build_fl(h, GRANULES_TO_WORDS(gran), clear,
7991 (ptr_t)GC_obj_kinds[kind].ok_freelist[gran]);
7992}
7993GC_API void GC_CALL GC_register_displacement(size_t offset)
7994{
7995 DCL_LOCK_STATE;
7996 LOCK();
7997 GC_register_displacement_inner(offset);
7998 UNLOCK();
7999}
8000GC_INNER void GC_register_displacement_inner(size_t offset)
8001{
8002 GC_ASSERT(I_HOLD_LOCK());
8003 if (offset >= VALID_OFFSET_SZ) {
8004 ABORT("Bad argument to GC_register_displacement");
8005 }
8006 if (!GC_valid_offsets[offset]) {
8007 GC_valid_offsets[offset] = TRUE;
8008 GC_modws_valid_offsets[offset % sizeof(word)] = TRUE;
8009 }
8010}
8011#ifdef MARK_BIT_PER_GRANULE
8012 GC_INNER GC_bool GC_add_map_entry(size_t granules)
8013 {
8014 unsigned displ;
8015 unsigned short * new_map;
8016 if (granules > BYTES_TO_GRANULES(MAXOBJBYTES)) granules = 0;
8017 if (GC_obj_map[granules] != 0) {
8018 return(TRUE);
8019 }
8020 new_map = (unsigned short *)GC_scratch_alloc(MAP_LEN * sizeof(short));
8021 if (new_map == 0) return(FALSE);
8022 GC_COND_LOG_PRINTF(
8023 "Adding block map for size of %u granules (%u bytes)\n",
8024 (unsigned)granules, (unsigned)GRANULES_TO_BYTES(granules));
8025 if (granules == 0) {
8026 for (displ = 0; displ < BYTES_TO_GRANULES(HBLKSIZE); displ++) {
8027 new_map[displ] = 1;
8028 }
8029 } else {
8030 for (displ = 0; displ < BYTES_TO_GRANULES(HBLKSIZE); displ++) {
8031 new_map[displ] = (unsigned short)(displ % granules);
8032 }
8033 }
8034 GC_obj_map[granules] = new_map;
8035 return(TRUE);
8036 }
8037#endif
8038GC_INNER void GC_initialize_offsets(void)
8039{
8040 unsigned i;
8041 if (GC_all_interior_pointers) {
8042 for (i = 0; i < VALID_OFFSET_SZ; ++i)
8043 GC_valid_offsets[i] = TRUE;
8044 } else {
8045 BZERO(GC_valid_offsets, sizeof(GC_valid_offsets));
8046 for (i = 0; i < sizeof(word); ++i)
8047 GC_modws_valid_offsets[i] = FALSE;
8048 }
8049}
8050STATIC void GC_CALLBACK GC_default_same_obj_print_proc(void * p, void * q)
8051{
8052 ABORT_ARG2("GC_same_obj test failed",
8053 ": %p and %p are not in the same object", p, q);
8054}
8055void (GC_CALLBACK *GC_same_obj_print_proc) (void *, void *)
8056 = GC_default_same_obj_print_proc;
8057GC_API void * GC_CALL GC_same_obj(void *p, void *q)
8058{
8059 struct hblk *h;
8060 hdr *hhdr;
8061 ptr_t base, limit;
8062 word sz;
8063 if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
8064 hhdr = HDR((word)p);
8065 if (hhdr == 0) {
8066 if (divHBLKSZ((word)p) != divHBLKSZ((word)q)
8067 && HDR((word)q) != 0) {
8068 goto fail;
8069 }
8070 return(p);
8071 }
8072 if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
8073 h = HBLKPTR(p) - (word)hhdr;
8074 hhdr = HDR(h);
8075 while (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
8076 h = FORWARDED_ADDR(h, hhdr);
8077 hhdr = HDR(h);
8078 }
8079 limit = (ptr_t)h + hhdr -> hb_sz;
8080 if ((word)p >= (word)limit || (word)q >= (word)limit
8081 || (word)q < (word)h) {
8082 goto fail;
8083 }
8084 return(p);
8085 }
8086 sz = hhdr -> hb_sz;
8087 if (sz > MAXOBJBYTES) {
8088 base = (ptr_t)HBLKPTR(p);
8089 limit = base + sz;
8090 if ((word)p >= (word)limit) {
8091 goto fail;
8092 }
8093 } else {
8094 size_t offset;
8095 size_t pdispl = HBLKDISPL(p);
8096 offset = pdispl % sz;
8097 if (HBLKPTR(p) != HBLKPTR(q)) goto fail;
8098 base = (ptr_t)p - offset;
8099 limit = base + sz;
8100 }
8101 if ((word)q >= (word)limit || (word)q < (word)base) {
8102 goto fail;
8103 }
8104 return(p);
8105fail:
8106 (*GC_same_obj_print_proc)((ptr_t)p, (ptr_t)q);
8107 return(p);
8108}
8109STATIC void GC_CALLBACK GC_default_is_valid_displacement_print_proc (void *p)
8110{
8111 ABORT_ARG1("GC_is_valid_displacement test failed", ": %p not valid", p);
8112}
8113void (GC_CALLBACK *GC_is_valid_displacement_print_proc)(void *) =
8114 GC_default_is_valid_displacement_print_proc;
8115GC_API void * GC_CALL GC_is_valid_displacement(void *p)
8116{
8117 hdr *hhdr;
8118 word pdispl;
8119 word offset;
8120 struct hblk *h;
8121 word sz;
8122 if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
8123 hhdr = HDR((word)p);
8124 if (hhdr == 0) return(p);
8125 h = HBLKPTR(p);
8126 if (GC_all_interior_pointers) {
8127 while (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
8128 h = FORWARDED_ADDR(h, hhdr);
8129 hhdr = HDR(h);
8130 }
8131 } else if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
8132 goto fail;
8133 }
8134 sz = hhdr -> hb_sz;
8135 pdispl = HBLKDISPL(p);
8136 offset = pdispl % sz;
8137 if ((sz > MAXOBJBYTES && (word)p >= (word)h + sz)
8138 || !GC_valid_offsets[offset]
8139 || ((word)p + (sz - offset) > (word)(h + 1)
8140 && !IS_FORWARDING_ADDR_OR_NIL(HDR(h + 1)))) {
8141 goto fail;
8142 }
8143 return(p);
8144fail:
8145 (*GC_is_valid_displacement_print_proc)((ptr_t)p);
8146 return(p);
8147}
8148STATIC void GC_CALLBACK GC_default_is_visible_print_proc(void * p)
8149{
8150 ABORT_ARG1("GC_is_visible test failed", ": %p not GC-visible", p);
8151}
8152void (GC_CALLBACK *GC_is_visible_print_proc)(void * p) =
8153 GC_default_is_visible_print_proc;
8154#ifndef THREADS
8155 STATIC GC_bool GC_on_stack(void *p)
8156 {
8157#ifdef STACK_GROWS_DOWN
8158 if ((word)p >= (word)GC_approx_sp()
8159 && (word)p < (word)GC_stackbottom) {
8160 return(TRUE);
8161 }
8162#else
8163 if ((word)p <= (word)GC_approx_sp()
8164 && (word)p > (word)GC_stackbottom) {
8165 return(TRUE);
8166 }
8167#endif
8168 return(FALSE);
8169 }
8170#endif
8171GC_API void * GC_CALL GC_is_visible(void *p)
8172{
8173 hdr *hhdr;
8174 if ((word)p & (ALIGNMENT - 1)) goto fail;
8175 if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
8176#ifdef THREADS
8177 hhdr = HDR((word)p);
8178 if (hhdr != 0 && GC_base(p) == 0) {
8179 goto fail;
8180 } else {
8181 return(p);
8182 }
8183#else
8184 if (GC_on_stack(p)) return(p);
8185 hhdr = HDR((word)p);
8186 if (hhdr == 0) {
8187 if (GC_is_static_root(p)) return(p);
8188#if defined(DYNAMIC_LOADING) || defined(MSWIN32) \
8189 || defined(MSWINCE) || defined(CYGWIN32) || defined(PCR)
8190 GC_register_dynamic_libraries();
8191 if (GC_is_static_root(p))
8192 return(p);
8193#endif
8194 goto fail;
8195 } else {
8196 word descr;
8197 ptr_t base = (ptr_t)GC_base(p);
8198 if (NULL == base) goto fail;
8199 if (HBLKPTR(base) != HBLKPTR(p))
8200 hhdr = HDR(base);
8201 descr = hhdr -> hb_descr;
8202 retry:
8203 switch(descr & GC_DS_TAGS) {
8204 case GC_DS_LENGTH:
8205 if ((word)p - (word)base > descr) goto fail;
8206 break;
8207 case GC_DS_BITMAP:
8208 if ((word)p - (word)base >= WORDS_TO_BYTES(BITMAP_BITS)
8209 || ((word)p & (sizeof(word) - 1))) goto fail;
8210 if (!(((word)1 << (WORDSZ - ((ptr_t)p - (ptr_t)base) - 1))
8211 & descr)) goto fail;
8212 break;
8213 case GC_DS_PROC:
8214 break;
8215 case GC_DS_PER_OBJECT:
8216 if ((signed_word)descr >= 0) {
8217 descr = *(word *)((ptr_t)base + (descr & ~GC_DS_TAGS));
8218 } else {
8219 ptr_t type_descr = *(ptr_t *)base;
8220 descr = *(word *)(type_descr
8221 - (descr - (word)(GC_DS_PER_OBJECT
8222 - GC_INDIR_PER_OBJ_BIAS)));
8223 }
8224 goto retry;
8225 }
8226 return(p);
8227 }
8228#endif
8229fail:
8230 (*GC_is_visible_print_proc)((ptr_t)p);
8231 return(p);
8232}
8233GC_API void * GC_CALL GC_pre_incr (void **p, ptrdiff_t how_much)
8234{
8235 void * initial = *p;
8236 void * result = GC_same_obj((void *)((ptr_t)initial + how_much), initial);
8237 if (!GC_all_interior_pointers) {
8238 (void) GC_is_valid_displacement(result);
8239 }
8240 return (*p = result);
8241}
8242GC_API void * GC_CALL GC_post_incr (void **p, ptrdiff_t how_much)
8243{
8244 void * initial = *p;
8245 void * result = GC_same_obj((void *)((ptr_t)initial + how_much), initial);
8246 if (!GC_all_interior_pointers) {
8247 (void) GC_is_valid_displacement(result);
8248 }
8249 *p = result;
8250 return(initial);
8251}
8252#ifndef GC_INLINE_H
8253#define GC_INLINE_H
8254#if GC_GNUC_PREREQ(3, 0)
8255#define GC_EXPECT(expr, outcome) __builtin_expect(expr,outcome)
8256#else
8257#define GC_EXPECT(expr, outcome) (expr)
8258#endif
8259#ifndef GC_ASSERT
8260#ifdef NDEBUG
8261#define GC_ASSERT(expr)
8262#else
8263#include <assert.h>
8264#define GC_ASSERT(expr) assert(expr)
8265#endif
8266#endif
8267#ifdef __cplusplus
8268 extern "C" {
8269#endif
8270#ifndef GC_PREFETCH_FOR_WRITE
8271#if GC_GNUC_PREREQ(3, 0) && !defined(GC_NO_PREFETCH_FOR_WRITE)
8272#define GC_PREFETCH_FOR_WRITE(x) __builtin_prefetch((x), 1)
8273#else
8274#define GC_PREFETCH_FOR_WRITE(x) (void)0
8275#endif
8276#endif
8277#define GC_I_PTRFREE 0
8278#define GC_I_NORMAL 1
8279GC_API void GC_CALL GC_generic_malloc_many(size_t , int ,
8280 void ** );
8281GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
8282 GC_malloc_kind(size_t , int );
8283#ifdef GC_THREADS
8284 GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
8285 GC_malloc_kind_global(size_t , int );
8286#else
8287#define GC_malloc_kind_global GC_malloc_kind
8288#endif
8289#if defined(GC_THREADS) && defined(AO_HAVE_store)
8290#define GC_FAST_M_AO_STORE(my_fl, next) \
8291 AO_store((volatile AO_t *)(my_fl), (AO_t)(next))
8292#else
8293#define GC_FAST_M_AO_STORE(my_fl, next) (void)(*(my_fl) = (next))
8294#endif
8295#define GC_FAST_MALLOC_GRANS(result,granules,tiny_fl,num_direct, \
8296 kind,default_expr,init) \
8297 do { \
8298 if (GC_EXPECT((granules) >= GC_TINY_FREELISTS,0)) { \
8299 result = (default_expr); \
8300 } else { \
8301 void **my_fl = (tiny_fl) + (granules); \
8302 void *my_entry=*my_fl; \
8303 void *next; \
8304 \
8305 for (;;) { \
8306 if (GC_EXPECT((GC_word)my_entry \
8307 > (num_direct) + GC_TINY_FREELISTS + 1, 1)) { \
8308 next = *(void **)(my_entry); \
8309 result = (void *)my_entry; \
8310 GC_FAST_M_AO_STORE(my_fl, next); \
8311 init; \
8312 GC_PREFETCH_FOR_WRITE(next); \
8313 if ((kind) != GC_I_PTRFREE) { \
8314 GC_end_stubborn_change(my_fl); \
8315 GC_reachable_here(next); \
8316 } \
8317 GC_ASSERT(GC_size(result) >= (granules)*GC_GRANULE_BYTES); \
8318 GC_ASSERT((kind) == GC_I_PTRFREE \
8319 || ((GC_word *)result)[1] == 0); \
8320 break; \
8321 } \
8322 \
8323 if ((GC_signed_word)my_entry - (GC_signed_word)(num_direct) <= 0 \
8324 \
8325 && my_entry != 0 ) { \
8326 \
8327 GC_FAST_M_AO_STORE(my_fl, (char *)my_entry \
8328 + (granules) + 1); \
8329 result = (default_expr); \
8330 break; \
8331 } else { \
8332 \
8333 GC_generic_malloc_many(((granules) == 0? GC_GRANULE_BYTES : \
8334 GC_RAW_BYTES_FROM_INDEX(granules)), \
8335 kind, my_fl); \
8336 my_entry = *my_fl; \
8337 if (my_entry == 0) { \
8338 result = (*GC_get_oom_fn())((granules)*GC_GRANULE_BYTES); \
8339 break; \
8340 } \
8341 } \
8342 } \
8343 } \
8344 } while (0)
8345#define GC_WORDS_TO_WHOLE_GRANULES(n) \
8346 GC_WORDS_TO_GRANULES((n) + GC_GRANULE_WORDS - 1)
8347#define GC_MALLOC_WORDS_KIND(result,n,tiny_fl,kind,init) \
8348 do { \
8349 size_t granules = GC_WORDS_TO_WHOLE_GRANULES(n); \
8350 GC_FAST_MALLOC_GRANS(result, granules, tiny_fl, 0, kind, \
8351 GC_malloc_kind(granules*GC_GRANULE_BYTES, kind), \
8352 init); \
8353 } while (0)
8354#define GC_MALLOC_WORDS(result,n,tiny_fl) \
8355 GC_MALLOC_WORDS_KIND(result, n, tiny_fl, GC_I_NORMAL, \
8356 *(void **)(result) = 0)
8357#define GC_MALLOC_ATOMIC_WORDS(result,n,tiny_fl) \
8358 GC_MALLOC_WORDS_KIND(result, n, tiny_fl, GC_I_PTRFREE, (void)0)
8359#define GC_CONS(result, first, second, tiny_fl) \
8360 do { \
8361 void *l = (void *)(first); \
8362 void *r = (void *)(second); \
8363 GC_MALLOC_WORDS_KIND(result, 2, tiny_fl, GC_I_NORMAL, (void)0); \
8364 if ((result) != 0 ) { \
8365 *(void **)(result) = l; \
8366 GC_PTR_STORE_AND_DIRTY((void **)(result) + 1, r); \
8367 GC_reachable_here(l); \
8368 } \
8369 } while (0)
8370GC_API void GC_CALL GC_print_free_list(int ,
8371 size_t );
8372#ifdef __cplusplus
8373 }
8374#endif
8375#endif
8376#include <stdio.h>
8377#ifdef GC_USE_ENTIRE_HEAP
8378 int GC_use_entire_heap = TRUE;
8379#else
8380 int GC_use_entire_heap = FALSE;
8381#endif
8382#define MAX_BLACK_LIST_ALLOC (2*HBLKSIZE)
8383#define UNIQUE_THRESHOLD 32
8384#define HUGE_THRESHOLD 256
8385#define FL_COMPRESSION 8
8386#define N_HBLK_FLS ((HUGE_THRESHOLD - UNIQUE_THRESHOLD) / FL_COMPRESSION \
8387 + UNIQUE_THRESHOLD)
8388#ifndef GC_GCJ_SUPPORT
8389 STATIC
8390#endif
8391 struct hblk * GC_hblkfreelist[N_HBLK_FLS+1] = { 0 };
8392#ifndef GC_GCJ_SUPPORT
8393 STATIC
8394#endif
8395 word GC_free_bytes[N_HBLK_FLS+1] = { 0 };
8396GC_INLINE int GC_enough_large_bytes_left(void)
8397{
8398 int n;
8399 word bytes = GC_large_allocd_bytes;
8400 GC_ASSERT(GC_max_large_allocd_bytes <= GC_heapsize);
8401 for (n = N_HBLK_FLS; n >= 0; --n) {
8402 bytes += GC_free_bytes[n];
8403 if (bytes >= GC_max_large_allocd_bytes) return n;
8404 }
8405 return 0;
8406}
8407STATIC int GC_hblk_fl_from_blocks(word blocks_needed)
8408{
8409 if (blocks_needed <= UNIQUE_THRESHOLD) return (int)blocks_needed;
8410 if (blocks_needed >= HUGE_THRESHOLD) return N_HBLK_FLS;
8411 return (int)(blocks_needed - UNIQUE_THRESHOLD)/FL_COMPRESSION
8412 + UNIQUE_THRESHOLD;
8413}
8414#define PHDR(hhdr) HDR((hhdr) -> hb_prev)
8415#define NHDR(hhdr) HDR((hhdr) -> hb_next)
8416#ifdef USE_MUNMAP
8417#define IS_MAPPED(hhdr) (((hhdr) -> hb_flags & WAS_UNMAPPED) == 0)
8418#else
8419#define IS_MAPPED(hhdr) TRUE
8420#endif
8421#if !defined(NO_DEBUGGING) || defined(GC_ASSERTIONS)
8422 GC_INNER word GC_compute_large_free_bytes(void)
8423 {
8424 word total_free = 0;
8425 unsigned i;
8426 for (i = 0; i <= N_HBLK_FLS; ++i) {
8427 struct hblk * h;
8428 hdr * hhdr;
8429 for (h = GC_hblkfreelist[i]; h != 0; h = hhdr->hb_next) {
8430 hhdr = HDR(h);
8431 total_free += hhdr->hb_sz;
8432 }
8433 }
8434 return total_free;
8435 }
8436#endif
8437#if !defined(NO_DEBUGGING)
8438void GC_print_hblkfreelist(void)
8439{
8440 unsigned i;
8441 word total;
8442 for (i = 0; i <= N_HBLK_FLS; ++i) {
8443 struct hblk * h = GC_hblkfreelist[i];
8444 if (0 != h) GC_printf("Free list %u (total size %lu):\n",
8445 i, (unsigned long)GC_free_bytes[i]);
8446 while (h ) {
8447 hdr * hhdr = HDR(h);
8448 GC_printf("\t%p size %lu %s black listed\n",
8449 (void *)h, (unsigned long) hhdr -> hb_sz,
8450 GC_is_black_listed(h, HBLKSIZE) != 0 ? "start" :
8451 GC_is_black_listed(h, hhdr -> hb_sz) != 0 ? "partially" :
8452 "not");
8453 h = hhdr -> hb_next;
8454 }
8455 }
8456 GC_printf("GC_large_free_bytes: %lu\n",
8457 (unsigned long)GC_large_free_bytes);
8458 if ((total = GC_compute_large_free_bytes()) != GC_large_free_bytes)
8459 GC_err_printf("GC_large_free_bytes INCONSISTENT!! Should be: %lu\n",
8460 (unsigned long)total);
8461}
8462static int free_list_index_of(hdr *wanted)
8463{
8464 int i;
8465 for (i = 0; i <= N_HBLK_FLS; ++i) {
8466 struct hblk * h;
8467 hdr * hhdr;
8468 for (h = GC_hblkfreelist[i]; h != 0; h = hhdr -> hb_next) {
8469 hhdr = HDR(h);
8470 if (hhdr == wanted) return i;
8471 }
8472 }
8473 return -1;
8474}
8475GC_API void GC_CALL GC_dump_regions(void)
8476{
8477 unsigned i;
8478 for (i = 0; i < GC_n_heap_sects; ++i) {
8479 ptr_t start = GC_heap_sects[i].hs_start;
8480 size_t bytes = GC_heap_sects[i].hs_bytes;
8481 ptr_t end = start + bytes;
8482 ptr_t p;
8483 while (i+1 < GC_n_heap_sects && GC_heap_sects[i+1].hs_start == end) {
8484 ++i;
8485 end = GC_heap_sects[i].hs_start + GC_heap_sects[i].hs_bytes;
8486 }
8487 GC_printf("***Section from %p to %p\n", (void *)start, (void *)end);
8488 for (p = start; (word)p < (word)end; ) {
8489 hdr *hhdr = HDR(p);
8490 if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
8491 GC_printf("\t%p Missing header!!(%p)\n",
8492 (void *)p, (void *)hhdr);
8493 p += HBLKSIZE;
8494 continue;
8495 }
8496 if (HBLK_IS_FREE(hhdr)) {
8497 int correct_index = GC_hblk_fl_from_blocks(
8498 divHBLKSZ(hhdr -> hb_sz));
8499 int actual_index;
8500 GC_printf("\t%p\tfree block of size 0x%lx bytes%s\n",
8501 (void *)p, (unsigned long)(hhdr -> hb_sz),
8502 IS_MAPPED(hhdr) ? "" : " (unmapped)");
8503 actual_index = free_list_index_of(hhdr);
8504 if (-1 == actual_index) {
8505 GC_printf("\t\tBlock not on free list %d!!\n",
8506 correct_index);
8507 } else if (correct_index != actual_index) {
8508 GC_printf("\t\tBlock on list %d, should be on %d!!\n",
8509 actual_index, correct_index);
8510 }
8511 p += hhdr -> hb_sz;
8512 } else {
8513 GC_printf("\t%p\tused for blocks of size 0x%lx bytes\n",
8514 (void *)p, (unsigned long)(hhdr -> hb_sz));
8515 p += HBLKSIZE * OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
8516 }
8517 }
8518 }
8519}
8520#endif
8521static GC_bool setup_header(hdr * hhdr, struct hblk *block, size_t byte_sz,
8522 int kind, unsigned flags)
8523{
8524 word descr;
8525#ifdef MARK_BIT_PER_GRANULE
8526 if (byte_sz > MAXOBJBYTES)
8527 flags |= LARGE_BLOCK;
8528#endif
8529#ifdef ENABLE_DISCLAIM
8530 if (GC_obj_kinds[kind].ok_disclaim_proc)
8531 flags |= HAS_DISCLAIM;
8532 if (GC_obj_kinds[kind].ok_mark_unconditionally)
8533 flags |= MARK_UNCONDITIONALLY;
8534#endif
8535 hhdr -> hb_sz = byte_sz;
8536 hhdr -> hb_obj_kind = (unsigned char)kind;
8537 hhdr -> hb_flags = (unsigned char)flags;
8538 hhdr -> hb_block = block;
8539 descr = GC_obj_kinds[kind].ok_descriptor;
8540 if (GC_obj_kinds[kind].ok_relocate_descr) descr += byte_sz;
8541 hhdr -> hb_descr = descr;
8542#ifdef MARK_BIT_PER_OBJ
8543 if (byte_sz > MAXOBJBYTES) {
8544 hhdr -> hb_inv_sz = LARGE_INV_SZ;
8545 } else {
8546 word inv_sz;
8547#if CPP_WORDSZ == 64
8548 inv_sz = ((word)1 << 32)/byte_sz;
8549 if (((inv_sz*byte_sz) >> 32) == 0) ++inv_sz;
8550#else
8551 GC_ASSERT(byte_sz >= 4);
8552 inv_sz = ((unsigned)1 << 31)/byte_sz;
8553 inv_sz *= 2;
8554 while (inv_sz*byte_sz > byte_sz) ++inv_sz;
8555#endif
8556#ifdef INV_SZ_COMPUTATION_CHECK
8557 GC_ASSERT(((1ULL << 32) + byte_sz - 1) / byte_sz == inv_sz);
8558#endif
8559 hhdr -> hb_inv_sz = inv_sz;
8560 }
8561#endif
8562#ifdef MARK_BIT_PER_GRANULE
8563 {
8564 size_t granules = BYTES_TO_GRANULES(byte_sz);
8565 if (EXPECT(!GC_add_map_entry(granules), FALSE)) {
8566 hhdr -> hb_sz = HBLKSIZE;
8567 hhdr -> hb_descr = 0;
8568 hhdr -> hb_flags |= LARGE_BLOCK;
8569 hhdr -> hb_map = 0;
8570 return FALSE;
8571 }
8572 hhdr -> hb_map = GC_obj_map[(hhdr -> hb_flags & LARGE_BLOCK) != 0 ?
8573 0 : granules];
8574 }
8575#endif
8576 GC_clear_hdr_marks(hhdr);
8577 hhdr -> hb_last_reclaimed = (unsigned short)GC_gc_no;
8578 return(TRUE);
8579}
8580STATIC void GC_remove_from_fl_at(hdr *hhdr, int index)
8581{
8582 GC_ASSERT(((hhdr -> hb_sz) & (HBLKSIZE-1)) == 0);
8583 if (hhdr -> hb_prev == 0) {
8584 GC_ASSERT(HDR(GC_hblkfreelist[index]) == hhdr);
8585 GC_hblkfreelist[index] = hhdr -> hb_next;
8586 } else {
8587 hdr *phdr;
8588 GET_HDR(hhdr -> hb_prev, phdr);
8589 phdr -> hb_next = hhdr -> hb_next;
8590 }
8591 GC_ASSERT(GC_free_bytes[index] >= hhdr -> hb_sz);
8592 GC_free_bytes[index] -= hhdr -> hb_sz;
8593 if (0 != hhdr -> hb_next) {
8594 hdr * nhdr;
8595 GC_ASSERT(!IS_FORWARDING_ADDR_OR_NIL(NHDR(hhdr)));
8596 GET_HDR(hhdr -> hb_next, nhdr);
8597 nhdr -> hb_prev = hhdr -> hb_prev;
8598 }
8599}
8600GC_INLINE void GC_remove_from_fl(hdr *hhdr)
8601{
8602 GC_remove_from_fl_at(hhdr, GC_hblk_fl_from_blocks(divHBLKSZ(hhdr->hb_sz)));
8603}
8604static struct hblk * get_block_ending_at(struct hblk *h)
8605{
8606 struct hblk * p = h - 1;
8607 hdr * phdr;
8608 GET_HDR(p, phdr);
8609 while (0 != phdr && IS_FORWARDING_ADDR_OR_NIL(phdr)) {
8610 p = FORWARDED_ADDR(p,phdr);
8611 phdr = HDR(p);
8612 }
8613 if (0 != phdr) {
8614 return p;
8615 }
8616 p = GC_prev_block(h - 1);
8617 if (p) {
8618 phdr = HDR(p);
8619 if ((ptr_t)p + phdr -> hb_sz == (ptr_t)h) {
8620 return p;
8621 }
8622 }
8623 return NULL;
8624}
8625STATIC struct hblk * GC_free_block_ending_at(struct hblk *h)
8626{
8627 struct hblk * p = get_block_ending_at(h);
8628 if (p ) {
8629 hdr * phdr = HDR(p);
8630 if (HBLK_IS_FREE(phdr)) {
8631 return p;
8632 }
8633 }
8634 return 0;
8635}
8636STATIC void GC_add_to_fl(struct hblk *h, hdr *hhdr)
8637{
8638 int index = GC_hblk_fl_from_blocks(divHBLKSZ(hhdr -> hb_sz));
8639 struct hblk *second = GC_hblkfreelist[index];
8640#if defined(GC_ASSERTIONS) && !defined(USE_MUNMAP)
8641 struct hblk *next = (struct hblk *)((word)h + hhdr -> hb_sz);
8642 hdr * nexthdr = HDR(next);
8643 struct hblk *prev = GC_free_block_ending_at(h);
8644 hdr * prevhdr = HDR(prev);
8645 GC_ASSERT(nexthdr == 0 || !HBLK_IS_FREE(nexthdr)
8646 || (GC_heapsize & SIGNB) != 0);
8647 GC_ASSERT(prev == 0 || !HBLK_IS_FREE(prevhdr)
8648 || (GC_heapsize & SIGNB) != 0);
8649#endif
8650 GC_ASSERT(((hhdr -> hb_sz) & (HBLKSIZE-1)) == 0);
8651 GC_hblkfreelist[index] = h;
8652 GC_free_bytes[index] += hhdr -> hb_sz;
8653 GC_ASSERT(GC_free_bytes[index] <= GC_large_free_bytes);
8654 hhdr -> hb_next = second;
8655 hhdr -> hb_prev = 0;
8656 if (second ) {
8657 hdr * second_hdr;
8658 GET_HDR(second, second_hdr);
8659 second_hdr -> hb_prev = h;
8660 }
8661 hhdr -> hb_flags |= FREE_BLK;
8662}
8663#ifdef USE_MUNMAP
8664#ifndef MUNMAP_THRESHOLD
8665#define MUNMAP_THRESHOLD 6
8666#endif
8667GC_INNER int GC_unmap_threshold = MUNMAP_THRESHOLD;
8668#ifdef COUNT_UNMAPPED_REGIONS
8669 static int calc_num_unmapped_regions_delta(struct hblk *h, hdr *hhdr)
8670 {
8671 struct hblk * prev = get_block_ending_at(h);
8672 struct hblk * next;
8673 GC_bool prev_unmapped = FALSE;
8674 GC_bool next_unmapped = FALSE;
8675 next = GC_next_block((struct hblk *)((ptr_t)h + hhdr->hb_sz), TRUE);
8676 if ((ptr_t)next != GC_unmap_end((ptr_t)h, (size_t)hhdr->hb_sz)) {
8677 next = NULL;
8678 }
8679 if (prev != NULL) {
8680 hdr * prevhdr = HDR(prev);
8681 prev_unmapped = !IS_MAPPED(prevhdr);
8682 }
8683 if (next != NULL) {
8684 hdr * nexthdr = HDR(next);
8685 next_unmapped = !IS_MAPPED(nexthdr);
8686 }
8687 if (prev_unmapped && next_unmapped) {
8688 return IS_MAPPED(hhdr) ? -1 : 1;
8689 }
8690 if (!prev_unmapped && !next_unmapped) {
8691 return IS_MAPPED(hhdr) ? 1 : -1;
8692 }
8693 return 0;
8694 }
8695#endif
8696GC_INLINE void GC_adjust_num_unmapped(struct hblk *h GC_ATTR_UNUSED,
8697 hdr *hhdr GC_ATTR_UNUSED)
8698{
8699#ifdef COUNT_UNMAPPED_REGIONS
8700 GC_num_unmapped_regions += calc_num_unmapped_regions_delta(h, hhdr);
8701#endif
8702}
8703GC_INNER void GC_unmap_old(void)
8704{
8705 int i;
8706 if (GC_unmap_threshold == 0)
8707 return;
8708#ifdef COUNT_UNMAPPED_REGIONS
8709 if (GC_num_unmapped_regions >= GC_UNMAPPED_REGIONS_SOFT_LIMIT)
8710 return;
8711#endif
8712 for (i = 0; i <= N_HBLK_FLS; ++i) {
8713 struct hblk * h;
8714 hdr * hhdr;
8715 for (h = GC_hblkfreelist[i]; 0 != h; h = hhdr -> hb_next) {
8716 hhdr = HDR(h);
8717 if (!IS_MAPPED(hhdr)) continue;
8718 if ((unsigned short)(GC_gc_no - hhdr->hb_last_reclaimed) >
8719 (unsigned short)GC_unmap_threshold) {
8720#ifdef COUNT_UNMAPPED_REGIONS
8721 int delta = calc_num_unmapped_regions_delta(h, hhdr);
8722 signed_word regions = GC_num_unmapped_regions + delta;
8723 if (delta >= 0 && regions >= GC_UNMAPPED_REGIONS_SOFT_LIMIT) {
8724 GC_COND_LOG_PRINTF("Unmapped regions limit reached!\n");
8725 return;
8726 }
8727 GC_num_unmapped_regions = regions;
8728#endif
8729 GC_unmap((ptr_t)h, (size_t)hhdr->hb_sz);
8730 hhdr -> hb_flags |= WAS_UNMAPPED;
8731 }
8732 }
8733 }
8734}
8735GC_INNER void GC_merge_unmapped(void)
8736{
8737 int i;
8738 for (i = 0; i <= N_HBLK_FLS; ++i) {
8739 struct hblk *h = GC_hblkfreelist[i];
8740 while (h != 0) {
8741 struct hblk *next;
8742 hdr *hhdr, *nexthdr;
8743 word size, nextsize;
8744 GET_HDR(h, hhdr);
8745 size = hhdr->hb_sz;
8746 next = (struct hblk *)((word)h + size);
8747 GET_HDR(next, nexthdr);
8748 if (0 != nexthdr && HBLK_IS_FREE(nexthdr)
8749 && (signed_word) (size + (nextsize = nexthdr->hb_sz)) > 0
8750 ) {
8751 if (IS_MAPPED(hhdr) && !IS_MAPPED(nexthdr)) {
8752 if (size > nextsize) {
8753 GC_adjust_num_unmapped(next, nexthdr);
8754 GC_remap((ptr_t)next, nextsize);
8755 } else {
8756 GC_adjust_num_unmapped(h, hhdr);
8757 GC_unmap((ptr_t)h, size);
8758 GC_unmap_gap((ptr_t)h, size, (ptr_t)next, nextsize);
8759 hhdr -> hb_flags |= WAS_UNMAPPED;
8760 }
8761 } else if (IS_MAPPED(nexthdr) && !IS_MAPPED(hhdr)) {
8762 if (size > nextsize) {
8763 GC_adjust_num_unmapped(next, nexthdr);
8764 GC_unmap((ptr_t)next, nextsize);
8765 GC_unmap_gap((ptr_t)h, size, (ptr_t)next, nextsize);
8766 } else {
8767 GC_adjust_num_unmapped(h, hhdr);
8768 GC_remap((ptr_t)h, size);
8769 hhdr -> hb_flags &= ~WAS_UNMAPPED;
8770 hhdr -> hb_last_reclaimed = nexthdr -> hb_last_reclaimed;
8771 }
8772 } else if (!IS_MAPPED(hhdr) && !IS_MAPPED(nexthdr)) {
8773 GC_unmap_gap((ptr_t)h, size, (ptr_t)next, nextsize);
8774 }
8775 GC_remove_from_fl_at(hhdr, i);
8776 GC_remove_from_fl(nexthdr);
8777 hhdr -> hb_sz += nexthdr -> hb_sz;
8778 GC_remove_header(next);
8779 GC_add_to_fl(h, hhdr);
8780 h = GC_hblkfreelist[i];
8781 } else {
8782 h = hhdr -> hb_next;
8783 }
8784 }
8785 }
8786}
8787#endif
8788STATIC struct hblk * GC_get_first_part(struct hblk *h, hdr *hhdr,
8789 size_t bytes, int index)
8790{
8791 word total_size = hhdr -> hb_sz;
8792 struct hblk * rest;
8793 hdr * rest_hdr;
8794 GC_ASSERT((total_size & (HBLKSIZE-1)) == 0);
8795 GC_remove_from_fl_at(hhdr, index);
8796 if (total_size == bytes) return h;
8797 rest = (struct hblk *)((word)h + bytes);
8798 rest_hdr = GC_install_header(rest);
8799 if (0 == rest_hdr) {
8800 WARN("Header allocation failed: dropping block\n", 0);
8801 return(0);
8802 }
8803 rest_hdr -> hb_sz = total_size - bytes;
8804 rest_hdr -> hb_flags = 0;
8805#ifdef GC_ASSERTIONS
8806 hhdr -> hb_flags &= ~FREE_BLK;
8807#endif
8808 GC_add_to_fl(rest, rest_hdr);
8809 return h;
8810}
8811STATIC void GC_split_block(struct hblk *h, hdr *hhdr, struct hblk *n,
8812 hdr *nhdr, int index )
8813{
8814 word total_size = hhdr -> hb_sz;
8815 word h_size = (word)n - (word)h;
8816 struct hblk *prev = hhdr -> hb_prev;
8817 struct hblk *next = hhdr -> hb_next;
8818 nhdr -> hb_prev = prev;
8819 nhdr -> hb_next = next;
8820 nhdr -> hb_sz = total_size - h_size;
8821 nhdr -> hb_flags = 0;
8822 if (prev ) {
8823 HDR(prev) -> hb_next = n;
8824 } else {
8825 GC_hblkfreelist[index] = n;
8826 }
8827 if (next ) {
8828 HDR(next) -> hb_prev = n;
8829 }
8830 GC_ASSERT(GC_free_bytes[index] > h_size);
8831 GC_free_bytes[index] -= h_size;
8832#ifdef USE_MUNMAP
8833 hhdr -> hb_last_reclaimed = (unsigned short)GC_gc_no;
8834#endif
8835 hhdr -> hb_sz = h_size;
8836 GC_add_to_fl(h, hhdr);
8837 nhdr -> hb_flags |= FREE_BLK;
8838}
8839STATIC struct hblk *
8840GC_allochblk_nth(size_t sz , int kind, unsigned flags, int n,
8841 int may_split);
8842#define AVOID_SPLIT_REMAPPED 2
8843GC_INNER struct hblk *
8844GC_allochblk(size_t sz, int kind, unsigned flags)
8845{
8846 word blocks;
8847 int start_list;
8848 struct hblk *result;
8849 int may_split;
8850 int split_limit;
8851 GC_ASSERT(I_HOLD_LOCK());
8852 GC_ASSERT((sz & (GRANULE_BYTES - 1)) == 0);
8853 blocks = OBJ_SZ_TO_BLOCKS_CHECKED(sz);
8854 if ((signed_word)(blocks * HBLKSIZE) < 0) {
8855 return 0;
8856 }
8857 start_list = GC_hblk_fl_from_blocks(blocks);
8858 result = GC_allochblk_nth(sz, kind, flags, start_list, FALSE);
8859 if (0 != result) return result;
8860 may_split = TRUE;
8861 if (GC_use_entire_heap || GC_dont_gc
8862 || USED_HEAP_SIZE < GC_requested_heapsize
8863 || GC_incremental || !GC_should_collect()) {
8864 split_limit = N_HBLK_FLS;
8865 } else if (GC_finalizer_bytes_freed > (GC_heapsize >> 4)) {
8866 split_limit = 0;
8867 } else {
8868 split_limit = GC_enough_large_bytes_left();
8869#ifdef USE_MUNMAP
8870 if (split_limit > 0)
8871 may_split = AVOID_SPLIT_REMAPPED;
8872#endif
8873 }
8874 if (start_list < UNIQUE_THRESHOLD) {
8875 ++start_list;
8876 }
8877 for (; start_list <= split_limit; ++start_list) {
8878 result = GC_allochblk_nth(sz, kind, flags, start_list, may_split);
8879 if (0 != result)
8880 break;
8881 }
8882 return result;
8883}
8884STATIC long GC_large_alloc_warn_suppressed = 0;
8885STATIC struct hblk *
8886GC_allochblk_nth(size_t sz, int kind, unsigned flags, int n, int may_split)
8887{
8888 struct hblk *hbp;
8889 hdr * hhdr;
8890 struct hblk *thishbp;
8891 hdr * thishdr;
8892 signed_word size_needed = HBLKSIZE * OBJ_SZ_TO_BLOCKS_CHECKED(sz);
8893 for (hbp = GC_hblkfreelist[n];; hbp = hhdr -> hb_next) {
8894 signed_word size_avail;
8895 if (hbp ) {
8896 } else {
8897 return NULL;
8898 }
8899 GET_HDR(hbp, hhdr);
8900 size_avail = (signed_word)hhdr->hb_sz;
8901 if (size_avail < size_needed) continue;
8902 if (size_avail != size_needed) {
8903 if (!may_split) continue;
8904 thishbp = hhdr -> hb_next;
8905 if (thishbp ) {
8906 signed_word next_size;
8907 GET_HDR(thishbp, thishdr);
8908 next_size = (signed_word)(thishdr -> hb_sz);
8909 if (next_size < size_avail
8910 && next_size >= size_needed
8911 && !GC_is_black_listed(thishbp, (word)size_needed)) {
8912 continue;
8913 }
8914 }
8915 }
8916 if (!IS_UNCOLLECTABLE(kind) && (kind != PTRFREE
8917 || size_needed > (signed_word)MAX_BLACK_LIST_ALLOC)) {
8918 struct hblk * lasthbp = hbp;
8919 ptr_t search_end = (ptr_t)hbp + size_avail - size_needed;
8920 signed_word orig_avail = size_avail;
8921 signed_word eff_size_needed = (flags & IGNORE_OFF_PAGE) != 0 ?
8922 (signed_word)HBLKSIZE
8923 : size_needed;
8924 while ((word)lasthbp <= (word)search_end
8925 && (thishbp = GC_is_black_listed(lasthbp,
8926 (word)eff_size_needed)) != 0) {
8927 lasthbp = thishbp;
8928 }
8929 size_avail -= (ptr_t)lasthbp - (ptr_t)hbp;
8930 thishbp = lasthbp;
8931 if (size_avail >= size_needed) {
8932 if (thishbp != hbp) {
8933#ifdef USE_MUNMAP
8934 if (may_split == AVOID_SPLIT_REMAPPED && !IS_MAPPED(hhdr))
8935 continue;
8936#endif
8937 thishdr = GC_install_header(thishbp);
8938 if (0 != thishdr) {
8939#ifdef USE_MUNMAP
8940 if (!IS_MAPPED(hhdr)) {
8941 GC_adjust_num_unmapped(hbp, hhdr);
8942 GC_remap((ptr_t)hbp, (size_t)hhdr->hb_sz);
8943 hhdr -> hb_flags &= ~WAS_UNMAPPED;
8944 }
8945#endif
8946 GC_split_block(hbp, hhdr, thishbp, thishdr, n);
8947 hbp = thishbp;
8948 hhdr = thishdr;
8949 }
8950 }
8951 } else if (size_needed > (signed_word)BL_LIMIT
8952 && orig_avail - size_needed
8953 > (signed_word)BL_LIMIT) {
8954 if (++GC_large_alloc_warn_suppressed
8955 >= GC_large_alloc_warn_interval) {
8956 WARN("Repeated allocation of very large block "
8957 "(appr. size %" WARN_PRIdPTR "):\n"
8958 "\tMay lead to memory leak and poor performance\n",
8959 size_needed);
8960 GC_large_alloc_warn_suppressed = 0;
8961 }
8962 size_avail = orig_avail;
8963 } else if (size_avail == 0
8964 && size_needed == (signed_word)HBLKSIZE
8965 && IS_MAPPED(hhdr)) {
8966 if (!GC_find_leak) {
8967 static unsigned count = 0;
8968 if ((++count & 3) == 0) {
8969 word total_size = hhdr -> hb_sz;
8970 struct hblk * limit = hbp + divHBLKSZ(total_size);
8971 struct hblk * h;
8972 struct hblk * prev = hhdr -> hb_prev;
8973 GC_large_free_bytes -= total_size;
8974 GC_bytes_dropped += total_size;
8975 GC_remove_from_fl_at(hhdr, n);
8976 for (h = hbp; (word)h < (word)limit; h++) {
8977 if (h != hbp) {
8978 hhdr = GC_install_header(h);
8979 }
8980 if (NULL != hhdr) {
8981 (void)setup_header(hhdr, h, HBLKSIZE, PTRFREE, 0);
8982 if (GC_debugging_started) {
8983 BZERO(h, HBLKSIZE);
8984 }
8985 }
8986 }
8987 hbp = prev;
8988 if (0 == hbp) {
8989 return GC_allochblk_nth(sz, kind, flags, n, may_split);
8990 }
8991 hhdr = HDR(hbp);
8992 }
8993 }
8994 }
8995 }
8996 if( size_avail >= size_needed ) {
8997#ifdef USE_MUNMAP
8998 if (!IS_MAPPED(hhdr)) {
8999 GC_adjust_num_unmapped(hbp, hhdr);
9000 GC_remap((ptr_t)hbp, (size_t)hhdr->hb_sz);
9001 hhdr -> hb_flags &= ~WAS_UNMAPPED;
9002 }
9003#endif
9004 hbp = GC_get_first_part(hbp, hhdr, size_needed, n);
9005 break;
9006 }
9007 }
9008 if (0 == hbp) return 0;
9009 if (!GC_install_counts(hbp, (word)size_needed)) return(0);
9010 if (!setup_header(hhdr, hbp, sz, kind, flags)) {
9011 GC_remove_counts(hbp, (word)size_needed);
9012 return(0);
9013 }
9014#ifndef GC_DISABLE_INCREMENTAL
9015 GC_ASSERT((size_needed & (HBLKSIZE-1)) == 0);
9016 GC_remove_protection(hbp, divHBLKSZ(size_needed),
9017 (hhdr -> hb_descr == 0) );
9018#endif
9019 GC_fail_count = 0;
9020 GC_large_free_bytes -= size_needed;
9021 GC_ASSERT(IS_MAPPED(hhdr));
9022 return( hbp );
9023}
9024GC_INNER void GC_freehblk(struct hblk *hbp)
9025{
9026 struct hblk *next, *prev;
9027 hdr *hhdr, *prevhdr, *nexthdr;
9028 word size;
9029 GET_HDR(hbp, hhdr);
9030 size = HBLKSIZE * OBJ_SZ_TO_BLOCKS(hhdr->hb_sz);
9031 if ((size & SIGNB) != 0)
9032 ABORT("Deallocating excessively large block. Too large an allocation?");
9033 GC_remove_counts(hbp, size);
9034 hhdr->hb_sz = size;
9035#ifdef USE_MUNMAP
9036 hhdr -> hb_last_reclaimed = (unsigned short)GC_gc_no;
9037#endif
9038 if (HBLK_IS_FREE(hhdr)) {
9039 ABORT_ARG1("Duplicate large block deallocation",
9040 " of %p", (void *)hbp);
9041 }
9042 GC_ASSERT(IS_MAPPED(hhdr));
9043 hhdr -> hb_flags |= FREE_BLK;
9044 next = (struct hblk *)((ptr_t)hbp + size);
9045 GET_HDR(next, nexthdr);
9046 prev = GC_free_block_ending_at(hbp);
9047 if(0 != nexthdr && HBLK_IS_FREE(nexthdr) && IS_MAPPED(nexthdr)
9048 && (signed_word)(hhdr -> hb_sz + nexthdr -> hb_sz) > 0
9049 ) {
9050 GC_remove_from_fl(nexthdr);
9051 hhdr -> hb_sz += nexthdr -> hb_sz;
9052 GC_remove_header(next);
9053 }
9054 if (prev ) {
9055 prevhdr = HDR(prev);
9056 if (IS_MAPPED(prevhdr)
9057 && (signed_word)(hhdr -> hb_sz + prevhdr -> hb_sz) > 0) {
9058 GC_remove_from_fl(prevhdr);
9059 prevhdr -> hb_sz += hhdr -> hb_sz;
9060#ifdef USE_MUNMAP
9061 prevhdr -> hb_last_reclaimed = (unsigned short)GC_gc_no;
9062#endif
9063 GC_remove_header(hbp);
9064 hbp = prev;
9065 hhdr = prevhdr;
9066 }
9067 }
9068 GC_large_free_bytes += size;
9069 GC_add_to_fl(hbp, hhdr);
9070}
9071#include <stdio.h>
9072#if !defined(MACOS) && !defined(MSWINCE)
9073#include <signal.h>
9074#if !defined(GC_NO_TYPES) && !defined(SN_TARGET_PSP2) \
9075 && !defined(__CC_ARM)
9076#include <sys/types.h>
9077#endif
9078#endif
9079word GC_non_gc_bytes = 0;
9080word GC_gc_no = 0;
9081#ifndef NO_CLOCK
9082 static unsigned long full_gc_total_time = 0;
9083 static unsigned full_gc_total_ns_frac = 0;
9084 static GC_bool measure_performance = FALSE;
9085 GC_API void GC_CALL GC_start_performance_measurement(void)
9086 {
9087 measure_performance = TRUE;
9088 }
9089 GC_API unsigned long GC_CALL GC_get_full_gc_total_time(void)
9090 {
9091 return full_gc_total_time;
9092 }
9093#endif
9094#ifndef GC_DISABLE_INCREMENTAL
9095 GC_INNER GC_bool GC_incremental = FALSE;
9096 STATIC GC_bool GC_should_start_incremental_collection = FALSE;
9097#endif
9098GC_API int GC_CALL GC_is_incremental_mode(void)
9099{
9100 return (int)GC_incremental;
9101}
9102#ifdef THREADS
9103 int GC_parallel = FALSE;
9104#endif
9105#if defined(GC_FULL_FREQ) && !defined(CPPCHECK)
9106 int GC_full_freq = GC_FULL_FREQ;
9107#else
9108 int GC_full_freq = 19;
9109#endif
9110STATIC GC_bool GC_need_full_gc = FALSE;
9111#ifdef THREAD_LOCAL_ALLOC
9112 GC_INNER GC_bool GC_world_stopped = FALSE;
9113#endif
9114STATIC GC_bool GC_disable_automatic_collection = FALSE;
9115GC_API void GC_CALL GC_set_disable_automatic_collection(int value)
9116{
9117 DCL_LOCK_STATE;
9118 LOCK();
9119 GC_disable_automatic_collection = (GC_bool)value;
9120 UNLOCK();
9121}
9122GC_API int GC_CALL GC_get_disable_automatic_collection(void)
9123{
9124 int value;
9125 DCL_LOCK_STATE;
9126 LOCK();
9127 value = (int)GC_disable_automatic_collection;
9128 UNLOCK();
9129 return value;
9130}
9131STATIC word GC_used_heap_size_after_full = 0;
9132EXTERN_C_BEGIN
9133extern const char * const GC_copyright[];
9134EXTERN_C_END
9135const char * const GC_copyright[] =
9136{"Copyright 1988, 1989 Hans-J. Boehm and Alan J. Demers ",
9137"Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved. ",
9138"Copyright (c) 1996-1998 by Silicon Graphics. All rights reserved. ",
9139"Copyright (c) 1999-2009 by Hewlett-Packard Company. All rights reserved. ",
9140"Copyright (c) 2008-2021 Ivan Maidanski ",
9141"THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY",
9142" EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.",
9143"See source code for details." };
9144#ifndef GC_NO_VERSION_VAR
9145 EXTERN_C_BEGIN
9146 extern const unsigned GC_version;
9147 EXTERN_C_END
9148 const unsigned GC_version = ((GC_VERSION_MAJOR << 16) |
9149 (GC_VERSION_MINOR << 8) | GC_VERSION_MICRO);
9150#endif
9151GC_API unsigned GC_CALL GC_get_version(void)
9152{
9153 return (GC_VERSION_MAJOR << 16) | (GC_VERSION_MINOR << 8) |
9154 GC_VERSION_MICRO;
9155}
9156#ifdef GC_DONT_EXPAND
9157 int GC_dont_expand = TRUE;
9158#else
9159 int GC_dont_expand = FALSE;
9160#endif
9161#if defined(GC_FREE_SPACE_DIVISOR) && !defined(CPPCHECK)
9162 word GC_free_space_divisor = GC_FREE_SPACE_DIVISOR;
9163#else
9164 word GC_free_space_divisor = 3;
9165#endif
9166GC_INNER int GC_CALLBACK GC_never_stop_func(void)
9167{
9168 return(0);
9169}
9170#if defined(GC_TIME_LIMIT) && !defined(CPPCHECK)
9171 unsigned long GC_time_limit = GC_TIME_LIMIT;
9172#elif defined(PARALLEL_MARK)
9173 unsigned long GC_time_limit = GC_TIME_UNLIMITED;
9174#else
9175 unsigned long GC_time_limit = 50;
9176#endif
9177#ifndef NO_CLOCK
9178 STATIC unsigned long GC_time_lim_nsec = 0;
9179#define TV_NSEC_LIMIT (1000UL * 1000)
9180 GC_API void GC_CALL GC_set_time_limit_tv(struct GC_timeval_s tv)
9181 {
9182 GC_ASSERT(tv.tv_ms <= GC_TIME_UNLIMITED);
9183 GC_ASSERT(tv.tv_nsec < TV_NSEC_LIMIT);
9184 GC_time_limit = tv.tv_ms;
9185 GC_time_lim_nsec = tv.tv_nsec;
9186 }
9187 GC_API struct GC_timeval_s GC_CALL GC_get_time_limit_tv(void)
9188 {
9189 struct GC_timeval_s tv;
9190 tv.tv_ms = GC_time_limit;
9191 tv.tv_nsec = GC_time_lim_nsec;
9192 return tv;
9193 }
9194 STATIC CLOCK_TYPE GC_start_time = CLOCK_TYPE_INITIALIZER;
9195#endif
9196STATIC int GC_n_attempts = 0;
9197STATIC GC_stop_func GC_default_stop_func = GC_never_stop_func;
9198GC_API void GC_CALL GC_set_stop_func(GC_stop_func stop_func)
9199{
9200 DCL_LOCK_STATE;
9201 GC_ASSERT(NONNULL_ARG_NOT_NULL(stop_func));
9202 LOCK();
9203 GC_default_stop_func = stop_func;
9204 UNLOCK();
9205}
9206GC_API GC_stop_func GC_CALL GC_get_stop_func(void)
9207{
9208 GC_stop_func stop_func;
9209 DCL_LOCK_STATE;
9210 LOCK();
9211 stop_func = GC_default_stop_func;
9212 UNLOCK();
9213 return stop_func;
9214}
9215#if defined(GC_DISABLE_INCREMENTAL) || defined(NO_CLOCK)
9216#define GC_timeout_stop_func GC_default_stop_func
9217#else
9218 STATIC int GC_CALLBACK GC_timeout_stop_func (void)
9219 {
9220 CLOCK_TYPE current_time;
9221 static unsigned count = 0;
9222 unsigned long time_diff, nsec_diff;
9223 if ((*GC_default_stop_func)())
9224 return(1);
9225 if ((count++ & 3) != 0) return(0);
9226 GET_TIME(current_time);
9227 time_diff = MS_TIME_DIFF(current_time,GC_start_time);
9228 nsec_diff = NS_FRAC_TIME_DIFF(current_time, GC_start_time);
9229#if defined(CPPCHECK)
9230 GC_noop1((word)&nsec_diff);
9231#endif
9232 if (time_diff >= GC_time_limit
9233 && (time_diff > GC_time_limit || nsec_diff >= GC_time_lim_nsec)) {
9234 GC_COND_LOG_PRINTF("Abandoning stopped marking after %lu ms %lu ns"
9235 " (attempt %d)\n",
9236 time_diff, nsec_diff, GC_n_attempts);
9237 return 1;
9238 }
9239 return(0);
9240 }
9241#endif
9242#ifdef THREADS
9243 GC_INNER word GC_total_stacksize = 0;
9244#endif
9245static size_t min_bytes_allocd_minimum = 1;
9246GC_API void GC_CALL GC_set_min_bytes_allocd(size_t value)
9247{
9248 GC_ASSERT(value > 0);
9249 min_bytes_allocd_minimum = value;
9250}
9251GC_API size_t GC_CALL GC_get_min_bytes_allocd(void)
9252{
9253 return min_bytes_allocd_minimum;
9254}
9255static word min_bytes_allocd(void)
9256{
9257 word result;
9258 word stack_size;
9259 word total_root_size;
9260 word scan_size;
9261#ifdef THREADS
9262 if (GC_need_to_lock) {
9263 stack_size = GC_total_stacksize;
9264#ifdef DEBUG_THREADS
9265 GC_log_printf("Total stacks size: %lu\n",
9266 (unsigned long)stack_size);
9267#endif
9268 } else
9269#endif
9270 {
9271#ifdef STACK_NOT_SCANNED
9272 stack_size = 0;
9273#elif defined(STACK_GROWS_UP)
9274 stack_size = GC_approx_sp() - GC_stackbottom;
9275#else
9276 stack_size = GC_stackbottom - GC_approx_sp();
9277#endif
9278 }
9279 total_root_size = 2 * stack_size + GC_root_size;
9280 scan_size = 2 * GC_composite_in_use + GC_atomic_in_use / 4
9281 + total_root_size;
9282 result = scan_size / GC_free_space_divisor;
9283 if (GC_incremental) {
9284 result /= 2;
9285 }
9286 return result > min_bytes_allocd_minimum
9287 ? result : min_bytes_allocd_minimum;
9288}
9289STATIC word GC_non_gc_bytes_at_gc = 0;
9290STATIC word GC_adj_bytes_allocd(void)
9291{
9292 signed_word result;
9293 signed_word expl_managed = (signed_word)GC_non_gc_bytes
9294 - (signed_word)GC_non_gc_bytes_at_gc;
9295 result = (signed_word)GC_bytes_allocd
9296 + (signed_word)GC_bytes_dropped
9297 - (signed_word)GC_bytes_freed
9298 + (signed_word)GC_finalizer_bytes_freed
9299 - expl_managed;
9300 if (result > (signed_word)GC_bytes_allocd) {
9301 result = GC_bytes_allocd;
9302 }
9303 result += GC_bytes_finalized;
9304 if (result < (signed_word)(GC_bytes_allocd >> 3)) {
9305 return(GC_bytes_allocd >> 3);
9306 } else {
9307 return(result);
9308 }
9309}
9310STATIC void GC_clear_a_few_frames(void)
9311{
9312#ifndef CLEAR_NWORDS
9313#define CLEAR_NWORDS 64
9314#endif
9315 volatile word frames[CLEAR_NWORDS];
9316 BZERO((word *)frames, CLEAR_NWORDS * sizeof(word));
9317}
9318STATIC word GC_collect_at_heapsize = GC_WORD_MAX;
9319GC_API void GC_CALL GC_start_incremental_collection(void)
9320{
9321#ifndef GC_DISABLE_INCREMENTAL
9322 DCL_LOCK_STATE;
9323 if (!GC_incremental) return;
9324 LOCK();
9325 GC_should_start_incremental_collection = TRUE;
9326 ENTER_GC();
9327 GC_collect_a_little_inner(1);
9328 EXIT_GC();
9329 UNLOCK();
9330#endif
9331}
9332GC_INNER GC_bool GC_should_collect(void)
9333{
9334 static word last_min_bytes_allocd;
9335 static word last_gc_no;
9336 GC_ASSERT(I_HOLD_LOCK());
9337 if (last_gc_no != GC_gc_no) {
9338 last_min_bytes_allocd = min_bytes_allocd();
9339 last_gc_no = GC_gc_no;
9340 }
9341#ifndef GC_DISABLE_INCREMENTAL
9342 if (GC_should_start_incremental_collection) {
9343 GC_should_start_incremental_collection = FALSE;
9344 return TRUE;
9345 }
9346#endif
9347 if (GC_disable_automatic_collection) return FALSE;
9348 return(GC_adj_bytes_allocd() >= last_min_bytes_allocd
9349 || GC_heapsize >= GC_collect_at_heapsize);
9350}
9351 GC_start_callback_proc GC_start_call_back = 0;
9352GC_API void GC_CALL GC_set_start_callback(GC_start_callback_proc fn)
9353{
9354 DCL_LOCK_STATE;
9355 LOCK();
9356 GC_start_call_back = fn;
9357 UNLOCK();
9358}
9359GC_API GC_start_callback_proc GC_CALL GC_get_start_callback(void)
9360{
9361 GC_start_callback_proc fn;
9362 DCL_LOCK_STATE;
9363 LOCK();
9364 fn = GC_start_call_back;
9365 UNLOCK();
9366 return fn;
9367}
9368GC_INLINE void GC_notify_full_gc(void)
9369{
9370 if (GC_start_call_back != 0) {
9371 (*GC_start_call_back)();
9372 }
9373}
9374STATIC GC_bool GC_is_full_gc = FALSE;
9375STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func);
9376STATIC void GC_finish_collection(void);
9377STATIC void GC_maybe_gc(void)
9378{
9379 GC_ASSERT(I_HOLD_LOCK());
9380 ASSERT_CANCEL_DISABLED();
9381 if (GC_should_collect()) {
9382 static int n_partial_gcs = 0;
9383 if (!GC_incremental) {
9384 GC_try_to_collect_inner(GC_never_stop_func);
9385 n_partial_gcs = 0;
9386 return;
9387 } else {
9388#ifdef PARALLEL_MARK
9389 if (GC_parallel)
9390 GC_wait_for_reclaim();
9391#endif
9392 if (GC_need_full_gc || n_partial_gcs >= GC_full_freq) {
9393 GC_COND_LOG_PRINTF(
9394 "***>Full mark for collection #%lu after %lu allocd bytes\n",
9395 (unsigned long)GC_gc_no + 1, (unsigned long)GC_bytes_allocd);
9396 GC_promote_black_lists();
9397 (void)GC_reclaim_all((GC_stop_func)0, TRUE);
9398 GC_notify_full_gc();
9399 GC_clear_marks();
9400 n_partial_gcs = 0;
9401 GC_is_full_gc = TRUE;
9402 } else {
9403 n_partial_gcs++;
9404 }
9405 }
9406#ifndef NO_CLOCK
9407 if (GC_time_limit != GC_TIME_UNLIMITED) { GET_TIME(GC_start_time); }
9408#endif
9409 if (GC_stopped_mark(GC_time_limit == GC_TIME_UNLIMITED?
9410 GC_never_stop_func : GC_timeout_stop_func)) {
9411#ifdef SAVE_CALL_CHAIN
9412 GC_save_callers(GC_last_stack);
9413#endif
9414 GC_finish_collection();
9415 } else {
9416 if (!GC_is_full_gc) {
9417 GC_n_attempts++;
9418 }
9419 }
9420 }
9421}
9422STATIC GC_on_collection_event_proc GC_on_collection_event = 0;
9423GC_API void GC_CALL GC_set_on_collection_event(GC_on_collection_event_proc fn)
9424{
9425 DCL_LOCK_STATE;
9426 LOCK();
9427 GC_on_collection_event = fn;
9428 UNLOCK();
9429}
9430GC_API GC_on_collection_event_proc GC_CALL GC_get_on_collection_event(void)
9431{
9432 GC_on_collection_event_proc fn;
9433 DCL_LOCK_STATE;
9434 LOCK();
9435 fn = GC_on_collection_event;
9436 UNLOCK();
9437 return fn;
9438}
9439GC_INNER GC_bool GC_try_to_collect_inner(GC_stop_func stop_func)
9440{
9441#ifndef NO_CLOCK
9442 CLOCK_TYPE start_time = CLOCK_TYPE_INITIALIZER;
9443 GC_bool start_time_valid;
9444#endif
9445 ASSERT_CANCEL_DISABLED();
9446 GC_ASSERT(I_HOLD_LOCK());
9447 if (GC_dont_gc || (*stop_func)()) return FALSE;
9448 if (GC_on_collection_event)
9449 GC_on_collection_event(GC_EVENT_START);
9450 if (GC_incremental && GC_collection_in_progress()) {
9451 GC_COND_LOG_PRINTF(
9452 "GC_try_to_collect_inner: finishing collection in progress\n");
9453 while(GC_collection_in_progress()) {
9454 if ((*stop_func)()) {
9455 return(FALSE);
9456 }
9457 ENTER_GC();
9458 GC_collect_a_little_inner(1);
9459 EXIT_GC();
9460 }
9461 }
9462 GC_notify_full_gc();
9463#ifndef NO_CLOCK
9464 start_time_valid = FALSE;
9465 if ((GC_print_stats | (int)measure_performance) != 0) {
9466 if (GC_print_stats)
9467 GC_log_printf("Initiating full world-stop collection!\n");
9468 start_time_valid = TRUE;
9469 GET_TIME(start_time);
9470 }
9471#endif
9472 GC_promote_black_lists();
9473#ifdef PARALLEL_MARK
9474 if (GC_parallel)
9475 GC_wait_for_reclaim();
9476#endif
9477 if ((GC_find_leak || stop_func != GC_never_stop_func)
9478 && !GC_reclaim_all(stop_func, FALSE)) {
9479 return(FALSE);
9480 }
9481 GC_invalidate_mark_state();
9482 GC_clear_marks();
9483#ifdef SAVE_CALL_CHAIN
9484 GC_save_callers(GC_last_stack);
9485#endif
9486 GC_is_full_gc = TRUE;
9487 if (!GC_stopped_mark(stop_func)) {
9488 if (!GC_incremental) {
9489 GC_invalidate_mark_state();
9490 GC_unpromote_black_lists();
9491 }
9492 return(FALSE);
9493 }
9494 GC_finish_collection();
9495#ifndef NO_CLOCK
9496 if (start_time_valid) {
9497 CLOCK_TYPE current_time;
9498 unsigned long time_diff, ns_frac_diff;
9499 GET_TIME(current_time);
9500 time_diff = MS_TIME_DIFF(current_time, start_time);
9501 ns_frac_diff = NS_FRAC_TIME_DIFF(current_time, start_time);
9502 if (measure_performance) {
9503 full_gc_total_time += time_diff;
9504 full_gc_total_ns_frac += (unsigned)ns_frac_diff;
9505 if (full_gc_total_ns_frac >= 1000000U) {
9506 full_gc_total_ns_frac -= 1000000U;
9507 full_gc_total_time++;
9508 }
9509 }
9510 if (GC_print_stats)
9511 GC_log_printf("Complete collection took %lu ms %lu ns\n",
9512 time_diff, ns_frac_diff);
9513 }
9514#endif
9515 if (GC_on_collection_event)
9516 GC_on_collection_event(GC_EVENT_END);
9517 return(TRUE);
9518}
9519#ifndef GC_RATE
9520#define GC_RATE 10
9521#endif
9522#ifndef MAX_PRIOR_ATTEMPTS
9523#define MAX_PRIOR_ATTEMPTS 1
9524#endif
9525STATIC int GC_deficit = 0;
9526STATIC int GC_rate = GC_RATE;
9527GC_API void GC_CALL GC_set_rate(int value)
9528{
9529 GC_ASSERT(value > 0);
9530 GC_rate = value;
9531}
9532GC_API int GC_CALL GC_get_rate(void)
9533{
9534 return GC_rate;
9535}
9536static int max_prior_attempts = MAX_PRIOR_ATTEMPTS;
9537GC_API void GC_CALL GC_set_max_prior_attempts(int value)
9538{
9539 GC_ASSERT(value >= 0);
9540 max_prior_attempts = value;
9541}
9542GC_API int GC_CALL GC_get_max_prior_attempts(void)
9543{
9544 return max_prior_attempts;
9545}
9546GC_INNER void GC_collect_a_little_inner(int n)
9547{
9548 IF_CANCEL(int cancel_state;)
9549 GC_ASSERT(I_HOLD_LOCK());
9550 if (GC_dont_gc) return;
9551 DISABLE_CANCEL(cancel_state);
9552 if (GC_incremental && GC_collection_in_progress()) {
9553 int i;
9554 int max_deficit = GC_rate * n;
9555#ifdef PARALLEL_MARK
9556 if (GC_time_limit != GC_TIME_UNLIMITED)
9557 GC_parallel_mark_disabled = TRUE;
9558#endif
9559 for (i = GC_deficit; i < max_deficit; i++) {
9560 if (GC_mark_some(NULL))
9561 break;
9562 }
9563#ifdef PARALLEL_MARK
9564 GC_parallel_mark_disabled = FALSE;
9565#endif
9566 if (i < max_deficit) {
9567#ifdef SAVE_CALL_CHAIN
9568 GC_save_callers(GC_last_stack);
9569#endif
9570#ifdef PARALLEL_MARK
9571 if (GC_parallel)
9572 GC_wait_for_reclaim();
9573#endif
9574 if (GC_n_attempts < max_prior_attempts
9575 && GC_time_limit != GC_TIME_UNLIMITED) {
9576#ifndef NO_CLOCK
9577 GET_TIME(GC_start_time);
9578#endif
9579 if (GC_stopped_mark(GC_timeout_stop_func)) {
9580 GC_finish_collection();
9581 } else {
9582 GC_n_attempts++;
9583 }
9584 } else {
9585 (void)GC_stopped_mark(GC_never_stop_func);
9586 GC_finish_collection();
9587 }
9588 }
9589 if (GC_deficit > 0) {
9590 GC_deficit -= max_deficit;
9591 if (GC_deficit < 0)
9592 GC_deficit = 0;
9593 }
9594 } else {
9595 GC_maybe_gc();
9596 }
9597 RESTORE_CANCEL(cancel_state);
9598}
9599GC_INNER void (*GC_check_heap)(void) = 0;
9600GC_INNER void (*GC_print_all_smashed)(void) = 0;
9601GC_API int GC_CALL GC_collect_a_little(void)
9602{
9603 int result;
9604 DCL_LOCK_STATE;
9605 LOCK();
9606 ENTER_GC();
9607 GC_collect_a_little_inner(1);
9608 EXIT_GC();
9609 result = (int)GC_collection_in_progress();
9610 UNLOCK();
9611 if (!result && GC_debugging_started) GC_print_all_smashed();
9612 return(result);
9613}
9614#ifndef NO_CLOCK
9615 static unsigned world_stopped_total_time = 0;
9616 static unsigned world_stopped_total_divisor = 0;
9617#ifndef MAX_TOTAL_TIME_DIVISOR
9618#define MAX_TOTAL_TIME_DIVISOR 1000
9619#endif
9620#endif
9621#ifdef USE_MUNMAP
9622#define IF_USE_MUNMAP(x) x
9623#define COMMA_IF_USE_MUNMAP(x) , x
9624#else
9625#define IF_USE_MUNMAP(x)
9626#define COMMA_IF_USE_MUNMAP(x)
9627#endif
9628STATIC GC_bool GC_stopped_mark(GC_stop_func stop_func)
9629{
9630 int i;
9631#ifndef NO_CLOCK
9632 CLOCK_TYPE start_time = CLOCK_TYPE_INITIALIZER;
9633#endif
9634 GC_ASSERT(I_HOLD_LOCK());
9635#if !defined(REDIRECT_MALLOC) && defined(USE_WINALLOC)
9636 GC_add_current_malloc_heap();
9637#endif
9638#if defined(REGISTER_LIBRARIES_EARLY)
9639 GC_cond_register_dynamic_libraries();
9640#endif
9641#ifndef NO_CLOCK
9642 if (GC_PRINT_STATS_FLAG)
9643 GET_TIME(start_time);
9644#endif
9645#if !defined(GC_NO_FINALIZATION) && !defined(GC_TOGGLE_REFS_NOT_NEEDED)
9646 GC_process_togglerefs();
9647#endif
9648#ifdef THREADS
9649 if (GC_on_collection_event)
9650 GC_on_collection_event(GC_EVENT_PRE_STOP_WORLD);
9651#endif
9652 STOP_WORLD();
9653#ifdef THREADS
9654 if (GC_on_collection_event)
9655 GC_on_collection_event(GC_EVENT_POST_STOP_WORLD);
9656#endif
9657#ifdef THREAD_LOCAL_ALLOC
9658 GC_world_stopped = TRUE;
9659#endif
9660 GC_COND_LOG_PRINTF(
9661 "\n--> Marking for collection #%lu after %lu allocated bytes\n",
9662 (unsigned long)GC_gc_no + 1, (unsigned long) GC_bytes_allocd);
9663#ifdef MAKE_BACK_GRAPH
9664 if (GC_print_back_height) {
9665 GC_build_back_graph();
9666 }
9667#endif
9668 if (GC_on_collection_event)
9669 GC_on_collection_event(GC_EVENT_MARK_START);
9670 GC_clear_a_few_frames();
9671 GC_noop6(0,0,0,0,0,0);
9672 GC_initiate_gc();
9673#ifdef PARALLEL_MARK
9674 if (stop_func != GC_never_stop_func)
9675 GC_parallel_mark_disabled = TRUE;
9676#endif
9677 for (i = 0; !(*stop_func)(); i++) {
9678 if (GC_mark_some(GC_approx_sp())) {
9679#ifdef PARALLEL_MARK
9680 if (GC_parallel && GC_parallel_mark_disabled) {
9681 GC_COND_LOG_PRINTF("Stopped marking done after %d iterations"
9682 " with disabled parallel marker\n", i);
9683 }
9684#endif
9685 i = -1;
9686 break;
9687 }
9688 }
9689#ifdef PARALLEL_MARK
9690 GC_parallel_mark_disabled = FALSE;
9691#endif
9692 if (i >= 0) {
9693 GC_COND_LOG_PRINTF("Abandoned stopped marking after"
9694 " %d iterations\n", i);
9695 GC_deficit = i;
9696#ifdef THREAD_LOCAL_ALLOC
9697 GC_world_stopped = FALSE;
9698#endif
9699#ifdef THREADS
9700 if (GC_on_collection_event)
9701 GC_on_collection_event(GC_EVENT_PRE_START_WORLD);
9702#endif
9703 START_WORLD();
9704#ifdef THREADS
9705 if (GC_on_collection_event)
9706 GC_on_collection_event(GC_EVENT_POST_START_WORLD);
9707#endif
9708 return FALSE;
9709 }
9710 GC_gc_no++;
9711#ifdef USE_MUNMAP
9712 GC_ASSERT(GC_heapsize >= GC_unmapped_bytes);
9713#endif
9714 GC_ASSERT(GC_our_mem_bytes >= GC_heapsize);
9715 GC_DBGLOG_PRINTF("GC #%lu freed %ld bytes, heap %lu KiB ("
9716 IF_USE_MUNMAP("+ %lu KiB unmapped ")
9717 "+ %lu KiB internal)\n",
9718 (unsigned long)GC_gc_no, (long)GC_bytes_found,
9719 TO_KiB_UL(GC_heapsize - GC_unmapped_bytes)
9720 COMMA_IF_USE_MUNMAP(TO_KiB_UL(GC_unmapped_bytes)),
9721 TO_KiB_UL(GC_our_mem_bytes - GC_heapsize));
9722 if (GC_debugging_started) {
9723 (*GC_check_heap)();
9724 }
9725 if (GC_on_collection_event) {
9726 GC_on_collection_event(GC_EVENT_MARK_END);
9727#ifdef THREADS
9728 GC_on_collection_event(GC_EVENT_PRE_START_WORLD);
9729#endif
9730 }
9731#ifdef THREAD_LOCAL_ALLOC
9732 GC_world_stopped = FALSE;
9733#endif
9734 START_WORLD();
9735#ifdef THREADS
9736 if (GC_on_collection_event)
9737 GC_on_collection_event(GC_EVENT_POST_START_WORLD);
9738#endif
9739#ifndef NO_CLOCK
9740 if (GC_PRINT_STATS_FLAG) {
9741 unsigned long time_diff;
9742 unsigned total_time, divisor;
9743 CLOCK_TYPE current_time;
9744 GET_TIME(current_time);
9745 time_diff = MS_TIME_DIFF(current_time,start_time);
9746 total_time = world_stopped_total_time;
9747 divisor = world_stopped_total_divisor;
9748 if ((int)total_time < 0 || divisor >= MAX_TOTAL_TIME_DIVISOR) {
9749 total_time >>= 1;
9750 divisor >>= 1;
9751 }
9752 total_time += time_diff < (((unsigned)-1) >> 1) ?
9753 (unsigned)time_diff : ((unsigned)-1) >> 1;
9754 world_stopped_total_time = total_time;
9755 world_stopped_total_divisor = ++divisor;
9756 GC_ASSERT(divisor != 0);
9757 GC_log_printf("World-stopped marking took %lu ms %lu ns"
9758 " (%u ms in average)\n",
9759 time_diff, NS_FRAC_TIME_DIFF(current_time, start_time),
9760 total_time / divisor);
9761 }
9762#endif
9763 return(TRUE);
9764}
9765GC_INNER void GC_set_fl_marks(ptr_t q)
9766{
9767 if (q ) {
9768 struct hblk *h = HBLKPTR(q);
9769 struct hblk *last_h = h;
9770 hdr *hhdr = HDR(h);
9771 IF_PER_OBJ(word sz = hhdr->hb_sz;)
9772 for (;;) {
9773 word bit_no = MARK_BIT_NO((ptr_t)q - (ptr_t)h, sz);
9774 if (!mark_bit_from_hdr(hhdr, bit_no)) {
9775 set_mark_bit_from_hdr(hhdr, bit_no);
9776 ++hhdr -> hb_n_marks;
9777 }
9778 q = (ptr_t)obj_link(q);
9779 if (q == NULL)
9780 break;
9781 h = HBLKPTR(q);
9782 if (h != last_h) {
9783 last_h = h;
9784 hhdr = HDR(h);
9785 IF_PER_OBJ(sz = hhdr->hb_sz;)
9786 }
9787 }
9788 }
9789}
9790#if defined(GC_ASSERTIONS) && defined(THREAD_LOCAL_ALLOC)
9791 void GC_check_fl_marks(void **pfreelist)
9792 {
9793#if defined(AO_HAVE_load_acquire_read) && !defined(THREAD_SANITIZER)
9794 AO_t *list = (AO_t *)AO_load_acquire_read((AO_t *)pfreelist);
9795 AO_t *prev;
9796 AO_t *p;
9797 if ((word)list <= HBLKSIZE) return;
9798 prev = (AO_t *)pfreelist;
9799 for (p = list; p != NULL;) {
9800 AO_t *next;
9801 if (!GC_is_marked(p)) {
9802 ABORT_ARG2("Unmarked local free list entry",
9803 ": object %p on list %p", (void *)p, (void *)list);
9804 }
9805 next = (AO_t *)AO_load_acquire_read(p);
9806 if (AO_load(prev) != (AO_t)p)
9807 break;
9808 prev = p;
9809 p = next;
9810 }
9811#else
9812 (void)pfreelist;
9813#endif
9814 }
9815#endif
9816STATIC void GC_clear_fl_marks(ptr_t q)
9817{
9818 struct hblk *h = HBLKPTR(q);
9819 struct hblk *last_h = h;
9820 hdr *hhdr = HDR(h);
9821 word sz = hhdr->hb_sz;
9822 for (;;) {
9823 word bit_no = MARK_BIT_NO((ptr_t)q - (ptr_t)h, sz);
9824 if (mark_bit_from_hdr(hhdr, bit_no)) {
9825 size_t n_marks = hhdr -> hb_n_marks;
9826 GC_ASSERT(n_marks != 0);
9827 clear_mark_bit_from_hdr(hhdr, bit_no);
9828 n_marks--;
9829#ifdef PARALLEL_MARK
9830 if (0 != n_marks || !GC_parallel) {
9831 hhdr -> hb_n_marks = n_marks;
9832 }
9833#else
9834 hhdr -> hb_n_marks = n_marks;
9835#endif
9836 }
9837 GC_bytes_found -= sz;
9838 q = (ptr_t)obj_link(q);
9839 if (q == NULL)
9840 break;
9841 h = HBLKPTR(q);
9842 if (h != last_h) {
9843 last_h = h;
9844 hhdr = HDR(h);
9845 sz = hhdr->hb_sz;
9846 }
9847 }
9848}
9849#if defined(GC_ASSERTIONS) && defined(THREAD_LOCAL_ALLOC)
9850 void GC_check_tls(void);
9851#endif
9852GC_on_heap_resize_proc GC_on_heap_resize = 0;
9853GC_INLINE int GC_compute_heap_usage_percent(void)
9854{
9855 word used = GC_composite_in_use + GC_atomic_in_use;
9856 word heap_sz = GC_heapsize - GC_unmapped_bytes;
9857#if defined(CPPCHECK)
9858 word limit = (GC_WORD_MAX >> 1) / 50;
9859#else
9860 const word limit = GC_WORD_MAX / 100;
9861#endif
9862 return used >= heap_sz ? 0 : used < limit ?
9863 (int)((used * 100) / heap_sz) : (int)(used / (heap_sz / 100));
9864}
9865STATIC void GC_finish_collection(void)
9866{
9867#ifndef NO_CLOCK
9868 CLOCK_TYPE start_time = CLOCK_TYPE_INITIALIZER;
9869 CLOCK_TYPE finalize_time = CLOCK_TYPE_INITIALIZER;
9870#endif
9871 GC_ASSERT(I_HOLD_LOCK());
9872#if defined(GC_ASSERTIONS) \
9873 && defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
9874 GC_check_tls();
9875#endif
9876#ifndef NO_CLOCK
9877 if (GC_print_stats)
9878 GET_TIME(start_time);
9879#endif
9880 if (GC_on_collection_event)
9881 GC_on_collection_event(GC_EVENT_RECLAIM_START);
9882#ifndef GC_GET_HEAP_USAGE_NOT_NEEDED
9883 if (GC_bytes_found > 0)
9884 GC_reclaimed_bytes_before_gc += (word)GC_bytes_found;
9885#endif
9886 GC_bytes_found = 0;
9887#if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG)
9888 if (GETENV("GC_PRINT_ADDRESS_MAP") != 0) {
9889 GC_print_address_map();
9890 }
9891#endif
9892 COND_DUMP;
9893 if (GC_find_leak) {
9894 word size;
9895 unsigned kind;
9896 ptr_t q;
9897 for (kind = 0; kind < GC_n_kinds; kind++) {
9898 for (size = 1; size <= MAXOBJGRANULES; size++) {
9899 q = (ptr_t)GC_obj_kinds[kind].ok_freelist[size];
9900 if (q != NULL)
9901 GC_set_fl_marks(q);
9902 }
9903 }
9904 GC_start_reclaim(TRUE);
9905 }
9906#ifndef GC_NO_FINALIZATION
9907 GC_finalize();
9908#endif
9909#ifndef NO_CLOCK
9910 if (GC_print_stats)
9911 GET_TIME(finalize_time);
9912#endif
9913 if (GC_print_back_height) {
9914#ifdef MAKE_BACK_GRAPH
9915 GC_traverse_back_graph();
9916#elif !defined(SMALL_CONFIG)
9917 GC_err_printf("Back height not available: "
9918 "Rebuild collector with -DMAKE_BACK_GRAPH\n");
9919#endif
9920 }
9921 {
9922 word size;
9923 ptr_t q;
9924 unsigned kind;
9925 for (kind = 0; kind < GC_n_kinds; kind++) {
9926 for (size = 1; size <= MAXOBJGRANULES; size++) {
9927 q = (ptr_t)GC_obj_kinds[kind].ok_freelist[size];
9928 if (q != NULL)
9929 GC_clear_fl_marks(q);
9930 }
9931 }
9932 }
9933 GC_VERBOSE_LOG_PRINTF("Bytes recovered before sweep - f.l. count = %ld\n",
9934 (long)GC_bytes_found);
9935 GC_start_reclaim(FALSE);
9936 GC_DBGLOG_PRINTF("In-use heap: %d%% (%lu KiB pointers + %lu KiB other)\n",
9937 GC_compute_heap_usage_percent(),
9938 TO_KiB_UL(GC_composite_in_use),
9939 TO_KiB_UL(GC_atomic_in_use));
9940 if (GC_is_full_gc) {
9941 GC_used_heap_size_after_full = USED_HEAP_SIZE;
9942 GC_need_full_gc = FALSE;
9943 } else {
9944 GC_need_full_gc = USED_HEAP_SIZE - GC_used_heap_size_after_full
9945 > min_bytes_allocd();
9946 }
9947 GC_VERBOSE_LOG_PRINTF("Immediately reclaimed %ld bytes, heapsize:"
9948 " %lu bytes" IF_USE_MUNMAP(" (%lu unmapped)") "\n",
9949 (long)GC_bytes_found,
9950 (unsigned long)GC_heapsize
9951 COMMA_IF_USE_MUNMAP((unsigned long)
9952 GC_unmapped_bytes));
9953 GC_n_attempts = 0;
9954 GC_is_full_gc = FALSE;
9955 GC_bytes_allocd_before_gc += GC_bytes_allocd;
9956 GC_non_gc_bytes_at_gc = GC_non_gc_bytes;
9957 GC_bytes_allocd = 0;
9958 GC_bytes_dropped = 0;
9959 GC_bytes_freed = 0;
9960 GC_finalizer_bytes_freed = 0;
9961 IF_USE_MUNMAP(GC_unmap_old());
9962 if (GC_on_collection_event)
9963 GC_on_collection_event(GC_EVENT_RECLAIM_END);
9964#ifndef NO_CLOCK
9965 if (GC_print_stats) {
9966 CLOCK_TYPE done_time;
9967 GET_TIME(done_time);
9968#if !defined(SMALL_CONFIG) && !defined(GC_NO_FINALIZATION)
9969 GC_print_finalization_stats();
9970#endif
9971 GC_log_printf("Finalize and initiate sweep took %lu ms %lu ns"
9972 " + %lu ms %lu ns\n",
9973 MS_TIME_DIFF(finalize_time, start_time),
9974 NS_FRAC_TIME_DIFF(finalize_time, start_time),
9975 MS_TIME_DIFF(done_time, finalize_time),
9976 NS_FRAC_TIME_DIFF(done_time, finalize_time));
9977 }
9978#elif !defined(SMALL_CONFIG) && !defined(GC_NO_FINALIZATION)
9979 if (GC_print_stats)
9980 GC_print_finalization_stats();
9981#endif
9982}
9983STATIC GC_bool GC_try_to_collect_general(GC_stop_func stop_func,
9984 GC_bool force_unmap GC_ATTR_UNUSED)
9985{
9986 GC_bool result;
9987 IF_USE_MUNMAP(int old_unmap_threshold;)
9988 IF_CANCEL(int cancel_state;)
9989 DCL_LOCK_STATE;
9990 if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
9991 if (GC_debugging_started) GC_print_all_smashed();
9992 GC_INVOKE_FINALIZERS();
9993 LOCK();
9994 DISABLE_CANCEL(cancel_state);
9995#ifdef USE_MUNMAP
9996 old_unmap_threshold = GC_unmap_threshold;
9997 if (force_unmap ||
9998 (GC_force_unmap_on_gcollect && old_unmap_threshold > 0))
9999 GC_unmap_threshold = 1;
10000#endif
10001 ENTER_GC();
10002 GC_noop6(0,0,0,0,0,0);
10003 result = GC_try_to_collect_inner(stop_func != 0 ? stop_func :
10004 GC_default_stop_func);
10005 EXIT_GC();
10006 IF_USE_MUNMAP(GC_unmap_threshold = old_unmap_threshold);
10007 RESTORE_CANCEL(cancel_state);
10008 UNLOCK();
10009 if (result) {
10010 if (GC_debugging_started) GC_print_all_smashed();
10011 GC_INVOKE_FINALIZERS();
10012 }
10013 return(result);
10014}
10015GC_API int GC_CALL GC_try_to_collect(GC_stop_func stop_func)
10016{
10017 GC_ASSERT(NONNULL_ARG_NOT_NULL(stop_func));
10018 return (int)GC_try_to_collect_general(stop_func, FALSE);
10019}
10020GC_API void GC_CALL GC_gcollect(void)
10021{
10022 (void)GC_try_to_collect_general(0, FALSE);
10023 if (GC_have_errors) GC_print_all_errors();
10024}
10025STATIC word GC_heapsize_at_forced_unmap = 0;
10026GC_API void GC_CALL GC_gcollect_and_unmap(void)
10027{
10028 GC_heapsize_at_forced_unmap = GC_heapsize;
10029 (void)GC_try_to_collect_general(GC_never_stop_func, TRUE);
10030}
10031#ifdef USE_PROC_FOR_LIBRARIES
10032 GC_INNER void GC_add_to_our_memory(ptr_t p, size_t bytes)
10033 {
10034 GC_ASSERT(p != NULL);
10035 if (GC_n_memory >= MAX_HEAP_SECTS)
10036 ABORT("Too many GC-allocated memory sections: Increase MAX_HEAP_SECTS");
10037 GC_our_memory[GC_n_memory].hs_start = p;
10038 GC_our_memory[GC_n_memory].hs_bytes = bytes;
10039 GC_n_memory++;
10040 GC_our_mem_bytes += bytes;
10041 }
10042#endif
10043STATIC void GC_add_to_heap(struct hblk *p, size_t bytes)
10044{
10045 hdr * phdr;
10046 word endp;
10047 size_t old_capacity = 0;
10048 void *old_heap_sects = NULL;
10049#ifdef GC_ASSERTIONS
10050 unsigned i;
10051#endif
10052 GC_ASSERT((word)p % HBLKSIZE == 0);
10053 GC_ASSERT(bytes % HBLKSIZE == 0);
10054 GC_ASSERT(bytes > 0);
10055 GC_ASSERT(GC_all_nils != NULL);
10056 if (GC_n_heap_sects == GC_capacity_heap_sects) {
10057#ifndef INITIAL_HEAP_SECTS
10058#define INITIAL_HEAP_SECTS 32
10059#endif
10060 size_t new_capacity = GC_n_heap_sects > 0 ?
10061 (size_t)GC_n_heap_sects * 2 : INITIAL_HEAP_SECTS;
10062 void *new_heap_sects =
10063 GC_scratch_alloc(new_capacity * sizeof(struct HeapSect));
10064 if (EXPECT(NULL == new_heap_sects, FALSE)) {
10065 new_capacity = (size_t)GC_n_heap_sects + INITIAL_HEAP_SECTS;
10066 new_heap_sects =
10067 GC_scratch_alloc(new_capacity * sizeof(struct HeapSect));
10068 if (NULL == new_heap_sects)
10069 ABORT("Insufficient memory for heap sections");
10070 }
10071 old_capacity = GC_capacity_heap_sects;
10072 old_heap_sects = GC_heap_sects;
10073 if (GC_n_heap_sects > 0)
10074 BCOPY(old_heap_sects, new_heap_sects,
10075 GC_n_heap_sects * sizeof(struct HeapSect));
10076 GC_capacity_heap_sects = new_capacity;
10077 GC_heap_sects = (struct HeapSect *)new_heap_sects;
10078 GC_COND_LOG_PRINTF("Grew heap sections array to %lu elements\n",
10079 (unsigned long)new_capacity);
10080 }
10081 while ((word)p <= HBLKSIZE) {
10082 ++p;
10083 bytes -= HBLKSIZE;
10084 if (0 == bytes) return;
10085 }
10086 endp = (word)p + bytes;
10087 if (endp <= (word)p) {
10088 bytes -= HBLKSIZE;
10089 if (0 == bytes) return;
10090 endp -= HBLKSIZE;
10091 }
10092 phdr = GC_install_header(p);
10093 if (0 == phdr) {
10094 return;
10095 }
10096 GC_ASSERT(endp > (word)p && endp == (word)p + bytes);
10097#ifdef GC_ASSERTIONS
10098 for (i = 0; i < GC_n_heap_sects; i++) {
10099 word hs_start = (word)GC_heap_sects[i].hs_start;
10100 word hs_end = hs_start + GC_heap_sects[i].hs_bytes;
10101 word p_e = (word)p + bytes;
10102 GC_ASSERT(!((hs_start <= (word)p && (word)p < hs_end)
10103 || (hs_start < p_e && p_e <= hs_end)
10104 || ((word)p < hs_start && hs_end < p_e)));
10105 }
10106#endif
10107 GC_heap_sects[GC_n_heap_sects].hs_start = (ptr_t)p;
10108 GC_heap_sects[GC_n_heap_sects].hs_bytes = bytes;
10109 GC_n_heap_sects++;
10110 phdr -> hb_sz = bytes;
10111 phdr -> hb_flags = 0;
10112 GC_freehblk(p);
10113 GC_heapsize += bytes;
10114 GC_collect_at_heapsize += bytes;
10115 if (GC_collect_at_heapsize < GC_heapsize )
10116 GC_collect_at_heapsize = GC_WORD_MAX;
10117 if ((word)p <= (word)GC_least_plausible_heap_addr
10118 || GC_least_plausible_heap_addr == 0) {
10119 GC_least_plausible_heap_addr = (void *)((ptr_t)p - sizeof(word));
10120 }
10121 if ((word)p + bytes >= (word)GC_greatest_plausible_heap_addr) {
10122 GC_greatest_plausible_heap_addr = (void *)endp;
10123 }
10124 if (old_capacity > 0) {
10125#ifndef GWW_VDB
10126 GC_scratch_recycle_no_gww(old_heap_sects,
10127 old_capacity * sizeof(struct HeapSect));
10128#else
10129 GC_noop1((word)old_heap_sects);
10130#endif
10131 }
10132}
10133#if !defined(NO_DEBUGGING)
10134 void GC_print_heap_sects(void)
10135 {
10136 unsigned i;
10137 GC_printf("Total heap size: %lu" IF_USE_MUNMAP(" (%lu unmapped)") "\n",
10138 (unsigned long)GC_heapsize
10139 COMMA_IF_USE_MUNMAP((unsigned long)GC_unmapped_bytes));
10140 for (i = 0; i < GC_n_heap_sects; i++) {
10141 ptr_t start = GC_heap_sects[i].hs_start;
10142 size_t len = GC_heap_sects[i].hs_bytes;
10143 struct hblk *h;
10144 unsigned nbl = 0;
10145 for (h = (struct hblk *)start; (word)h < (word)(start + len); h++) {
10146 if (GC_is_black_listed(h, HBLKSIZE)) nbl++;
10147 }
10148 GC_printf("Section %d from %p to %p %u/%lu blacklisted\n",
10149 i, (void *)start, (void *)&start[len],
10150 nbl, (unsigned long)divHBLKSZ(len));
10151 }
10152 }
10153#endif
10154void * GC_least_plausible_heap_addr = (void *)GC_WORD_MAX;
10155void * GC_greatest_plausible_heap_addr = 0;
10156GC_INLINE word GC_max(word x, word y)
10157{
10158 return(x > y? x : y);
10159}
10160GC_INLINE word GC_min(word x, word y)
10161{
10162 return(x < y? x : y);
10163}
10164STATIC word GC_max_heapsize = 0;
10165GC_API void GC_CALL GC_set_max_heap_size(GC_word n)
10166{
10167 GC_max_heapsize = n;
10168}
10169GC_word GC_max_retries = 0;
10170GC_INNER void GC_scratch_recycle_inner(void *ptr, size_t bytes)
10171{
10172 size_t page_offset;
10173 size_t displ = 0;
10174 size_t recycled_bytes;
10175 if (NULL == ptr) return;
10176 GC_ASSERT(bytes != 0);
10177 GC_ASSERT(GC_page_size != 0);
10178 page_offset = (word)ptr & (GC_page_size - 1);
10179 if (page_offset != 0)
10180 displ = GC_page_size - page_offset;
10181 recycled_bytes = bytes > displ ? (bytes - displ) & ~(GC_page_size - 1) : 0;
10182 GC_COND_LOG_PRINTF("Recycle %lu/%lu scratch-allocated bytes at %p\n",
10183 (unsigned long)recycled_bytes, (unsigned long)bytes, ptr);
10184 if (recycled_bytes > 0)
10185 GC_add_to_heap((struct hblk *)((word)ptr + displ), recycled_bytes);
10186}
10187GC_INNER GC_bool GC_expand_hp_inner(word n)
10188{
10189 size_t bytes;
10190 struct hblk * space;
10191 word expansion_slop;
10192 GC_ASSERT(I_HOLD_LOCK());
10193 GC_ASSERT(GC_page_size != 0);
10194 if (n < MINHINCR) n = MINHINCR;
10195 bytes = ROUNDUP_PAGESIZE((size_t)n * HBLKSIZE);
10196 if (GC_max_heapsize != 0
10197 && (GC_max_heapsize < (word)bytes
10198 || GC_heapsize > GC_max_heapsize - (word)bytes)) {
10199 return(FALSE);
10200 }
10201 space = GET_MEM(bytes);
10202 if (EXPECT(NULL == space, FALSE)) {
10203 WARN("Failed to expand heap by %" WARN_PRIdPTR " bytes\n",
10204 (word)bytes);
10205 return(FALSE);
10206 }
10207 GC_add_to_our_memory((ptr_t)space, bytes);
10208 GC_INFOLOG_PRINTF("Grow heap to %lu KiB after %lu bytes allocated\n",
10209 TO_KiB_UL(GC_heapsize + (word)bytes),
10210 (unsigned long)GC_bytes_allocd);
10211 expansion_slop = min_bytes_allocd() + 4 * MAXHINCR * HBLKSIZE;
10212 if ((GC_last_heap_addr == 0 && !((word)space & SIGNB))
10213 || (GC_last_heap_addr != 0
10214 && (word)GC_last_heap_addr < (word)space)) {
10215 word new_limit = (word)space + (word)bytes + expansion_slop;
10216 if (new_limit > (word)space) {
10217 GC_greatest_plausible_heap_addr =
10218 (void *)GC_max((word)GC_greatest_plausible_heap_addr,
10219 (word)new_limit);
10220 }
10221 } else {
10222 word new_limit = (word)space - expansion_slop;
10223 if (new_limit < (word)space) {
10224 GC_least_plausible_heap_addr =
10225 (void *)GC_min((word)GC_least_plausible_heap_addr,
10226 (word)space - expansion_slop);
10227 }
10228 }
10229 GC_last_heap_addr = (ptr_t)space;
10230 GC_add_to_heap(space, bytes);
10231 GC_collect_at_heapsize =
10232 GC_heapsize + expansion_slop - 2 * MAXHINCR * HBLKSIZE;
10233 if (GC_collect_at_heapsize < GC_heapsize )
10234 GC_collect_at_heapsize = GC_WORD_MAX;
10235 if (GC_on_heap_resize)
10236 (*GC_on_heap_resize)(GC_heapsize);
10237 return(TRUE);
10238}
10239GC_API int GC_CALL GC_expand_hp(size_t bytes)
10240{
10241 int result;
10242 DCL_LOCK_STATE;
10243 if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
10244 LOCK();
10245 result = (int)GC_expand_hp_inner(divHBLKSZ((word)bytes));
10246 if (result) GC_requested_heapsize += bytes;
10247 UNLOCK();
10248 return(result);
10249}
10250GC_INNER unsigned GC_fail_count = 0;
10251#if defined(GC_ALLOCD_BYTES_PER_FINALIZER) && !defined(CPPCHECK)
10252 STATIC word GC_allocd_bytes_per_finalizer = GC_ALLOCD_BYTES_PER_FINALIZER;
10253#else
10254 STATIC word GC_allocd_bytes_per_finalizer = 10000;
10255#endif
10256GC_API void GC_CALL GC_set_allocd_bytes_per_finalizer(GC_word value)
10257{
10258 GC_allocd_bytes_per_finalizer = value;
10259}
10260GC_API GC_word GC_CALL GC_get_allocd_bytes_per_finalizer(void)
10261{
10262 return GC_allocd_bytes_per_finalizer;
10263}
10264static word last_fo_entries = 0;
10265static word last_bytes_finalized = 0;
10266GC_INNER GC_bool GC_collect_or_expand(word needed_blocks,
10267 GC_bool ignore_off_page,
10268 GC_bool retry)
10269{
10270 GC_bool gc_not_stopped = TRUE;
10271 word blocks_to_get;
10272 IF_CANCEL(int cancel_state;)
10273 GC_ASSERT(I_HOLD_LOCK());
10274 DISABLE_CANCEL(cancel_state);
10275 if (!GC_incremental && !GC_dont_gc &&
10276 ((GC_dont_expand && GC_bytes_allocd > 0)
10277 || (GC_fo_entries > last_fo_entries
10278 && (last_bytes_finalized | GC_bytes_finalized) != 0
10279 && (GC_fo_entries - last_fo_entries)
10280 * GC_allocd_bytes_per_finalizer > GC_bytes_allocd)
10281 || GC_should_collect())) {
10282 gc_not_stopped = GC_try_to_collect_inner(
10283 GC_bytes_allocd > 0 && (!GC_dont_expand || !retry) ?
10284 GC_default_stop_func : GC_never_stop_func);
10285 if (gc_not_stopped == TRUE || !retry) {
10286 last_fo_entries = GC_fo_entries;
10287 last_bytes_finalized = GC_bytes_finalized;
10288 RESTORE_CANCEL(cancel_state);
10289 return(TRUE);
10290 }
10291 }
10292 blocks_to_get = (GC_heapsize - GC_heapsize_at_forced_unmap)
10293 / (HBLKSIZE * GC_free_space_divisor)
10294 + needed_blocks;
10295 if (blocks_to_get > MAXHINCR) {
10296 word slop;
10297 if (ignore_off_page) {
10298 slop = 4;
10299 } else {
10300 slop = 2 * divHBLKSZ(BL_LIMIT);
10301 if (slop > needed_blocks) slop = needed_blocks;
10302 }
10303 if (needed_blocks + slop > MAXHINCR) {
10304 blocks_to_get = needed_blocks + slop;
10305 } else {
10306 blocks_to_get = MAXHINCR;
10307 }
10308 if (blocks_to_get > divHBLKSZ(GC_WORD_MAX))
10309 blocks_to_get = divHBLKSZ(GC_WORD_MAX);
10310 }
10311 if (!GC_expand_hp_inner(blocks_to_get)
10312 && (blocks_to_get == needed_blocks
10313 || !GC_expand_hp_inner(needed_blocks))) {
10314 if (gc_not_stopped == FALSE) {
10315 GC_gcollect_inner();
10316 GC_ASSERT(GC_bytes_allocd == 0);
10317 } else if (GC_fail_count++ < GC_max_retries) {
10318 WARN("Out of Memory! Trying to continue...\n", 0);
10319 GC_gcollect_inner();
10320 } else {
10321#if !defined(AMIGA) || !defined(GC_AMIGA_FASTALLOC)
10322 WARN("Out of Memory! Heap size: %" WARN_PRIdPTR " MiB."
10323 " Returning NULL!\n", (GC_heapsize - GC_unmapped_bytes) >> 20);
10324#endif
10325 RESTORE_CANCEL(cancel_state);
10326 return(FALSE);
10327 }
10328 } else if (GC_fail_count) {
10329 GC_COND_LOG_PRINTF("Memory available again...\n");
10330 }
10331 RESTORE_CANCEL(cancel_state);
10332 return(TRUE);
10333}
10334GC_INNER ptr_t GC_allocobj(size_t gran, int kind)
10335{
10336 void ** flh = &(GC_obj_kinds[kind].ok_freelist[gran]);
10337 GC_bool tried_minor = FALSE;
10338 GC_bool retry = FALSE;
10339 GC_ASSERT(I_HOLD_LOCK());
10340 if (gran == 0) return(0);
10341 while (*flh == 0) {
10342 ENTER_GC();
10343#ifndef GC_DISABLE_INCREMENTAL
10344 if (GC_incremental && GC_time_limit != GC_TIME_UNLIMITED) {
10345 GC_collect_a_little_inner(1);
10346 }
10347#endif
10348 GC_ASSERT(!GC_is_full_gc
10349 || NULL == GC_obj_kinds[kind].ok_reclaim_list
10350 || NULL == GC_obj_kinds[kind].ok_reclaim_list[gran]);
10351 GC_continue_reclaim(gran, kind);
10352 EXIT_GC();
10353#if defined(CPPCHECK)
10354 GC_noop1((word)&flh);
10355#endif
10356 if (NULL == *flh) {
10357 GC_new_hblk(gran, kind);
10358#if defined(CPPCHECK)
10359 GC_noop1((word)&flh);
10360#endif
10361 if (NULL == *flh) {
10362 ENTER_GC();
10363 if (GC_incremental && GC_time_limit == GC_TIME_UNLIMITED
10364 && !tried_minor) {
10365 GC_collect_a_little_inner(1);
10366 tried_minor = TRUE;
10367 } else {
10368 if (!GC_collect_or_expand(1, FALSE, retry)) {
10369 EXIT_GC();
10370 return(0);
10371 }
10372 retry = TRUE;
10373 }
10374 EXIT_GC();
10375 }
10376 }
10377 }
10378 GC_fail_count = 0;
10379 return (ptr_t)(*flh);
10380}
10381#ifndef MSWINCE
10382#include <errno.h>
10383#endif
10384#include <string.h>
10385#ifndef SHORT_DBG_HDRS
10386 GC_INNER int GC_has_other_debug_info(ptr_t p)
10387 {
10388 ptr_t body = (ptr_t)((oh *)p + 1);
10389 word sz = GC_size(p);
10390 if (HBLKPTR(p) != HBLKPTR((ptr_t)body)
10391 || sz < DEBUG_BYTES + EXTRA_BYTES) {
10392 return 0;
10393 }
10394 if (((oh *)p) -> oh_sf != (START_FLAG ^ (word)body)
10395 && ((word *)p)[BYTES_TO_WORDS(sz)-1] != (END_FLAG ^ (word)body)) {
10396 return 0;
10397 }
10398 if (((oh *)p)->oh_sz == sz) {
10399 return -1;
10400 }
10401 return 1;
10402 }
10403#endif
10404#ifdef LINT2
10405 long GC_random(void)
10406 {
10407 static unsigned seed = 1;
10408 seed = (seed * 1103515245U + 12345) & GC_RAND_MAX;
10409 return (long)seed;
10410 }
10411#endif
10412#ifdef KEEP_BACK_PTRS
10413#ifdef LINT2
10414#define RANDOM() GC_random()
10415#else
10416#include <stdlib.h>
10417#define GC_RAND_MAX RAND_MAX
10418#if defined(__GLIBC__) || defined(SOLARIS) \
10419 || defined(HPUX) || defined(IRIX5) || defined(OSF1)
10420#define RANDOM() random()
10421#else
10422#define RANDOM() (long)rand()
10423#endif
10424#endif
10425 GC_INNER void GC_store_back_pointer(ptr_t source, ptr_t dest)
10426 {
10427 if (GC_HAS_DEBUG_INFO(dest)) {
10428#ifdef PARALLEL_MARK
10429 AO_store((volatile AO_t *)&((oh *)dest)->oh_back_ptr,
10430 (AO_t)HIDE_BACK_PTR(source));
10431#else
10432 ((oh *)dest) -> oh_back_ptr = HIDE_BACK_PTR(source);
10433#endif
10434 }
10435 }
10436 GC_INNER void GC_marked_for_finalization(ptr_t dest)
10437 {
10438 GC_store_back_pointer(MARKED_FOR_FINALIZATION, dest);
10439 }
10440 GC_API GC_ref_kind GC_CALL GC_get_back_ptr_info(void *dest, void **base_p,
10441 size_t *offset_p)
10442 {
10443 oh * hdr = (oh *)GC_base(dest);
10444 ptr_t bp;
10445 ptr_t bp_base;
10446#ifdef LINT2
10447 if (!hdr) ABORT("Invalid GC_get_back_ptr_info argument");
10448#endif
10449 if (!GC_HAS_DEBUG_INFO((ptr_t) hdr)) return GC_NO_SPACE;
10450 bp = (ptr_t)GC_REVEAL_POINTER(hdr -> oh_back_ptr);
10451 if (MARKED_FOR_FINALIZATION == bp) return GC_FINALIZER_REFD;
10452 if (MARKED_FROM_REGISTER == bp) return GC_REFD_FROM_REG;
10453 if (NOT_MARKED == bp) return GC_UNREFERENCED;
10454#if ALIGNMENT == 1
10455 {
10456 ptr_t alternate_ptr = bp + 1;
10457 ptr_t target = *(ptr_t *)bp;
10458 ptr_t alternate_target = *(ptr_t *)alternate_ptr;
10459 if ((word)alternate_target >= (word)GC_least_plausible_heap_addr
10460 && (word)alternate_target <= (word)GC_greatest_plausible_heap_addr
10461 && ((word)target < (word)GC_least_plausible_heap_addr
10462 || (word)target > (word)GC_greatest_plausible_heap_addr)) {
10463 bp = alternate_ptr;
10464 }
10465 }
10466#endif
10467 bp_base = (ptr_t)GC_base(bp);
10468 if (NULL == bp_base) {
10469 *base_p = bp;
10470 *offset_p = 0;
10471 return GC_REFD_FROM_ROOT;
10472 } else {
10473 if (GC_HAS_DEBUG_INFO(bp_base)) bp_base += sizeof(oh);
10474 *base_p = bp_base;
10475 *offset_p = bp - bp_base;
10476 return GC_REFD_FROM_HEAP;
10477 }
10478 }
10479 GC_API void * GC_CALL GC_generate_random_heap_address(void)
10480 {
10481 size_t i;
10482 word heap_offset = RANDOM();
10483 if (GC_heapsize > GC_RAND_MAX) {
10484 heap_offset *= GC_RAND_MAX;
10485 heap_offset += RANDOM();
10486 }
10487 heap_offset %= GC_heapsize;
10488 for (i = 0;; ++i) {
10489 size_t size;
10490 if (i >= GC_n_heap_sects)
10491 ABORT("GC_generate_random_heap_address: size inconsistency");
10492 size = GC_heap_sects[i].hs_bytes;
10493 if (heap_offset < size) {
10494 break;
10495 } else {
10496 heap_offset -= size;
10497 }
10498 }
10499 return GC_heap_sects[i].hs_start + heap_offset;
10500 }
10501 GC_API void * GC_CALL GC_generate_random_valid_address(void)
10502 {
10503 ptr_t result;
10504 ptr_t base;
10505 do {
10506 result = (ptr_t)GC_generate_random_heap_address();
10507 base = (ptr_t)GC_base(result);
10508 } while (NULL == base || !GC_is_marked(base));
10509 return result;
10510 }
10511 GC_API void GC_CALL GC_print_backtrace(void *p)
10512 {
10513 void *current = p;
10514 int i;
10515 GC_ref_kind source;
10516 size_t offset;
10517 void *base;
10518 GC_print_heap_obj((ptr_t)GC_base(current));
10519 for (i = 0; ; ++i) {
10520 source = GC_get_back_ptr_info(current, &base, &offset);
10521 if (GC_UNREFERENCED == source) {
10522 GC_err_printf("Reference could not be found\n");
10523 goto out;
10524 }
10525 if (GC_NO_SPACE == source) {
10526 GC_err_printf("No debug info in object: Can't find reference\n");
10527 goto out;
10528 }
10529 GC_err_printf("Reachable via %d levels of pointers from ", i);
10530 switch(source) {
10531 case GC_REFD_FROM_ROOT:
10532 GC_err_printf("root at %p\n\n", base);
10533 goto out;
10534 case GC_REFD_FROM_REG:
10535 GC_err_printf("root in register\n\n");
10536 goto out;
10537 case GC_FINALIZER_REFD:
10538 GC_err_printf("list of finalizable objects\n\n");
10539 goto out;
10540 case GC_REFD_FROM_HEAP:
10541 GC_err_printf("offset %ld in object:\n", (long)offset);
10542 GC_print_heap_obj((ptr_t)GC_base(base));
10543 break;
10544 default:
10545 GC_err_printf("INTERNAL ERROR: UNEXPECTED SOURCE!!!!\n");
10546 goto out;
10547 }
10548 current = base;
10549 }
10550 out:;
10551 }
10552 GC_INNER void GC_generate_random_backtrace_no_gc(void)
10553 {
10554 void * current;
10555 current = GC_generate_random_valid_address();
10556 GC_printf("\n****Chosen address %p in object\n", current);
10557 GC_print_backtrace(current);
10558 }
10559 GC_API void GC_CALL GC_generate_random_backtrace(void)
10560 {
10561 if (GC_try_to_collect(GC_never_stop_func) == 0) {
10562 GC_err_printf("Cannot generate a backtrace: "
10563 "garbage collection is disabled!\n");
10564 return;
10565 }
10566 GC_generate_random_backtrace_no_gc();
10567 }
10568#endif
10569#define CROSSES_HBLK(p, sz) \
10570 (((word)((p) + sizeof(oh) + (sz) - 1) ^ (word)(p)) >= HBLKSIZE)
10571GC_INNER void *GC_store_debug_info_inner(void *p, word sz GC_ATTR_UNUSED,
10572 const char *string, int linenum)
10573{
10574 word * result = (word *)((oh *)p + 1);
10575 GC_ASSERT(I_HOLD_LOCK());
10576 GC_ASSERT(GC_size(p) >= sizeof(oh) + sz);
10577 GC_ASSERT(!(SMALL_OBJ(sz) && CROSSES_HBLK((ptr_t)p, sz)));
10578#ifdef KEEP_BACK_PTRS
10579 ((oh *)p) -> oh_back_ptr = HIDE_BACK_PTR(NOT_MARKED);
10580#endif
10581#ifdef MAKE_BACK_GRAPH
10582 ((oh *)p) -> oh_bg_ptr = HIDE_BACK_PTR((ptr_t)0);
10583#endif
10584 ((oh *)p) -> oh_string = string;
10585 ((oh *)p) -> oh_int = linenum;
10586#ifndef SHORT_DBG_HDRS
10587 ((oh *)p) -> oh_sz = sz;
10588 ((oh *)p) -> oh_sf = START_FLAG ^ (word)result;
10589 ((word *)p)[BYTES_TO_WORDS(GC_size(p))-1] =
10590 result[SIMPLE_ROUNDED_UP_WORDS(sz)] = END_FLAG ^ (word)result;
10591#endif
10592 return result;
10593}
10594static void *store_debug_info(void *p, size_t lb,
10595 const char *fn, GC_EXTRA_PARAMS)
10596{
10597 void *result;
10598 DCL_LOCK_STATE;
10599 if (NULL == p) {
10600 GC_err_printf("%s(%lu) returning NULL (%s:%d)\n",
10601 fn, (unsigned long)lb, s, i);
10602 return NULL;
10603 }
10604 LOCK();
10605 if (!GC_debugging_started)
10606 GC_start_debugging_inner();
10607 ADD_CALL_CHAIN(p, ra);
10608 result = GC_store_debug_info_inner(p, (word)lb, s, i);
10609 UNLOCK();
10610 return result;
10611}
10612#ifndef SHORT_DBG_HDRS
10613 STATIC ptr_t GC_check_annotated_obj(oh *ohdr)
10614 {
10615 ptr_t body = (ptr_t)(ohdr + 1);
10616 word gc_sz = GC_size((ptr_t)ohdr);
10617 if (ohdr -> oh_sz + DEBUG_BYTES > gc_sz) {
10618 return((ptr_t)(&(ohdr -> oh_sz)));
10619 }
10620 if (ohdr -> oh_sf != (START_FLAG ^ (word)body)) {
10621 return((ptr_t)(&(ohdr -> oh_sf)));
10622 }
10623 if (((word *)ohdr)[BYTES_TO_WORDS(gc_sz)-1] != (END_FLAG ^ (word)body)) {
10624 return (ptr_t)(&((word *)ohdr)[BYTES_TO_WORDS(gc_sz)-1]);
10625 }
10626 if (((word *)body)[SIMPLE_ROUNDED_UP_WORDS(ohdr -> oh_sz)]
10627 != (END_FLAG ^ (word)body)) {
10628 return (ptr_t)(&((word *)body)[SIMPLE_ROUNDED_UP_WORDS(ohdr->oh_sz)]);
10629 }
10630 return(0);
10631 }
10632#endif
10633STATIC GC_describe_type_fn GC_describe_type_fns[MAXOBJKINDS] = {0};
10634GC_API void GC_CALL GC_register_describe_type_fn(int kind,
10635 GC_describe_type_fn fn)
10636{
10637 GC_describe_type_fns[kind] = fn;
10638}
10639#define GET_OH_LINENUM(ohdr) ((int)(ohdr)->oh_int)
10640#ifndef SHORT_DBG_HDRS
10641#define IF_NOT_SHORTDBG_HDRS(x) x
10642#define COMMA_IFNOT_SHORTDBG_HDRS(x) , x
10643#else
10644#define IF_NOT_SHORTDBG_HDRS(x)
10645#define COMMA_IFNOT_SHORTDBG_HDRS(x)
10646#endif
10647STATIC void GC_print_obj(ptr_t p)
10648{
10649 oh * ohdr = (oh *)GC_base(p);
10650 ptr_t q;
10651 hdr * hhdr;
10652 int kind;
10653 const char *kind_str;
10654 char buffer[GC_TYPE_DESCR_LEN + 1];
10655 GC_ASSERT(I_DONT_HOLD_LOCK());
10656#ifdef LINT2
10657 if (!ohdr) ABORT("Invalid GC_print_obj argument");
10658#endif
10659 q = (ptr_t)(ohdr + 1);
10660 hhdr = GC_find_header(q);
10661 kind = hhdr -> hb_obj_kind;
10662 if (0 != GC_describe_type_fns[kind] && GC_is_marked(ohdr)) {
10663 buffer[GC_TYPE_DESCR_LEN] = 0;
10664 (GC_describe_type_fns[kind])(q, buffer);
10665 GC_ASSERT(buffer[GC_TYPE_DESCR_LEN] == 0);
10666 kind_str = buffer;
10667 } else {
10668 switch(kind) {
10669 case PTRFREE:
10670 kind_str = "PTRFREE";
10671 break;
10672 case NORMAL:
10673 kind_str = "NORMAL";
10674 break;
10675 case UNCOLLECTABLE:
10676 kind_str = "UNCOLLECTABLE";
10677 break;
10678#ifdef GC_ATOMIC_UNCOLLECTABLE
10679 case AUNCOLLECTABLE:
10680 kind_str = "ATOMIC_UNCOLLECTABLE";
10681 break;
10682#endif
10683 default:
10684 kind_str = NULL;
10685 }
10686 }
10687 if (NULL != kind_str) {
10688 GC_err_printf("%p (%s:%d," IF_NOT_SHORTDBG_HDRS(" sz= %lu,") " %s)\n",
10689 (void *)((ptr_t)ohdr + sizeof(oh)),
10690 ohdr->oh_string, GET_OH_LINENUM(ohdr)
10691 COMMA_IFNOT_SHORTDBG_HDRS((unsigned long)ohdr->oh_sz),
10692 kind_str);
10693 } else {
10694 GC_err_printf("%p (%s:%d," IF_NOT_SHORTDBG_HDRS(" sz= %lu,")
10695 " kind= %d, descr= 0x%lx)\n",
10696 (void *)((ptr_t)ohdr + sizeof(oh)),
10697 ohdr->oh_string, GET_OH_LINENUM(ohdr)
10698 COMMA_IFNOT_SHORTDBG_HDRS((unsigned long)ohdr->oh_sz),
10699 kind, (unsigned long)hhdr->hb_descr);
10700 }
10701 PRINT_CALL_CHAIN(ohdr);
10702}
10703STATIC void GC_debug_print_heap_obj_proc(ptr_t p)
10704{
10705 GC_ASSERT(I_DONT_HOLD_LOCK());
10706 if (GC_HAS_DEBUG_INFO(p)) {
10707 GC_print_obj(p);
10708 } else {
10709 GC_default_print_heap_obj_proc(p);
10710 }
10711}
10712#ifndef SHORT_DBG_HDRS
10713 STATIC void GC_print_smashed_obj(const char *msg, void *p,
10714 ptr_t clobbered_addr)
10715 {
10716 oh * ohdr = (oh *)GC_base(p);
10717 GC_ASSERT(I_DONT_HOLD_LOCK());
10718#ifdef LINT2
10719 if (!ohdr) ABORT("Invalid GC_print_smashed_obj argument");
10720#endif
10721 if ((word)clobbered_addr <= (word)(&ohdr->oh_sz)
10722 || ohdr -> oh_string == 0) {
10723 GC_err_printf(
10724 "%s %p in or near object at %p(<smashed>, appr. sz= %lu)\n",
10725 msg, (void *)clobbered_addr, p,
10726 (unsigned long)(GC_size((ptr_t)ohdr) - DEBUG_BYTES));
10727 } else {
10728 GC_err_printf("%s %p in or near object at %p (%s:%d, sz= %lu)\n",
10729 msg, (void *)clobbered_addr, p,
10730 (word)(ohdr -> oh_string) < HBLKSIZE ? "(smashed string)" :
10731 ohdr -> oh_string[0] == '\0' ? "EMPTY(smashed?)" :
10732 ohdr -> oh_string,
10733 GET_OH_LINENUM(ohdr), (unsigned long)(ohdr -> oh_sz));
10734 PRINT_CALL_CHAIN(ohdr);
10735 }
10736 }
10737 STATIC void GC_check_heap_proc (void);
10738 STATIC void GC_print_all_smashed_proc (void);
10739#else
10740 STATIC void GC_do_nothing(void) {}
10741#endif
10742GC_INNER void GC_start_debugging_inner(void)
10743{
10744 GC_ASSERT(I_HOLD_LOCK());
10745#ifndef SHORT_DBG_HDRS
10746 GC_check_heap = GC_check_heap_proc;
10747 GC_print_all_smashed = GC_print_all_smashed_proc;
10748#else
10749 GC_check_heap = GC_do_nothing;
10750 GC_print_all_smashed = GC_do_nothing;
10751#endif
10752 GC_print_heap_obj = GC_debug_print_heap_obj_proc;
10753 GC_debugging_started = TRUE;
10754 GC_register_displacement_inner((word)sizeof(oh));
10755#if defined(CPPCHECK)
10756 GC_noop1(GC_debug_header_size);
10757#endif
10758}
10759const size_t GC_debug_header_size = sizeof(oh);
10760GC_API size_t GC_CALL GC_get_debug_header_size(void) {
10761 return sizeof(oh);
10762}
10763GC_API void GC_CALL GC_debug_register_displacement(size_t offset)
10764{
10765 DCL_LOCK_STATE;
10766 LOCK();
10767 GC_register_displacement_inner(offset);
10768 GC_register_displacement_inner((word)sizeof(oh) + offset);
10769 UNLOCK();
10770}
10771#ifdef GC_ADD_CALLER
10772#if defined(HAVE_DLADDR) && defined(GC_HAVE_RETURN_ADDR_PARENT)
10773#include <dlfcn.h>
10774 STATIC void GC_caller_func_offset(word ad, const char **symp, int *offp)
10775 {
10776 Dl_info caller;
10777 if (ad && dladdr((void *)ad, &caller) && caller.dli_sname != NULL) {
10778 *symp = caller.dli_sname;
10779 *offp = (int)((char *)ad - (char *)caller.dli_saddr);
10780 }
10781 if (NULL == *symp) {
10782 *symp = "unknown";
10783 }
10784 }
10785#else
10786#define GC_caller_func_offset(ad, symp, offp) (void)(*(symp) = "unknown")
10787#endif
10788#endif
10789GC_API GC_ATTR_MALLOC void * GC_CALL GC_debug_malloc(size_t lb,
10790 GC_EXTRA_PARAMS)
10791{
10792 void * result;
10793 result = GC_malloc(SIZET_SAT_ADD(lb, DEBUG_BYTES));
10794#ifdef GC_ADD_CALLER
10795 if (s == NULL) {
10796 GC_caller_func_offset(ra, &s, &i);
10797 }
10798#endif
10799 return store_debug_info(result, lb, "GC_debug_malloc", OPT_RA s, i);
10800}
10801GC_API GC_ATTR_MALLOC void * GC_CALL
10802 GC_debug_malloc_ignore_off_page(size_t lb, GC_EXTRA_PARAMS)
10803{
10804 void * result = GC_malloc_ignore_off_page(SIZET_SAT_ADD(lb, DEBUG_BYTES));
10805 return store_debug_info(result, lb, "GC_debug_malloc_ignore_off_page",
10806 OPT_RA s, i);
10807}
10808GC_API GC_ATTR_MALLOC void * GC_CALL
10809 GC_debug_malloc_atomic_ignore_off_page(size_t lb, GC_EXTRA_PARAMS)
10810{
10811 void * result = GC_malloc_atomic_ignore_off_page(
10812 SIZET_SAT_ADD(lb, DEBUG_BYTES));
10813 return store_debug_info(result, lb,
10814 "GC_debug_malloc_atomic_ignore_off_page",
10815 OPT_RA s, i);
10816}
10817STATIC void * GC_debug_generic_malloc(size_t lb, int knd, GC_EXTRA_PARAMS)
10818{
10819 void * result = GC_generic_malloc(SIZET_SAT_ADD(lb, DEBUG_BYTES), knd);
10820 return store_debug_info(result, lb, "GC_debug_generic_malloc",
10821 OPT_RA s, i);
10822}
10823#ifdef DBG_HDRS_ALL
10824 GC_INNER void * GC_debug_generic_malloc_inner(size_t lb, int k)
10825 {
10826 void * result;
10827 GC_ASSERT(I_HOLD_LOCK());
10828 result = GC_generic_malloc_inner(SIZET_SAT_ADD(lb, DEBUG_BYTES), k);
10829 if (NULL == result) {
10830 GC_err_printf("GC internal allocation (%lu bytes) returning NULL\n",
10831 (unsigned long) lb);
10832 return(0);
10833 }
10834 if (!GC_debugging_started) {
10835 GC_start_debugging_inner();
10836 }
10837 ADD_CALL_CHAIN(result, GC_RETURN_ADDR);
10838 return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", 0));
10839 }
10840 GC_INNER void * GC_debug_generic_malloc_inner_ignore_off_page(size_t lb,
10841 int k)
10842 {
10843 void * result;
10844 GC_ASSERT(I_HOLD_LOCK());
10845 result = GC_generic_malloc_inner_ignore_off_page(
10846 SIZET_SAT_ADD(lb, DEBUG_BYTES), k);
10847 if (NULL == result) {
10848 GC_err_printf("GC internal allocation (%lu bytes) returning NULL\n",
10849 (unsigned long) lb);
10850 return(0);
10851 }
10852 if (!GC_debugging_started) {
10853 GC_start_debugging_inner();
10854 }
10855 ADD_CALL_CHAIN(result, GC_RETURN_ADDR);
10856 return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", 0));
10857 }
10858#endif
10859#ifndef CPPCHECK
10860 GC_API void * GC_CALL GC_debug_malloc_stubborn(size_t lb, GC_EXTRA_PARAMS)
10861 {
10862 return GC_debug_malloc(lb, OPT_RA s, i);
10863 }
10864 GC_API void GC_CALL GC_debug_change_stubborn(
10865 const void * p GC_ATTR_UNUSED) {}
10866#endif
10867GC_API void GC_CALL GC_debug_end_stubborn_change(const void *p)
10868{
10869 const void * q = GC_base_C(p);
10870 if (NULL == q) {
10871 ABORT_ARG1("GC_debug_end_stubborn_change: bad arg", ": %p", p);
10872 }
10873 GC_end_stubborn_change(q);
10874}
10875GC_API void GC_CALL GC_debug_ptr_store_and_dirty(void *p, const void *q)
10876{
10877 *(void **)GC_is_visible(p) = GC_is_valid_displacement((void *)q);
10878 GC_debug_end_stubborn_change(p);
10879 REACHABLE_AFTER_DIRTY(q);
10880}
10881GC_API GC_ATTR_MALLOC void * GC_CALL GC_debug_malloc_atomic(size_t lb,
10882 GC_EXTRA_PARAMS)
10883{
10884 void * result = GC_malloc_atomic(SIZET_SAT_ADD(lb, DEBUG_BYTES));
10885 return store_debug_info(result, lb, "GC_debug_malloc_atomic",
10886 OPT_RA s, i);
10887}
10888GC_API GC_ATTR_MALLOC char * GC_CALL GC_debug_strdup(const char *str,
10889 GC_EXTRA_PARAMS)
10890{
10891 char *copy;
10892 size_t lb;
10893 if (str == NULL) {
10894 if (GC_find_leak)
10895 GC_err_printf("strdup(NULL) behavior is undefined\n");
10896 return NULL;
10897 }
10898 lb = strlen(str) + 1;
10899 copy = (char *)GC_debug_malloc_atomic(lb, OPT_RA s, i);
10900 if (copy == NULL) {
10901#ifndef MSWINCE
10902 errno = ENOMEM;
10903#endif
10904 return NULL;
10905 }
10906 BCOPY(str, copy, lb);
10907 return copy;
10908}
10909GC_API GC_ATTR_MALLOC char * GC_CALL GC_debug_strndup(const char *str,
10910 size_t size, GC_EXTRA_PARAMS)
10911{
10912 char *copy;
10913 size_t len = strlen(str);
10914 if (len > size)
10915 len = size;
10916 copy = (char *)GC_debug_malloc_atomic(len + 1, OPT_RA s, i);
10917 if (copy == NULL) {
10918#ifndef MSWINCE
10919 errno = ENOMEM;
10920#endif
10921 return NULL;
10922 }
10923 if (len > 0)
10924 BCOPY(str, copy, len);
10925 copy[len] = '\0';
10926 return copy;
10927}
10928#ifdef GC_REQUIRE_WCSDUP
10929#include <wchar.h>
10930 GC_API GC_ATTR_MALLOC wchar_t * GC_CALL GC_debug_wcsdup(const wchar_t *str,
10931 GC_EXTRA_PARAMS)
10932 {
10933 size_t lb = (wcslen(str) + 1) * sizeof(wchar_t);
10934 wchar_t *copy = (wchar_t *)GC_debug_malloc_atomic(lb, OPT_RA s, i);
10935 if (copy == NULL) {
10936#ifndef MSWINCE
10937 errno = ENOMEM;
10938#endif
10939 return NULL;
10940 }
10941 BCOPY(str, copy, lb);
10942 return copy;
10943 }
10944#endif
10945GC_API GC_ATTR_MALLOC void * GC_CALL GC_debug_malloc_uncollectable(size_t lb,
10946 GC_EXTRA_PARAMS)
10947{
10948 void * result = GC_malloc_uncollectable(
10949 SIZET_SAT_ADD(lb, UNCOLLECTABLE_DEBUG_BYTES));
10950 return store_debug_info(result, lb, "GC_debug_malloc_uncollectable",
10951 OPT_RA s, i);
10952}
10953#ifdef GC_ATOMIC_UNCOLLECTABLE
10954 GC_API GC_ATTR_MALLOC void * GC_CALL
10955 GC_debug_malloc_atomic_uncollectable(size_t lb, GC_EXTRA_PARAMS)
10956 {
10957 void * result = GC_malloc_atomic_uncollectable(
10958 SIZET_SAT_ADD(lb, UNCOLLECTABLE_DEBUG_BYTES));
10959 return store_debug_info(result, lb,
10960 "GC_debug_malloc_atomic_uncollectable",
10961 OPT_RA s, i);
10962 }
10963#endif
10964#ifndef GC_FREED_MEM_MARKER
10965#if CPP_WORDSZ == 32
10966#define GC_FREED_MEM_MARKER 0xdeadbeef
10967#else
10968#define GC_FREED_MEM_MARKER GC_WORD_C(0xEFBEADDEdeadbeef)
10969#endif
10970#endif
10971GC_API void GC_CALL GC_debug_free(void * p)
10972{
10973 ptr_t base;
10974 if (0 == p) return;
10975 base = (ptr_t)GC_base(p);
10976 if (NULL == base) {
10977#if defined(REDIRECT_MALLOC) \
10978 && ((defined(NEED_CALLINFO) && defined(GC_HAVE_BUILTIN_BACKTRACE)) \
10979 || defined(GC_LINUX_THREADS) || defined(GC_SOLARIS_THREADS) \
10980 || defined(MSWIN32))
10981 if (!GC_is_heap_ptr(p)) return;
10982#endif
10983 ABORT_ARG1("Invalid pointer passed to free()", ": %p", p);
10984 }
10985 if ((ptr_t)p - (ptr_t)base != sizeof(oh)) {
10986#if defined(REDIRECT_FREE) && defined(USE_PROC_FOR_LIBRARIES)
10987#endif
10988 GC_err_printf(
10989 "GC_debug_free called on pointer %p w/o debugging info\n", p);
10990 } else {
10991#ifndef SHORT_DBG_HDRS
10992 ptr_t clobbered = GC_check_annotated_obj((oh *)base);
10993 word sz = GC_size(base);
10994 if (clobbered != 0) {
10995 GC_have_errors = TRUE;
10996 if (((oh *)base) -> oh_sz == sz) {
10997 GC_print_smashed_obj(
10998 "GC_debug_free: found previously deallocated (?) object at",
10999 p, clobbered);
11000 return;
11001 } else {
11002 GC_print_smashed_obj("GC_debug_free: found smashed location at",
11003 p, clobbered);
11004 }
11005 }
11006 ((oh *)base) -> oh_sz = sz;
11007#endif
11008 }
11009 if (GC_find_leak
11010#ifndef SHORT_DBG_HDRS
11011 && ((ptr_t)p - (ptr_t)base != sizeof(oh) || !GC_findleak_delay_free)
11012#endif
11013 ) {
11014 GC_free(base);
11015 } else {
11016 hdr * hhdr = HDR(p);
11017 if (hhdr -> hb_obj_kind == UNCOLLECTABLE
11018#ifdef GC_ATOMIC_UNCOLLECTABLE
11019 || hhdr -> hb_obj_kind == AUNCOLLECTABLE
11020#endif
11021 ) {
11022 GC_free(base);
11023 } else {
11024 word i;
11025 word sz = hhdr -> hb_sz;
11026 word obj_sz = BYTES_TO_WORDS(sz - sizeof(oh));
11027 for (i = 0; i < obj_sz; ++i)
11028 ((word *)p)[i] = GC_FREED_MEM_MARKER;
11029 GC_ASSERT((word *)p + i == (word *)(base + sz));
11030 LOCK();
11031 GC_bytes_freed += sz;
11032 UNLOCK();
11033 }
11034 }
11035}
11036#if defined(THREADS) && defined(DBG_HDRS_ALL)
11037 GC_INNER void GC_debug_free_inner(void * p)
11038 {
11039 ptr_t base = (ptr_t)GC_base(p);
11040 GC_ASSERT((ptr_t)p - (ptr_t)base == sizeof(oh));
11041#ifdef LINT2
11042 if (!base) ABORT("Invalid GC_debug_free_inner argument");
11043#endif
11044#ifndef SHORT_DBG_HDRS
11045 ((oh *)base) -> oh_sz = GC_size(base);
11046#endif
11047 GC_free_inner(base);
11048 }
11049#endif
11050GC_API void * GC_CALL GC_debug_realloc(void * p, size_t lb, GC_EXTRA_PARAMS)
11051{
11052 void * base;
11053 void * result;
11054 hdr * hhdr;
11055 if (p == 0) {
11056 return GC_debug_malloc(lb, OPT_RA s, i);
11057 }
11058 if (0 == lb) {
11059 GC_debug_free(p);
11060 return NULL;
11061 }
11062#ifdef GC_ADD_CALLER
11063 if (s == NULL) {
11064 GC_caller_func_offset(ra, &s, &i);
11065 }
11066#endif
11067 base = GC_base(p);
11068 if (base == 0) {
11069 ABORT_ARG1("Invalid pointer passed to realloc()", ": %p", p);
11070 }
11071 if ((ptr_t)p - (ptr_t)base != sizeof(oh)) {
11072 GC_err_printf(
11073 "GC_debug_realloc called on pointer %p w/o debugging info\n", p);
11074 return(GC_realloc(p, lb));
11075 }
11076 hhdr = HDR(base);
11077 switch (hhdr -> hb_obj_kind) {
11078 case NORMAL:
11079 result = GC_debug_malloc(lb, OPT_RA s, i);
11080 break;
11081 case PTRFREE:
11082 result = GC_debug_malloc_atomic(lb, OPT_RA s, i);
11083 break;
11084 case UNCOLLECTABLE:
11085 result = GC_debug_malloc_uncollectable(lb, OPT_RA s, i);
11086 break;
11087#ifdef GC_ATOMIC_UNCOLLECTABLE
11088 case AUNCOLLECTABLE:
11089 result = GC_debug_malloc_atomic_uncollectable(lb, OPT_RA s, i);
11090 break;
11091#endif
11092 default:
11093 result = NULL;
11094 ABORT_RET("GC_debug_realloc: encountered bad kind");
11095 }
11096 if (result != NULL) {
11097 size_t old_sz;
11098#ifdef SHORT_DBG_HDRS
11099 old_sz = GC_size(base) - sizeof(oh);
11100#else
11101 old_sz = ((oh *)base) -> oh_sz;
11102#endif
11103 if (old_sz > 0)
11104 BCOPY(p, result, old_sz < lb ? old_sz : lb);
11105 GC_debug_free(p);
11106 }
11107 return(result);
11108}
11109GC_API GC_ATTR_MALLOC void * GC_CALL
11110 GC_debug_generic_or_special_malloc(size_t lb, int knd, GC_EXTRA_PARAMS)
11111{
11112 switch (knd) {
11113 case PTRFREE:
11114 return GC_debug_malloc_atomic(lb, OPT_RA s, i);
11115 case NORMAL:
11116 return GC_debug_malloc(lb, OPT_RA s, i);
11117 case UNCOLLECTABLE:
11118 return GC_debug_malloc_uncollectable(lb, OPT_RA s, i);
11119#ifdef GC_ATOMIC_UNCOLLECTABLE
11120 case AUNCOLLECTABLE:
11121 return GC_debug_malloc_atomic_uncollectable(lb, OPT_RA s, i);
11122#endif
11123 default:
11124 return GC_debug_generic_malloc(lb, knd, OPT_RA s, i);
11125 }
11126}
11127#ifndef SHORT_DBG_HDRS
11128#ifndef MAX_SMASHED
11129#define MAX_SMASHED 20
11130#endif
11131STATIC ptr_t GC_smashed[MAX_SMASHED] = {0};
11132STATIC unsigned GC_n_smashed = 0;
11133STATIC void GC_add_smashed(ptr_t smashed)
11134{
11135 GC_ASSERT(GC_is_marked(GC_base(smashed)));
11136 GC_smashed[GC_n_smashed] = smashed;
11137 if (GC_n_smashed < MAX_SMASHED - 1) ++GC_n_smashed;
11138 GC_have_errors = TRUE;
11139}
11140STATIC void GC_print_all_smashed_proc(void)
11141{
11142 unsigned i;
11143 GC_ASSERT(I_DONT_HOLD_LOCK());
11144 if (GC_n_smashed == 0) return;
11145 GC_err_printf("GC_check_heap_block: found %u smashed heap objects:\n",
11146 GC_n_smashed);
11147 for (i = 0; i < GC_n_smashed; ++i) {
11148 ptr_t base = (ptr_t)GC_base(GC_smashed[i]);
11149#ifdef LINT2
11150 if (!base) ABORT("Invalid GC_smashed element");
11151#endif
11152 GC_print_smashed_obj("", base + sizeof(oh), GC_smashed[i]);
11153 GC_smashed[i] = 0;
11154 }
11155 GC_n_smashed = 0;
11156}
11157STATIC void GC_check_heap_block(struct hblk *hbp, word dummy GC_ATTR_UNUSED)
11158{
11159 struct hblkhdr * hhdr = HDR(hbp);
11160 word sz = hhdr -> hb_sz;
11161 word bit_no;
11162 char *p, *plim;
11163 p = hbp->hb_body;
11164 if (sz > MAXOBJBYTES) {
11165 plim = p;
11166 } else {
11167 plim = hbp->hb_body + HBLKSIZE - sz;
11168 }
11169 for (bit_no = 0; (word)p <= (word)plim;
11170 bit_no += MARK_BIT_OFFSET(sz), p += sz) {
11171 if (mark_bit_from_hdr(hhdr, bit_no) && GC_HAS_DEBUG_INFO((ptr_t)p)) {
11172 ptr_t clobbered = GC_check_annotated_obj((oh *)p);
11173 if (clobbered != 0)
11174 GC_add_smashed(clobbered);
11175 }
11176 }
11177}
11178STATIC void GC_check_heap_proc(void)
11179{
11180 GC_STATIC_ASSERT((sizeof(oh) & (GRANULE_BYTES - 1)) == 0);
11181 GC_apply_to_all_blocks(GC_check_heap_block, 0);
11182}
11183GC_INNER GC_bool GC_check_leaked(ptr_t base)
11184{
11185 word i;
11186 word obj_sz;
11187 word *p;
11188 if (
11189#if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
11190 (*(word *)base & 1) != 0 &&
11191#endif
11192 GC_has_other_debug_info(base) >= 0)
11193 return TRUE;
11194 p = (word *)(base + sizeof(oh));
11195 obj_sz = BYTES_TO_WORDS(HDR(base)->hb_sz - sizeof(oh));
11196 for (i = 0; i < obj_sz; ++i)
11197 if (p[i] != GC_FREED_MEM_MARKER) {
11198 GC_set_mark_bit(base);
11199 GC_add_smashed((ptr_t)(&p[i]));
11200 break;
11201 }
11202 return FALSE;
11203}
11204#endif
11205#ifndef GC_NO_FINALIZATION
11206struct closure {
11207 GC_finalization_proc cl_fn;
11208 void * cl_data;
11209};
11210STATIC void * GC_make_closure(GC_finalization_proc fn, void * data)
11211{
11212 struct closure * result =
11213#ifdef DBG_HDRS_ALL
11214 (struct closure *) GC_debug_malloc(sizeof (struct closure),
11215 GC_EXTRAS);
11216#else
11217 (struct closure *) GC_malloc(sizeof (struct closure));
11218#endif
11219 if (result != 0) {
11220 result -> cl_fn = fn;
11221 result -> cl_data = data;
11222 }
11223 return((void *)result);
11224}
11225STATIC void GC_CALLBACK GC_debug_invoke_finalizer(void * obj, void * data)
11226{
11227 struct closure * cl = (struct closure *) data;
11228 (*(cl -> cl_fn))((void *)((char *)obj + sizeof(oh)), cl -> cl_data);
11229}
11230#define OFN_UNSET ((GC_finalization_proc)~(signed_word)0)
11231static void store_old(void *obj, GC_finalization_proc my_old_fn,
11232 struct closure *my_old_cd, GC_finalization_proc *ofn,
11233 void **ocd)
11234{
11235 if (0 != my_old_fn) {
11236 if (my_old_fn == OFN_UNSET) {
11237 return;
11238 }
11239 if (my_old_fn != GC_debug_invoke_finalizer) {
11240 GC_err_printf("Debuggable object at %p had a non-debug finalizer\n",
11241 obj);
11242 } else {
11243 if (ofn) *ofn = my_old_cd -> cl_fn;
11244 if (ocd) *ocd = my_old_cd -> cl_data;
11245 }
11246 } else {
11247 if (ofn) *ofn = 0;
11248 if (ocd) *ocd = 0;
11249 }
11250}
11251GC_API void GC_CALL GC_debug_register_finalizer(void * obj,
11252 GC_finalization_proc fn,
11253 void * cd, GC_finalization_proc *ofn,
11254 void * *ocd)
11255{
11256 GC_finalization_proc my_old_fn = OFN_UNSET;
11257 void * my_old_cd;
11258 ptr_t base = (ptr_t)GC_base(obj);
11259 if (NULL == base) {
11260 if (ocd) *ocd = 0;
11261 if (ofn) *ofn = 0;
11262 return;
11263 }
11264 if ((ptr_t)obj - base != sizeof(oh)) {
11265 GC_err_printf("GC_debug_register_finalizer called with"
11266 " non-base-pointer %p\n", obj);
11267 }
11268 if (0 == fn) {
11269 GC_register_finalizer(base, 0, 0, &my_old_fn, &my_old_cd);
11270 } else {
11271 cd = GC_make_closure(fn, cd);
11272 if (cd == 0) return;
11273 GC_register_finalizer(base, GC_debug_invoke_finalizer,
11274 cd, &my_old_fn, &my_old_cd);
11275 }
11276 store_old(obj, my_old_fn, (struct closure *)my_old_cd, ofn, ocd);
11277}
11278GC_API void GC_CALL GC_debug_register_finalizer_no_order
11279 (void * obj, GC_finalization_proc fn,
11280 void * cd, GC_finalization_proc *ofn,
11281 void * *ocd)
11282{
11283 GC_finalization_proc my_old_fn = OFN_UNSET;
11284 void * my_old_cd;
11285 ptr_t base = (ptr_t)GC_base(obj);
11286 if (NULL == base) {
11287 if (ocd) *ocd = 0;
11288 if (ofn) *ofn = 0;
11289 return;
11290 }
11291 if ((ptr_t)obj - base != sizeof(oh)) {
11292 GC_err_printf("GC_debug_register_finalizer_no_order called with"
11293 " non-base-pointer %p\n", obj);
11294 }
11295 if (0 == fn) {
11296 GC_register_finalizer_no_order(base, 0, 0, &my_old_fn, &my_old_cd);
11297 } else {
11298 cd = GC_make_closure(fn, cd);
11299 if (cd == 0) return;
11300 GC_register_finalizer_no_order(base, GC_debug_invoke_finalizer,
11301 cd, &my_old_fn, &my_old_cd);
11302 }
11303 store_old(obj, my_old_fn, (struct closure *)my_old_cd, ofn, ocd);
11304}
11305GC_API void GC_CALL GC_debug_register_finalizer_unreachable
11306 (void * obj, GC_finalization_proc fn,
11307 void * cd, GC_finalization_proc *ofn,
11308 void * *ocd)
11309{
11310 GC_finalization_proc my_old_fn = OFN_UNSET;
11311 void * my_old_cd;
11312 ptr_t base = (ptr_t)GC_base(obj);
11313 if (NULL == base) {
11314 if (ocd) *ocd = 0;
11315 if (ofn) *ofn = 0;
11316 return;
11317 }
11318 if ((ptr_t)obj - base != sizeof(oh)) {
11319 GC_err_printf("GC_debug_register_finalizer_unreachable called with"
11320 " non-base-pointer %p\n", obj);
11321 }
11322 if (0 == fn) {
11323 GC_register_finalizer_unreachable(base, 0, 0, &my_old_fn, &my_old_cd);
11324 } else {
11325 cd = GC_make_closure(fn, cd);
11326 if (cd == 0) return;
11327 GC_register_finalizer_unreachable(base, GC_debug_invoke_finalizer,
11328 cd, &my_old_fn, &my_old_cd);
11329 }
11330 store_old(obj, my_old_fn, (struct closure *)my_old_cd, ofn, ocd);
11331}
11332GC_API void GC_CALL GC_debug_register_finalizer_ignore_self
11333 (void * obj, GC_finalization_proc fn,
11334 void * cd, GC_finalization_proc *ofn,
11335 void * *ocd)
11336{
11337 GC_finalization_proc my_old_fn = OFN_UNSET;
11338 void * my_old_cd;
11339 ptr_t base = (ptr_t)GC_base(obj);
11340 if (NULL == base) {
11341 if (ocd) *ocd = 0;
11342 if (ofn) *ofn = 0;
11343 return;
11344 }
11345 if ((ptr_t)obj - base != sizeof(oh)) {
11346 GC_err_printf("GC_debug_register_finalizer_ignore_self called with"
11347 " non-base-pointer %p\n", obj);
11348 }
11349 if (0 == fn) {
11350 GC_register_finalizer_ignore_self(base, 0, 0, &my_old_fn, &my_old_cd);
11351 } else {
11352 cd = GC_make_closure(fn, cd);
11353 if (cd == 0) return;
11354 GC_register_finalizer_ignore_self(base, GC_debug_invoke_finalizer,
11355 cd, &my_old_fn, &my_old_cd);
11356 }
11357 store_old(obj, my_old_fn, (struct closure *)my_old_cd, ofn, ocd);
11358}
11359#endif
11360GC_API GC_ATTR_MALLOC void * GC_CALL GC_debug_malloc_replacement(size_t lb)
11361{
11362 return GC_debug_malloc(lb, GC_DBG_EXTRAS);
11363}
11364GC_API void * GC_CALL GC_debug_realloc_replacement(void *p, size_t lb)
11365{
11366 return GC_debug_realloc(p, lb, GC_DBG_EXTRAS);
11367}
11368#ifndef GC_NO_FINALIZATION
11369#ifndef GC_JAVAXFC_H
11370#define GC_JAVAXFC_H
11371#ifndef GC_H
11372#endif
11373#ifdef __cplusplus
11374 extern "C" {
11375#endif
11376GC_API void GC_CALL GC_finalize_all(void);
11377#ifdef GC_THREADS
11378#ifndef GC_SUSPEND_THREAD_ID
11379#define GC_SUSPEND_THREAD_ID void*
11380#endif
11381 GC_API void GC_CALL GC_suspend_thread(GC_SUSPEND_THREAD_ID);
11382 GC_API void GC_CALL GC_resume_thread(GC_SUSPEND_THREAD_ID);
11383 GC_API int GC_CALL GC_is_thread_suspended(GC_SUSPEND_THREAD_ID);
11384#endif
11385#ifdef __cplusplus
11386 }
11387#endif
11388#endif
11389typedef void (* finalization_mark_proc)(ptr_t );
11390#define HASH3(addr,size,log_size) \
11391 ((((word)(addr) >> 3) ^ ((word)(addr) >> (3 + (log_size)))) \
11392 & ((size) - 1))
11393#define HASH2(addr,log_size) HASH3(addr, (word)1 << (log_size), log_size)
11394struct hash_chain_entry {
11395 word hidden_key;
11396 struct hash_chain_entry * next;
11397};
11398struct disappearing_link {
11399 struct hash_chain_entry prolog;
11400#define dl_hidden_link prolog.hidden_key
11401#define dl_next(x) (struct disappearing_link *)((x) -> prolog.next)
11402#define dl_set_next(x, y) \
11403 (void)((x)->prolog.next = (struct hash_chain_entry *)(y))
11404 word dl_hidden_obj;
11405};
11406struct finalizable_object {
11407 struct hash_chain_entry prolog;
11408#define fo_hidden_base prolog.hidden_key
11409#define fo_next(x) (struct finalizable_object *)((x) -> prolog.next)
11410#define fo_set_next(x,y) ((x)->prolog.next = (struct hash_chain_entry *)(y))
11411 GC_finalization_proc fo_fn;
11412 ptr_t fo_client_data;
11413 word fo_object_size;
11414 finalization_mark_proc fo_mark_proc;
11415};
11416#ifdef AO_HAVE_store
11417#define SET_FINALIZE_NOW(fo) \
11418 AO_store((volatile AO_t *)&GC_fnlz_roots.finalize_now, (AO_t)(fo))
11419#else
11420#define SET_FINALIZE_NOW(fo) (void)(GC_fnlz_roots.finalize_now = (fo))
11421#endif
11422GC_API void GC_CALL GC_push_finalizer_structures(void)
11423{
11424 GC_ASSERT((word)(&GC_dl_hashtbl.head) % sizeof(word) == 0);
11425 GC_ASSERT((word)(&GC_fnlz_roots) % sizeof(word) == 0);
11426#ifndef GC_LONG_REFS_NOT_NEEDED
11427 GC_ASSERT((word)(&GC_ll_hashtbl.head) % sizeof(word) == 0);
11428 GC_PUSH_ALL_SYM(GC_ll_hashtbl.head);
11429#endif
11430 GC_PUSH_ALL_SYM(GC_dl_hashtbl.head);
11431 GC_PUSH_ALL_SYM(GC_fnlz_roots);
11432}
11433#ifndef GC_ON_GROW_LOG_SIZE_MIN
11434#define GC_ON_GROW_LOG_SIZE_MIN CPP_LOG_HBLKSIZE
11435#endif
11436STATIC void GC_grow_table(struct hash_chain_entry ***table,
11437 unsigned *log_size_ptr, word *entries_ptr)
11438{
11439 word i;
11440 struct hash_chain_entry *p;
11441 unsigned log_old_size = *log_size_ptr;
11442 unsigned log_new_size = log_old_size + 1;
11443 word old_size = *table == NULL ? 0 : (word)1 << log_old_size;
11444 word new_size = (word)1 << log_new_size;
11445 struct hash_chain_entry **new_table;
11446 GC_ASSERT(I_HOLD_LOCK());
11447 if (log_old_size >= GC_ON_GROW_LOG_SIZE_MIN && !GC_incremental) {
11448 IF_CANCEL(int cancel_state;)
11449 DISABLE_CANCEL(cancel_state);
11450 (void)GC_try_to_collect_inner(GC_never_stop_func);
11451 RESTORE_CANCEL(cancel_state);
11452 if (*entries_ptr < ((word)1 << log_old_size) - (*entries_ptr >> 2))
11453 return;
11454 }
11455 new_table = (struct hash_chain_entry **)
11456 GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE(
11457 (size_t)new_size * sizeof(struct hash_chain_entry *),
11458 NORMAL);
11459 if (new_table == 0) {
11460 if (*table == 0) {
11461 ABORT("Insufficient space for initial table allocation");
11462 } else {
11463 return;
11464 }
11465 }
11466 for (i = 0; i < old_size; i++) {
11467 p = (*table)[i];
11468 while (p != 0) {
11469 ptr_t real_key = (ptr_t)GC_REVEAL_POINTER(p->hidden_key);
11470 struct hash_chain_entry *next = p -> next;
11471 size_t new_hash = HASH3(real_key, new_size, log_new_size);
11472 p -> next = new_table[new_hash];
11473 GC_dirty(p);
11474 new_table[new_hash] = p;
11475 p = next;
11476 }
11477 }
11478 *log_size_ptr = log_new_size;
11479 *table = new_table;
11480 GC_dirty(new_table);
11481}
11482GC_API int GC_CALL GC_register_disappearing_link(void * * link)
11483{
11484 ptr_t base;
11485 base = (ptr_t)GC_base(link);
11486 if (base == 0)
11487 ABORT("Bad arg to GC_register_disappearing_link");
11488 return(GC_general_register_disappearing_link(link, base));
11489}
11490STATIC int GC_register_disappearing_link_inner(
11491 struct dl_hashtbl_s *dl_hashtbl, void **link,
11492 const void *obj, const char *tbl_log_name)
11493{
11494 struct disappearing_link *curr_dl;
11495 size_t index;
11496 struct disappearing_link * new_dl;
11497 DCL_LOCK_STATE;
11498 if (EXPECT(GC_find_leak, FALSE)) return GC_UNIMPLEMENTED;
11499 LOCK();
11500 GC_ASSERT(obj != NULL && GC_base_C(obj) == obj);
11501 if (EXPECT(NULL == dl_hashtbl -> head, FALSE)
11502 || EXPECT(dl_hashtbl -> entries
11503 > ((word)1 << dl_hashtbl -> log_size), FALSE)) {
11504 GC_grow_table((struct hash_chain_entry ***)&dl_hashtbl -> head,
11505 &dl_hashtbl -> log_size, &dl_hashtbl -> entries);
11506 GC_COND_LOG_PRINTF("Grew %s table to %u entries\n", tbl_log_name,
11507 1U << dl_hashtbl -> log_size);
11508 }
11509 index = HASH2(link, dl_hashtbl -> log_size);
11510 for (curr_dl = dl_hashtbl -> head[index]; curr_dl != 0;
11511 curr_dl = dl_next(curr_dl)) {
11512 if (curr_dl -> dl_hidden_link == GC_HIDE_POINTER(link)) {
11513 curr_dl -> dl_hidden_obj = GC_HIDE_POINTER(obj);
11514 UNLOCK();
11515 return GC_DUPLICATE;
11516 }
11517 }
11518 new_dl = (struct disappearing_link *)
11519 GC_INTERNAL_MALLOC(sizeof(struct disappearing_link),NORMAL);
11520 if (0 == new_dl) {
11521 GC_oom_func oom_fn = GC_oom_fn;
11522 UNLOCK();
11523 new_dl = (struct disappearing_link *)
11524 (*oom_fn)(sizeof(struct disappearing_link));
11525 if (0 == new_dl) {
11526 return GC_NO_MEMORY;
11527 }
11528 LOCK();
11529 index = HASH2(link, dl_hashtbl -> log_size);
11530 for (curr_dl = dl_hashtbl -> head[index]; curr_dl != 0;
11531 curr_dl = dl_next(curr_dl)) {
11532 if (curr_dl -> dl_hidden_link == GC_HIDE_POINTER(link)) {
11533 curr_dl -> dl_hidden_obj = GC_HIDE_POINTER(obj);
11534 UNLOCK();
11535#ifndef DBG_HDRS_ALL
11536 GC_free((void *)new_dl);
11537#endif
11538 return GC_DUPLICATE;
11539 }
11540 }
11541 }
11542 new_dl -> dl_hidden_obj = GC_HIDE_POINTER(obj);
11543 new_dl -> dl_hidden_link = GC_HIDE_POINTER(link);
11544 dl_set_next(new_dl, dl_hashtbl -> head[index]);
11545 GC_dirty(new_dl);
11546 dl_hashtbl -> head[index] = new_dl;
11547 dl_hashtbl -> entries++;
11548 GC_dirty(dl_hashtbl->head + index);
11549 UNLOCK();
11550 return GC_SUCCESS;
11551}
11552GC_API int GC_CALL GC_general_register_disappearing_link(void * * link,
11553 const void * obj)
11554{
11555 if (((word)link & (ALIGNMENT-1)) != 0 || !NONNULL_ARG_NOT_NULL(link))
11556 ABORT("Bad arg to GC_general_register_disappearing_link");
11557 return GC_register_disappearing_link_inner(&GC_dl_hashtbl, link, obj,
11558 "dl");
11559}
11560#ifdef DBG_HDRS_ALL
11561#define FREE_DL_ENTRY(curr_dl) dl_set_next(curr_dl, NULL)
11562#else
11563#define FREE_DL_ENTRY(curr_dl) GC_free(curr_dl)
11564#endif
11565GC_INLINE struct disappearing_link *GC_unregister_disappearing_link_inner(
11566 struct dl_hashtbl_s *dl_hashtbl, void **link)
11567{
11568 struct disappearing_link *curr_dl;
11569 struct disappearing_link *prev_dl = NULL;
11570 size_t index;
11571 GC_ASSERT(I_HOLD_LOCK());
11572 if (EXPECT(NULL == dl_hashtbl -> head, FALSE)) return NULL;
11573 index = HASH2(link, dl_hashtbl -> log_size);
11574 for (curr_dl = dl_hashtbl -> head[index]; curr_dl;
11575 curr_dl = dl_next(curr_dl)) {
11576 if (curr_dl -> dl_hidden_link == GC_HIDE_POINTER(link)) {
11577 if (NULL == prev_dl) {
11578 dl_hashtbl -> head[index] = dl_next(curr_dl);
11579 GC_dirty(dl_hashtbl->head + index);
11580 } else {
11581 dl_set_next(prev_dl, dl_next(curr_dl));
11582 GC_dirty(prev_dl);
11583 }
11584 dl_hashtbl -> entries--;
11585 break;
11586 }
11587 prev_dl = curr_dl;
11588 }
11589 return curr_dl;
11590}
11591GC_API int GC_CALL GC_unregister_disappearing_link(void * * link)
11592{
11593 struct disappearing_link *curr_dl;
11594 DCL_LOCK_STATE;
11595 if (((word)link & (ALIGNMENT-1)) != 0) return(0);
11596 LOCK();
11597 curr_dl = GC_unregister_disappearing_link_inner(&GC_dl_hashtbl, link);
11598 UNLOCK();
11599 if (NULL == curr_dl) return 0;
11600 FREE_DL_ENTRY(curr_dl);
11601 return 1;
11602}
11603#ifndef GC_TOGGLE_REFS_NOT_NEEDED
11604 typedef union toggle_ref_u GCToggleRef;
11605 STATIC GC_toggleref_func GC_toggleref_callback = 0;
11606 GC_INNER void GC_process_togglerefs(void)
11607 {
11608 size_t i;
11609 size_t new_size = 0;
11610 GC_bool needs_barrier = FALSE;
11611 GC_ASSERT(I_HOLD_LOCK());
11612 for (i = 0; i < GC_toggleref_array_size; ++i) {
11613 GCToggleRef r = GC_toggleref_arr[i];
11614 void *obj = r.strong_ref;
11615 if (((word)obj & 1) != 0) {
11616 obj = GC_REVEAL_POINTER(r.weak_ref);
11617 }
11618 if (NULL == obj) {
11619 continue;
11620 }
11621 switch (GC_toggleref_callback(obj)) {
11622 case GC_TOGGLE_REF_DROP:
11623 break;
11624 case GC_TOGGLE_REF_STRONG:
11625 GC_toggleref_arr[new_size++].strong_ref = obj;
11626 needs_barrier = TRUE;
11627 break;
11628 case GC_TOGGLE_REF_WEAK:
11629 GC_toggleref_arr[new_size++].weak_ref = GC_HIDE_POINTER(obj);
11630 break;
11631 default:
11632 ABORT("Bad toggle-ref status returned by callback");
11633 }
11634 }
11635 if (new_size < GC_toggleref_array_size) {
11636 BZERO(&GC_toggleref_arr[new_size],
11637 (GC_toggleref_array_size - new_size) * sizeof(GCToggleRef));
11638 GC_toggleref_array_size = new_size;
11639 }
11640 if (needs_barrier)
11641 GC_dirty(GC_toggleref_arr);
11642 }
11643 STATIC void GC_normal_finalize_mark_proc(ptr_t);
11644 static void push_and_mark_object(void *p)
11645 {
11646 GC_normal_finalize_mark_proc((ptr_t)p);
11647 while (!GC_mark_stack_empty()) {
11648 MARK_FROM_MARK_STACK();
11649 }
11650 GC_set_mark_bit(p);
11651 if (GC_mark_state != MS_NONE) {
11652 while (!GC_mark_some(0)) {
11653 }
11654 }
11655 }
11656 STATIC void GC_mark_togglerefs(void)
11657 {
11658 size_t i;
11659 if (NULL == GC_toggleref_arr)
11660 return;
11661 GC_set_mark_bit(GC_toggleref_arr);
11662 for (i = 0; i < GC_toggleref_array_size; ++i) {
11663 void *obj = GC_toggleref_arr[i].strong_ref;
11664 if (obj != NULL && ((word)obj & 1) == 0) {
11665 push_and_mark_object(obj);
11666 }
11667 }
11668 }
11669 STATIC void GC_clear_togglerefs(void)
11670 {
11671 size_t i;
11672 for (i = 0; i < GC_toggleref_array_size; ++i) {
11673 if ((GC_toggleref_arr[i].weak_ref & 1) != 0) {
11674 if (!GC_is_marked(GC_REVEAL_POINTER(GC_toggleref_arr[i].weak_ref))) {
11675 GC_toggleref_arr[i].weak_ref = 0;
11676 } else {
11677 }
11678 }
11679 }
11680 }
11681 GC_API void GC_CALL GC_set_toggleref_func(GC_toggleref_func fn)
11682 {
11683 DCL_LOCK_STATE;
11684 LOCK();
11685 GC_toggleref_callback = fn;
11686 UNLOCK();
11687 }
11688 GC_API GC_toggleref_func GC_CALL GC_get_toggleref_func(void)
11689 {
11690 GC_toggleref_func fn;
11691 DCL_LOCK_STATE;
11692 LOCK();
11693 fn = GC_toggleref_callback;
11694 UNLOCK();
11695 return fn;
11696 }
11697 static GC_bool ensure_toggleref_capacity(size_t capacity_inc)
11698 {
11699 GC_ASSERT(I_HOLD_LOCK());
11700 if (NULL == GC_toggleref_arr) {
11701 GC_toggleref_array_capacity = 32;
11702 GC_toggleref_arr = (GCToggleRef *)GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE(
11703 GC_toggleref_array_capacity * sizeof(GCToggleRef),
11704 NORMAL);
11705 if (NULL == GC_toggleref_arr)
11706 return FALSE;
11707 }
11708 if (GC_toggleref_array_size + capacity_inc
11709 >= GC_toggleref_array_capacity) {
11710 GCToggleRef *new_array;
11711 while (GC_toggleref_array_capacity
11712 < GC_toggleref_array_size + capacity_inc) {
11713 GC_toggleref_array_capacity *= 2;
11714 if ((GC_toggleref_array_capacity
11715 & ((size_t)1 << (sizeof(size_t) * 8 - 1))) != 0)
11716 return FALSE;
11717 }
11718 new_array = (GCToggleRef *)GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE(
11719 GC_toggleref_array_capacity * sizeof(GCToggleRef),
11720 NORMAL);
11721 if (NULL == new_array)
11722 return FALSE;
11723 if (EXPECT(GC_toggleref_array_size > 0, TRUE))
11724 BCOPY(GC_toggleref_arr, new_array,
11725 GC_toggleref_array_size * sizeof(GCToggleRef));
11726 GC_INTERNAL_FREE(GC_toggleref_arr);
11727 GC_toggleref_arr = new_array;
11728 }
11729 return TRUE;
11730 }
11731 GC_API int GC_CALL GC_toggleref_add(void *obj, int is_strong_ref)
11732 {
11733 int res = GC_SUCCESS;
11734 DCL_LOCK_STATE;
11735 GC_ASSERT(NONNULL_ARG_NOT_NULL(obj));
11736 LOCK();
11737 if (GC_toggleref_callback != 0) {
11738 if (!ensure_toggleref_capacity(1)) {
11739 res = GC_NO_MEMORY;
11740 } else {
11741 GC_toggleref_arr[GC_toggleref_array_size].strong_ref =
11742 is_strong_ref ? obj : (void *)GC_HIDE_POINTER(obj);
11743 if (is_strong_ref)
11744 GC_dirty(GC_toggleref_arr + GC_toggleref_array_size);
11745 GC_toggleref_array_size++;
11746 }
11747 }
11748 UNLOCK();
11749 return res;
11750 }
11751#endif
11752STATIC GC_await_finalize_proc GC_object_finalized_proc = 0;
11753GC_API void GC_CALL GC_set_await_finalize_proc(GC_await_finalize_proc fn)
11754{
11755 DCL_LOCK_STATE;
11756 LOCK();
11757 GC_object_finalized_proc = fn;
11758 UNLOCK();
11759}
11760GC_API GC_await_finalize_proc GC_CALL GC_get_await_finalize_proc(void)
11761{
11762 GC_await_finalize_proc fn;
11763 DCL_LOCK_STATE;
11764 LOCK();
11765 fn = GC_object_finalized_proc;
11766 UNLOCK();
11767 return fn;
11768}
11769#ifndef GC_LONG_REFS_NOT_NEEDED
11770 GC_API int GC_CALL GC_register_long_link(void * * link, const void * obj)
11771 {
11772 if (((word)link & (ALIGNMENT-1)) != 0 || !NONNULL_ARG_NOT_NULL(link))
11773 ABORT("Bad arg to GC_register_long_link");
11774 return GC_register_disappearing_link_inner(&GC_ll_hashtbl, link, obj,
11775 "long dl");
11776 }
11777 GC_API int GC_CALL GC_unregister_long_link(void * * link)
11778 {
11779 struct disappearing_link *curr_dl;
11780 DCL_LOCK_STATE;
11781 if (((word)link & (ALIGNMENT-1)) != 0) return(0);
11782 LOCK();
11783 curr_dl = GC_unregister_disappearing_link_inner(&GC_ll_hashtbl, link);
11784 UNLOCK();
11785 if (NULL == curr_dl) return 0;
11786 FREE_DL_ENTRY(curr_dl);
11787 return 1;
11788 }
11789#endif
11790#ifndef GC_MOVE_DISAPPEARING_LINK_NOT_NEEDED
11791 STATIC int GC_move_disappearing_link_inner(
11792 struct dl_hashtbl_s *dl_hashtbl,
11793 void **link, void **new_link)
11794 {
11795 struct disappearing_link *curr_dl, *new_dl;
11796 struct disappearing_link *prev_dl = NULL;
11797 size_t curr_index, new_index;
11798 word curr_hidden_link, new_hidden_link;
11799 GC_ASSERT(I_HOLD_LOCK());
11800 if (EXPECT(NULL == dl_hashtbl -> head, FALSE)) return GC_NOT_FOUND;
11801 curr_index = HASH2(link, dl_hashtbl -> log_size);
11802 curr_hidden_link = GC_HIDE_POINTER(link);
11803 for (curr_dl = dl_hashtbl -> head[curr_index]; curr_dl;
11804 curr_dl = dl_next(curr_dl)) {
11805 if (curr_dl -> dl_hidden_link == curr_hidden_link)
11806 break;
11807 prev_dl = curr_dl;
11808 }
11809 if (EXPECT(NULL == curr_dl, FALSE)) {
11810 return GC_NOT_FOUND;
11811 } else if (link == new_link) {
11812 return GC_SUCCESS;
11813 }
11814 new_index = HASH2(new_link, dl_hashtbl -> log_size);
11815 new_hidden_link = GC_HIDE_POINTER(new_link);
11816 for (new_dl = dl_hashtbl -> head[new_index]; new_dl;
11817 new_dl = dl_next(new_dl)) {
11818 if (new_dl -> dl_hidden_link == new_hidden_link) {
11819 return GC_DUPLICATE;
11820 }
11821 }
11822 if (NULL == prev_dl) {
11823 dl_hashtbl -> head[curr_index] = dl_next(curr_dl);
11824 } else {
11825 dl_set_next(prev_dl, dl_next(curr_dl));
11826 GC_dirty(prev_dl);
11827 }
11828 curr_dl -> dl_hidden_link = new_hidden_link;
11829 dl_set_next(curr_dl, dl_hashtbl -> head[new_index]);
11830 dl_hashtbl -> head[new_index] = curr_dl;
11831 GC_dirty(curr_dl);
11832 GC_dirty(dl_hashtbl->head);
11833 return GC_SUCCESS;
11834 }
11835 GC_API int GC_CALL GC_move_disappearing_link(void **link, void **new_link)
11836 {
11837 int result;
11838 DCL_LOCK_STATE;
11839 if (((word)new_link & (ALIGNMENT-1)) != 0
11840 || !NONNULL_ARG_NOT_NULL(new_link))
11841 ABORT("Bad new_link arg to GC_move_disappearing_link");
11842 if (((word)link & (ALIGNMENT-1)) != 0)
11843 return GC_NOT_FOUND;
11844 LOCK();
11845 result = GC_move_disappearing_link_inner(&GC_dl_hashtbl, link, new_link);
11846 UNLOCK();
11847 return result;
11848 }
11849#ifndef GC_LONG_REFS_NOT_NEEDED
11850 GC_API int GC_CALL GC_move_long_link(void **link, void **new_link)
11851 {
11852 int result;
11853 DCL_LOCK_STATE;
11854 if (((word)new_link & (ALIGNMENT-1)) != 0
11855 || !NONNULL_ARG_NOT_NULL(new_link))
11856 ABORT("Bad new_link arg to GC_move_long_link");
11857 if (((word)link & (ALIGNMENT-1)) != 0)
11858 return GC_NOT_FOUND;
11859 LOCK();
11860 result = GC_move_disappearing_link_inner(&GC_ll_hashtbl, link, new_link);
11861 UNLOCK();
11862 return result;
11863 }
11864#endif
11865#endif
11866#if defined(_MSC_VER) && defined(I386)
11867 GC_ATTR_NOINLINE
11868#endif
11869STATIC void GC_normal_finalize_mark_proc(ptr_t p)
11870{
11871 GC_mark_stack_top = GC_push_obj(p, HDR(p), GC_mark_stack_top,
11872 GC_mark_stack + GC_mark_stack_size);
11873}
11874STATIC void GC_ignore_self_finalize_mark_proc(ptr_t p)
11875{
11876 hdr * hhdr = HDR(p);
11877 word descr = hhdr -> hb_descr;
11878 ptr_t q;
11879 ptr_t scan_limit;
11880 ptr_t target_limit = p + hhdr -> hb_sz - 1;
11881 if ((descr & GC_DS_TAGS) == GC_DS_LENGTH) {
11882 scan_limit = p + descr - sizeof(word);
11883 } else {
11884 scan_limit = target_limit + 1 - sizeof(word);
11885 }
11886 for (q = p; (word)q <= (word)scan_limit; q += ALIGNMENT) {
11887 word r = *(word *)q;
11888 if (r < (word)p || r > (word)target_limit) {
11889 GC_PUSH_ONE_HEAP(r, q, GC_mark_stack_top);
11890 }
11891 }
11892}
11893STATIC void GC_null_finalize_mark_proc(ptr_t p GC_ATTR_UNUSED) {}
11894STATIC void GC_unreachable_finalize_mark_proc(ptr_t p)
11895{
11896 GC_normal_finalize_mark_proc(p);
11897}
11898STATIC void GC_register_finalizer_inner(void * obj,
11899 GC_finalization_proc fn, void *cd,
11900 GC_finalization_proc *ofn, void **ocd,
11901 finalization_mark_proc mp)
11902{
11903 struct finalizable_object * curr_fo;
11904 size_t index;
11905 struct finalizable_object *new_fo = 0;
11906 hdr *hhdr = NULL;
11907 DCL_LOCK_STATE;
11908 if (EXPECT(GC_find_leak, FALSE)) return;
11909 LOCK();
11910 if (EXPECT(NULL == GC_fnlz_roots.fo_head, FALSE)
11911 || EXPECT(GC_fo_entries > ((word)1 << GC_log_fo_table_size), FALSE)) {
11912 GC_grow_table((struct hash_chain_entry ***)&GC_fnlz_roots.fo_head,
11913 &GC_log_fo_table_size, &GC_fo_entries);
11914 GC_COND_LOG_PRINTF("Grew fo table to %u entries\n",
11915 1U << GC_log_fo_table_size);
11916 }
11917 for (;;) {
11918 struct finalizable_object *prev_fo = NULL;
11919 GC_oom_func oom_fn;
11920 index = HASH2(obj, GC_log_fo_table_size);
11921 curr_fo = GC_fnlz_roots.fo_head[index];
11922 while (curr_fo != 0) {
11923 GC_ASSERT(GC_size(curr_fo) >= sizeof(struct finalizable_object));
11924 if (curr_fo -> fo_hidden_base == GC_HIDE_POINTER(obj)) {
11925 if (ocd) *ocd = (void *) (curr_fo -> fo_client_data);
11926 if (ofn) *ofn = curr_fo -> fo_fn;
11927 if (prev_fo == 0) {
11928 GC_fnlz_roots.fo_head[index] = fo_next(curr_fo);
11929 } else {
11930 fo_set_next(prev_fo, fo_next(curr_fo));
11931 GC_dirty(prev_fo);
11932 }
11933 if (fn == 0) {
11934 GC_fo_entries--;
11935#if !defined(THREADS) && !defined(DBG_HDRS_ALL)
11936 GC_free((void *)curr_fo);
11937#endif
11938 } else {
11939 curr_fo -> fo_fn = fn;
11940 curr_fo -> fo_client_data = (ptr_t)cd;
11941 curr_fo -> fo_mark_proc = mp;
11942 GC_dirty(curr_fo);
11943 if (prev_fo == 0) {
11944 GC_fnlz_roots.fo_head[index] = curr_fo;
11945 } else {
11946 fo_set_next(prev_fo, curr_fo);
11947 GC_dirty(prev_fo);
11948 }
11949 }
11950 if (NULL == prev_fo)
11951 GC_dirty(GC_fnlz_roots.fo_head + index);
11952 UNLOCK();
11953#ifndef DBG_HDRS_ALL
11954 GC_free((void *)new_fo);
11955#endif
11956 return;
11957 }
11958 prev_fo = curr_fo;
11959 curr_fo = fo_next(curr_fo);
11960 }
11961 if (EXPECT(new_fo != 0, FALSE)) {
11962 GC_ASSERT(fn != 0);
11963#ifdef LINT2
11964 if (NULL == hhdr) ABORT("Bad hhdr in GC_register_finalizer_inner");
11965#endif
11966 break;
11967 }
11968 if (fn == 0) {
11969 if (ocd) *ocd = 0;
11970 if (ofn) *ofn = 0;
11971 UNLOCK();
11972 return;
11973 }
11974 GET_HDR(obj, hhdr);
11975 if (EXPECT(0 == hhdr, FALSE)) {
11976 if (ocd) *ocd = 0;
11977 if (ofn) *ofn = 0;
11978 UNLOCK();
11979 return;
11980 }
11981 new_fo = (struct finalizable_object *)
11982 GC_INTERNAL_MALLOC(sizeof(struct finalizable_object),NORMAL);
11983 if (EXPECT(new_fo != 0, TRUE))
11984 break;
11985 oom_fn = GC_oom_fn;
11986 UNLOCK();
11987 new_fo = (struct finalizable_object *)
11988 (*oom_fn)(sizeof(struct finalizable_object));
11989 if (0 == new_fo) {
11990 return;
11991 }
11992 LOCK();
11993 }
11994 GC_ASSERT(GC_size(new_fo) >= sizeof(struct finalizable_object));
11995 if (ocd) *ocd = 0;
11996 if (ofn) *ofn = 0;
11997 new_fo -> fo_hidden_base = GC_HIDE_POINTER(obj);
11998 new_fo -> fo_fn = fn;
11999 new_fo -> fo_client_data = (ptr_t)cd;
12000 new_fo -> fo_object_size = hhdr -> hb_sz;
12001 new_fo -> fo_mark_proc = mp;
12002 fo_set_next(new_fo, GC_fnlz_roots.fo_head[index]);
12003 GC_dirty(new_fo);
12004 GC_fo_entries++;
12005 GC_fnlz_roots.fo_head[index] = new_fo;
12006 GC_dirty(GC_fnlz_roots.fo_head + index);
12007 UNLOCK();
12008}
12009GC_API void GC_CALL GC_register_finalizer(void * obj,
12010 GC_finalization_proc fn, void * cd,
12011 GC_finalization_proc *ofn, void ** ocd)
12012{
12013 GC_register_finalizer_inner(obj, fn, cd, ofn,
12014 ocd, GC_normal_finalize_mark_proc);
12015}
12016GC_API void GC_CALL GC_register_finalizer_ignore_self(void * obj,
12017 GC_finalization_proc fn, void * cd,
12018 GC_finalization_proc *ofn, void ** ocd)
12019{
12020 GC_register_finalizer_inner(obj, fn, cd, ofn,
12021 ocd, GC_ignore_self_finalize_mark_proc);
12022}
12023GC_API void GC_CALL GC_register_finalizer_no_order(void * obj,
12024 GC_finalization_proc fn, void * cd,
12025 GC_finalization_proc *ofn, void ** ocd)
12026{
12027 GC_register_finalizer_inner(obj, fn, cd, ofn,
12028 ocd, GC_null_finalize_mark_proc);
12029}
12030static GC_bool need_unreachable_finalization = FALSE;
12031GC_API void GC_CALL GC_register_finalizer_unreachable(void * obj,
12032 GC_finalization_proc fn, void * cd,
12033 GC_finalization_proc *ofn, void ** ocd)
12034{
12035 need_unreachable_finalization = TRUE;
12036 GC_ASSERT(GC_java_finalization);
12037 GC_register_finalizer_inner(obj, fn, cd, ofn,
12038 ocd, GC_unreachable_finalize_mark_proc);
12039}
12040#ifndef NO_DEBUGGING
12041 STATIC void GC_dump_finalization_links(
12042 const struct dl_hashtbl_s *dl_hashtbl)
12043 {
12044 size_t dl_size = (size_t)1 << dl_hashtbl -> log_size;
12045 size_t i;
12046 if (NULL == dl_hashtbl -> head) return;
12047 for (i = 0; i < dl_size; i++) {
12048 struct disappearing_link *curr_dl;
12049 for (curr_dl = dl_hashtbl -> head[i]; curr_dl != 0;
12050 curr_dl = dl_next(curr_dl)) {
12051 ptr_t real_ptr = (ptr_t)GC_REVEAL_POINTER(curr_dl->dl_hidden_obj);
12052 ptr_t real_link = (ptr_t)GC_REVEAL_POINTER(curr_dl->dl_hidden_link);
12053 GC_printf("Object: %p, link: %p\n",
12054 (void *)real_ptr, (void *)real_link);
12055 }
12056 }
12057 }
12058 GC_API void GC_CALL GC_dump_finalization(void)
12059 {
12060 struct finalizable_object * curr_fo;
12061 size_t i;
12062 size_t fo_size = GC_fnlz_roots.fo_head == NULL ? 0 :
12063 (size_t)1 << GC_log_fo_table_size;
12064 GC_printf("Disappearing (short) links:\n");
12065 GC_dump_finalization_links(&GC_dl_hashtbl);
12066#ifndef GC_LONG_REFS_NOT_NEEDED
12067 GC_printf("Disappearing long links:\n");
12068 GC_dump_finalization_links(&GC_ll_hashtbl);
12069#endif
12070 GC_printf("Finalizers:\n");
12071 for (i = 0; i < fo_size; i++) {
12072 for (curr_fo = GC_fnlz_roots.fo_head[i];
12073 curr_fo != NULL; curr_fo = fo_next(curr_fo)) {
12074 ptr_t real_ptr = (ptr_t)GC_REVEAL_POINTER(curr_fo->fo_hidden_base);
12075 GC_printf("Finalizable object: %p\n", (void *)real_ptr);
12076 }
12077 }
12078 }
12079#endif
12080#ifndef SMALL_CONFIG
12081 STATIC word GC_old_dl_entries = 0;
12082#ifndef GC_LONG_REFS_NOT_NEEDED
12083 STATIC word GC_old_ll_entries = 0;
12084#endif
12085#endif
12086#ifndef THREADS
12087 STATIC int GC_finalizer_nested = 0;
12088 STATIC unsigned GC_finalizer_skipped = 0;
12089 STATIC unsigned char *GC_check_finalizer_nested(void)
12090 {
12091 unsigned nesting_level = *(unsigned char *)&GC_finalizer_nested;
12092 if (nesting_level) {
12093 if (++GC_finalizer_skipped < (1U << nesting_level)) return NULL;
12094 GC_finalizer_skipped = 0;
12095 }
12096 *(char *)&GC_finalizer_nested = (char)(nesting_level + 1);
12097 return (unsigned char *)&GC_finalizer_nested;
12098 }
12099#endif
12100GC_INLINE void GC_make_disappearing_links_disappear(
12101 struct dl_hashtbl_s* dl_hashtbl,
12102 GC_bool is_remove_dangling)
12103{
12104 size_t i;
12105 size_t dl_size = (size_t)1 << dl_hashtbl -> log_size;
12106 GC_bool needs_barrier = FALSE;
12107 GC_ASSERT(I_HOLD_LOCK());
12108 if (NULL == dl_hashtbl -> head) return;
12109 for (i = 0; i < dl_size; i++) {
12110 struct disappearing_link *curr_dl, *next_dl;
12111 struct disappearing_link *prev_dl = NULL;
12112 for (curr_dl = dl_hashtbl->head[i]; curr_dl != NULL; curr_dl = next_dl) {
12113 next_dl = dl_next(curr_dl);
12114 if (is_remove_dangling) {
12115 ptr_t real_link = (ptr_t)GC_base(GC_REVEAL_POINTER(
12116 curr_dl->dl_hidden_link));
12117 if (NULL == real_link || EXPECT(GC_is_marked(real_link), TRUE)) {
12118 prev_dl = curr_dl;
12119 continue;
12120 }
12121 } else {
12122 if (EXPECT(GC_is_marked((ptr_t)GC_REVEAL_POINTER(
12123 curr_dl->dl_hidden_obj)), TRUE)) {
12124 prev_dl = curr_dl;
12125 continue;
12126 }
12127 *(ptr_t *)GC_REVEAL_POINTER(curr_dl->dl_hidden_link) = NULL;
12128 }
12129 if (NULL == prev_dl) {
12130 dl_hashtbl -> head[i] = next_dl;
12131 needs_barrier = TRUE;
12132 } else {
12133 dl_set_next(prev_dl, next_dl);
12134 GC_dirty(prev_dl);
12135 }
12136 GC_clear_mark_bit(curr_dl);
12137 dl_hashtbl -> entries--;
12138 }
12139 }
12140 if (needs_barrier)
12141 GC_dirty(dl_hashtbl -> head);
12142}
12143GC_INNER void GC_finalize(void)
12144{
12145 struct finalizable_object * curr_fo, * prev_fo, * next_fo;
12146 ptr_t real_ptr;
12147 size_t i;
12148 size_t fo_size = GC_fnlz_roots.fo_head == NULL ? 0 :
12149 (size_t)1 << GC_log_fo_table_size;
12150 GC_bool needs_barrier = FALSE;
12151 GC_ASSERT(I_HOLD_LOCK());
12152#ifndef SMALL_CONFIG
12153 GC_old_dl_entries = GC_dl_hashtbl.entries;
12154#ifndef GC_LONG_REFS_NOT_NEEDED
12155 GC_old_ll_entries = GC_ll_hashtbl.entries;
12156#endif
12157#endif
12158#ifndef GC_TOGGLE_REFS_NOT_NEEDED
12159 GC_mark_togglerefs();
12160#endif
12161 GC_make_disappearing_links_disappear(&GC_dl_hashtbl, FALSE);
12162 GC_ASSERT(GC_mark_state == MS_NONE);
12163 for (i = 0; i < fo_size; i++) {
12164 for (curr_fo = GC_fnlz_roots.fo_head[i];
12165 curr_fo != NULL; curr_fo = fo_next(curr_fo)) {
12166 GC_ASSERT(GC_size(curr_fo) >= sizeof(struct finalizable_object));
12167 real_ptr = (ptr_t)GC_REVEAL_POINTER(curr_fo->fo_hidden_base);
12168 if (!GC_is_marked(real_ptr)) {
12169 GC_MARKED_FOR_FINALIZATION(real_ptr);
12170 GC_MARK_FO(real_ptr, curr_fo -> fo_mark_proc);
12171 if (GC_is_marked(real_ptr)) {
12172 WARN("Finalization cycle involving %p\n", real_ptr);
12173 }
12174 }
12175 }
12176 }
12177 GC_bytes_finalized = 0;
12178 for (i = 0; i < fo_size; i++) {
12179 curr_fo = GC_fnlz_roots.fo_head[i];
12180 prev_fo = 0;
12181 while (curr_fo != 0) {
12182 real_ptr = (ptr_t)GC_REVEAL_POINTER(curr_fo->fo_hidden_base);
12183 if (!GC_is_marked(real_ptr)) {
12184 if (!GC_java_finalization) {
12185 GC_set_mark_bit(real_ptr);
12186 }
12187 next_fo = fo_next(curr_fo);
12188 if (NULL == prev_fo) {
12189 GC_fnlz_roots.fo_head[i] = next_fo;
12190 if (GC_object_finalized_proc) {
12191 GC_dirty(GC_fnlz_roots.fo_head + i);
12192 } else {
12193 needs_barrier = TRUE;
12194 }
12195 } else {
12196 fo_set_next(prev_fo, next_fo);
12197 GC_dirty(prev_fo);
12198 }
12199 GC_fo_entries--;
12200 if (GC_object_finalized_proc)
12201 GC_object_finalized_proc(real_ptr);
12202 fo_set_next(curr_fo, GC_fnlz_roots.finalize_now);
12203 GC_dirty(curr_fo);
12204 SET_FINALIZE_NOW(curr_fo);
12205 curr_fo -> fo_hidden_base =
12206 (word)GC_REVEAL_POINTER(curr_fo -> fo_hidden_base);
12207 GC_bytes_finalized +=
12208 curr_fo -> fo_object_size
12209 + sizeof(struct finalizable_object);
12210 GC_ASSERT(GC_is_marked(GC_base(curr_fo)));
12211 curr_fo = next_fo;
12212 } else {
12213 prev_fo = curr_fo;
12214 curr_fo = fo_next(curr_fo);
12215 }
12216 }
12217 }
12218 if (GC_java_finalization) {
12219 for (curr_fo = GC_fnlz_roots.finalize_now;
12220 curr_fo != NULL; curr_fo = fo_next(curr_fo)) {
12221 real_ptr = (ptr_t)curr_fo -> fo_hidden_base;
12222 if (!GC_is_marked(real_ptr)) {
12223 if (curr_fo -> fo_mark_proc == GC_null_finalize_mark_proc) {
12224 GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
12225 }
12226 if (curr_fo -> fo_mark_proc != GC_unreachable_finalize_mark_proc) {
12227 GC_set_mark_bit(real_ptr);
12228 }
12229 }
12230 }
12231 if (need_unreachable_finalization) {
12232 curr_fo = GC_fnlz_roots.finalize_now;
12233 GC_ASSERT(NULL == curr_fo || GC_fnlz_roots.fo_head != NULL);
12234 prev_fo = NULL;
12235 while (curr_fo != NULL) {
12236 next_fo = fo_next(curr_fo);
12237 if (curr_fo -> fo_mark_proc == GC_unreachable_finalize_mark_proc) {
12238 real_ptr = (ptr_t)curr_fo -> fo_hidden_base;
12239 if (!GC_is_marked(real_ptr)) {
12240 GC_set_mark_bit(real_ptr);
12241 } else {
12242 if (NULL == prev_fo) {
12243 SET_FINALIZE_NOW(next_fo);
12244 } else {
12245 fo_set_next(prev_fo, next_fo);
12246 GC_dirty(prev_fo);
12247 }
12248 curr_fo -> fo_hidden_base =
12249 GC_HIDE_POINTER(curr_fo -> fo_hidden_base);
12250 GC_bytes_finalized -=
12251 curr_fo->fo_object_size + sizeof(struct finalizable_object);
12252 i = HASH2(real_ptr, GC_log_fo_table_size);
12253 fo_set_next(curr_fo, GC_fnlz_roots.fo_head[i]);
12254 GC_dirty(curr_fo);
12255 GC_fo_entries++;
12256 GC_fnlz_roots.fo_head[i] = curr_fo;
12257 curr_fo = prev_fo;
12258 needs_barrier = TRUE;
12259 }
12260 }
12261 prev_fo = curr_fo;
12262 curr_fo = next_fo;
12263 }
12264 }
12265 }
12266 if (needs_barrier)
12267 GC_dirty(GC_fnlz_roots.fo_head);
12268 GC_make_disappearing_links_disappear(&GC_dl_hashtbl, TRUE);
12269#ifndef GC_TOGGLE_REFS_NOT_NEEDED
12270 GC_clear_togglerefs();
12271#endif
12272#ifndef GC_LONG_REFS_NOT_NEEDED
12273 GC_make_disappearing_links_disappear(&GC_ll_hashtbl, FALSE);
12274 GC_make_disappearing_links_disappear(&GC_ll_hashtbl, TRUE);
12275#endif
12276 if (GC_fail_count) {
12277#ifdef THREADS
12278 GC_reset_finalizer_nested();
12279#else
12280 GC_finalizer_nested = 0;
12281#endif
12282 }
12283}
12284#ifndef JAVA_FINALIZATION_NOT_NEEDED
12285 STATIC void GC_enqueue_all_finalizers(void)
12286 {
12287 struct finalizable_object * next_fo;
12288 size_t i;
12289 size_t fo_size = GC_fnlz_roots.fo_head == NULL ? 0 :
12290 (size_t)1 << GC_log_fo_table_size;
12291 GC_ASSERT(I_HOLD_LOCK());
12292 GC_bytes_finalized = 0;
12293 for (i = 0; i < fo_size; i++) {
12294 struct finalizable_object * curr_fo = GC_fnlz_roots.fo_head[i];
12295 GC_fnlz_roots.fo_head[i] = NULL;
12296 while (curr_fo != NULL) {
12297 ptr_t real_ptr = (ptr_t)GC_REVEAL_POINTER(curr_fo->fo_hidden_base);
12298 GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
12299 GC_set_mark_bit(real_ptr);
12300 next_fo = fo_next(curr_fo);
12301 fo_set_next(curr_fo, GC_fnlz_roots.finalize_now);
12302 GC_dirty(curr_fo);
12303 SET_FINALIZE_NOW(curr_fo);
12304 curr_fo -> fo_hidden_base =
12305 (word)GC_REVEAL_POINTER(curr_fo -> fo_hidden_base);
12306 GC_bytes_finalized +=
12307 curr_fo -> fo_object_size + sizeof(struct finalizable_object);
12308 curr_fo = next_fo;
12309 }
12310 }
12311 GC_fo_entries = 0;
12312 }
12313 GC_API void GC_CALL GC_finalize_all(void)
12314 {
12315 DCL_LOCK_STATE;
12316 LOCK();
12317 while (GC_fo_entries > 0) {
12318 GC_enqueue_all_finalizers();
12319 UNLOCK();
12320 GC_invoke_finalizers();
12321 LOCK();
12322 }
12323 UNLOCK();
12324 }
12325#endif
12326GC_API int GC_CALL GC_should_invoke_finalizers(void)
12327{
12328#ifdef AO_HAVE_load
12329 return AO_load((volatile AO_t *)&GC_fnlz_roots.finalize_now) != 0;
12330#else
12331 return GC_fnlz_roots.finalize_now != NULL;
12332#endif
12333}
12334GC_API int GC_CALL GC_invoke_finalizers(void)
12335{
12336 int count = 0;
12337 word bytes_freed_before = 0;
12338 DCL_LOCK_STATE;
12339 while (GC_should_invoke_finalizers()) {
12340 struct finalizable_object * curr_fo;
12341#ifdef THREADS
12342 LOCK();
12343#endif
12344 if (count == 0) {
12345 bytes_freed_before = GC_bytes_freed;
12346 }
12347 curr_fo = GC_fnlz_roots.finalize_now;
12348#ifdef THREADS
12349 if (curr_fo != NULL)
12350 SET_FINALIZE_NOW(fo_next(curr_fo));
12351 UNLOCK();
12352 if (curr_fo == 0) break;
12353#else
12354 GC_fnlz_roots.finalize_now = fo_next(curr_fo);
12355#endif
12356 fo_set_next(curr_fo, 0);
12357 (*(curr_fo -> fo_fn))((ptr_t)(curr_fo -> fo_hidden_base),
12358 curr_fo -> fo_client_data);
12359 curr_fo -> fo_client_data = 0;
12360 ++count;
12361 }
12362 if (count != 0
12363#if defined(THREADS) && !defined(THREAD_SANITIZER)
12364 && bytes_freed_before != GC_bytes_freed
12365#endif
12366 ) {
12367 LOCK();
12368 GC_finalizer_bytes_freed += (GC_bytes_freed - bytes_freed_before);
12369 UNLOCK();
12370 }
12371 return count;
12372}
12373static word last_finalizer_notification = 0;
12374GC_INNER void GC_notify_or_invoke_finalizers(void)
12375{
12376 GC_finalizer_notifier_proc notifier_fn = 0;
12377#if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
12378 static word last_back_trace_gc_no = 1;
12379#endif
12380 DCL_LOCK_STATE;
12381#if defined(THREADS) && !defined(KEEP_BACK_PTRS) \
12382 && !defined(MAKE_BACK_GRAPH)
12383 if (!GC_should_invoke_finalizers())
12384 return;
12385#endif
12386 LOCK();
12387#if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
12388 if (GC_gc_no > last_back_trace_gc_no) {
12389#ifdef KEEP_BACK_PTRS
12390 long i;
12391 last_back_trace_gc_no = GC_WORD_MAX;
12392 for (i = 0; i < GC_backtraces; ++i) {
12393 UNLOCK();
12394 GC_generate_random_backtrace_no_gc();
12395 LOCK();
12396 }
12397 last_back_trace_gc_no = GC_gc_no;
12398#endif
12399#ifdef MAKE_BACK_GRAPH
12400 if (GC_print_back_height) {
12401 GC_print_back_graph_stats();
12402 }
12403#endif
12404 }
12405#endif
12406 if (NULL == GC_fnlz_roots.finalize_now) {
12407 UNLOCK();
12408 return;
12409 }
12410 if (!GC_finalize_on_demand) {
12411 unsigned char *pnested = GC_check_finalizer_nested();
12412 UNLOCK();
12413 if (pnested != NULL) {
12414 (void) GC_invoke_finalizers();
12415 *pnested = 0;
12416#ifndef THREADS
12417 GC_ASSERT(NULL == GC_fnlz_roots.finalize_now);
12418#endif
12419 }
12420 return;
12421 }
12422 if (last_finalizer_notification != GC_gc_no) {
12423 notifier_fn = GC_finalizer_notifier;
12424 last_finalizer_notification = GC_gc_no;
12425 }
12426 UNLOCK();
12427 if (notifier_fn != 0)
12428 (*notifier_fn)();
12429}
12430#ifndef SMALL_CONFIG
12431#ifndef GC_LONG_REFS_NOT_NEEDED
12432#define IF_LONG_REFS_PRESENT_ELSE(x,y) (x)
12433#else
12434#define IF_LONG_REFS_PRESENT_ELSE(x,y) (y)
12435#endif
12436 GC_INNER void GC_print_finalization_stats(void)
12437 {
12438 struct finalizable_object *fo;
12439 unsigned long ready = 0;
12440 GC_log_printf("%lu finalization entries;"
12441 " %lu/%lu short/long disappearing links alive\n",
12442 (unsigned long)GC_fo_entries,
12443 (unsigned long)GC_dl_hashtbl.entries,
12444 (unsigned long)IF_LONG_REFS_PRESENT_ELSE(
12445 GC_ll_hashtbl.entries, 0));
12446 for (fo = GC_fnlz_roots.finalize_now; fo != NULL; fo = fo_next(fo))
12447 ++ready;
12448 GC_log_printf("%lu finalization-ready objects;"
12449 " %ld/%ld short/long links cleared\n",
12450 ready,
12451 (long)GC_old_dl_entries - (long)GC_dl_hashtbl.entries,
12452 (long)IF_LONG_REFS_PRESENT_ELSE(
12453 GC_old_ll_entries - GC_ll_hashtbl.entries, 0));
12454 }
12455#endif
12456#endif
12457#ifdef ENABLE_DISCLAIM
12458#ifndef GC_DISCLAIM_H
12459#define GC_DISCLAIM_H
12460#ifdef __cplusplus
12461 extern "C" {
12462#endif
12463GC_API void GC_CALL GC_init_finalized_malloc(void);
12464typedef int (GC_CALLBACK * GC_disclaim_proc)(void * );
12465GC_API void GC_CALL GC_register_disclaim_proc(int ,
12466 GC_disclaim_proc ,
12467 int ) GC_ATTR_NONNULL(2);
12468struct GC_finalizer_closure {
12469 GC_finalization_proc proc;
12470 void *cd;
12471};
12472GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
12473 GC_finalized_malloc(size_t ,
12474 const struct GC_finalizer_closure * ) GC_ATTR_NONNULL(2);
12475#ifdef __cplusplus
12476 }
12477#endif
12478#endif
12479#if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
12480#define FINALIZER_CLOSURE_FLAG 0x2
12481#else
12482#define FINALIZER_CLOSURE_FLAG 0x1
12483#endif
12484STATIC int GC_CALLBACK GC_finalized_disclaim(void *obj)
12485{
12486 word fc_word = *(word *)obj;
12487 if ((fc_word & FINALIZER_CLOSURE_FLAG) != 0) {
12488 const struct GC_finalizer_closure *fc
12489 = (struct GC_finalizer_closure *)(fc_word
12490 & ~(word)FINALIZER_CLOSURE_FLAG);
12491 GC_ASSERT(!GC_find_leak);
12492 (*fc->proc)((word *)obj + 1, fc->cd);
12493 }
12494 return 0;
12495}
12496GC_API void GC_CALL GC_init_finalized_malloc(void)
12497{
12498 DCL_LOCK_STATE;
12499 GC_init();
12500 LOCK();
12501 if (GC_finalized_kind != 0) {
12502 UNLOCK();
12503 return;
12504 }
12505 GC_register_displacement_inner(sizeof(word));
12506 GC_register_displacement_inner(FINALIZER_CLOSURE_FLAG);
12507 GC_register_displacement_inner(sizeof(oh) + FINALIZER_CLOSURE_FLAG);
12508 GC_finalized_kind = GC_new_kind_inner(GC_new_free_list_inner(),
12509 GC_DS_LENGTH, TRUE, TRUE);
12510 GC_ASSERT(GC_finalized_kind != 0);
12511 GC_register_disclaim_proc(GC_finalized_kind, GC_finalized_disclaim, TRUE);
12512 UNLOCK();
12513}
12514GC_API void GC_CALL GC_register_disclaim_proc(int kind, GC_disclaim_proc proc,
12515 int mark_unconditionally)
12516{
12517 GC_ASSERT((unsigned)kind < MAXOBJKINDS);
12518 GC_ASSERT(NONNULL_ARG_NOT_NULL(proc));
12519 if (!EXPECT(GC_find_leak, FALSE)) {
12520 GC_obj_kinds[kind].ok_disclaim_proc = proc;
12521 GC_obj_kinds[kind].ok_mark_unconditionally =
12522 (GC_bool)mark_unconditionally;
12523 }
12524}
12525GC_API GC_ATTR_MALLOC void * GC_CALL GC_finalized_malloc(size_t lb,
12526 const struct GC_finalizer_closure *fclos)
12527{
12528 word *op;
12529 GC_ASSERT(GC_finalized_kind != 0);
12530 GC_ASSERT(NONNULL_ARG_NOT_NULL(fclos));
12531 GC_ASSERT(((word)fclos & FINALIZER_CLOSURE_FLAG) == 0);
12532 op = (word *)GC_malloc_kind(SIZET_SAT_ADD(lb, sizeof(word)),
12533 GC_finalized_kind);
12534 if (EXPECT(NULL == op, FALSE))
12535 return NULL;
12536 *op = (word)fclos | FINALIZER_CLOSURE_FLAG;
12537 GC_dirty(op);
12538 REACHABLE_AFTER_DIRTY(fclos);
12539 return op + 1;
12540}
12541#endif
12542#include <stdio.h>
12543#include <string.h>
12544STATIC GC_bool GC_alloc_reclaim_list(struct obj_kind *kind)
12545{
12546 struct hblk ** result = (struct hblk **)
12547 GC_scratch_alloc((MAXOBJGRANULES+1) * sizeof(struct hblk *));
12548 if (result == 0) return(FALSE);
12549 BZERO(result, (MAXOBJGRANULES+1)*sizeof(struct hblk *));
12550 kind -> ok_reclaim_list = result;
12551 return(TRUE);
12552}
12553GC_INNER ptr_t GC_alloc_large(size_t lb, int k, unsigned flags)
12554{
12555 struct hblk * h;
12556 word n_blocks;
12557 ptr_t result;
12558 GC_bool retry = FALSE;
12559 GC_ASSERT(I_HOLD_LOCK());
12560 lb = ROUNDUP_GRANULE_SIZE(lb);
12561 n_blocks = OBJ_SZ_TO_BLOCKS_CHECKED(lb);
12562 if (!EXPECT(GC_is_initialized, TRUE)) {
12563 DCL_LOCK_STATE;
12564 UNLOCK();
12565 GC_init();
12566 LOCK();
12567 }
12568 if (GC_incremental && !GC_dont_gc) {
12569 ENTER_GC();
12570 GC_collect_a_little_inner((int)n_blocks);
12571 EXIT_GC();
12572 }
12573 h = GC_allochblk(lb, k, flags);
12574#ifdef USE_MUNMAP
12575 if (0 == h) {
12576 GC_merge_unmapped();
12577 h = GC_allochblk(lb, k, flags);
12578 }
12579#endif
12580 while (0 == h && GC_collect_or_expand(n_blocks, flags != 0, retry)) {
12581 h = GC_allochblk(lb, k, flags);
12582 retry = TRUE;
12583 }
12584 if (h == 0) {
12585 result = 0;
12586 } else {
12587 size_t total_bytes = n_blocks * HBLKSIZE;
12588 if (n_blocks > 1) {
12589 GC_large_allocd_bytes += total_bytes;
12590 if (GC_large_allocd_bytes > GC_max_large_allocd_bytes)
12591 GC_max_large_allocd_bytes = GC_large_allocd_bytes;
12592 }
12593 result = h -> hb_body;
12594 }
12595 return result;
12596}
12597STATIC ptr_t GC_alloc_large_and_clear(size_t lb, int k, unsigned flags)
12598{
12599 ptr_t result;
12600 GC_ASSERT(I_HOLD_LOCK());
12601 result = GC_alloc_large(lb, k, flags);
12602 if (result != NULL
12603 && (GC_debugging_started || GC_obj_kinds[k].ok_init)) {
12604 word n_blocks = OBJ_SZ_TO_BLOCKS(lb);
12605 BZERO(result, n_blocks * HBLKSIZE);
12606 }
12607 return result;
12608}
12609STATIC void GC_extend_size_map(size_t i)
12610{
12611 size_t orig_granule_sz = ROUNDED_UP_GRANULES(i);
12612 size_t granule_sz;
12613 size_t byte_sz = GRANULES_TO_BYTES(orig_granule_sz);
12614 size_t smaller_than_i = byte_sz - (byte_sz >> 3);
12615 size_t low_limit;
12616 size_t number_of_objs;
12617 GC_ASSERT(I_HOLD_LOCK());
12618 GC_ASSERT(0 == GC_size_map[i]);
12619 if (0 == GC_size_map[smaller_than_i]) {
12620 low_limit = byte_sz - (byte_sz >> 2);
12621 granule_sz = orig_granule_sz;
12622 while (GC_size_map[low_limit] != 0)
12623 low_limit++;
12624 } else {
12625 low_limit = smaller_than_i + 1;
12626 while (GC_size_map[low_limit] != 0)
12627 low_limit++;
12628 granule_sz = ROUNDED_UP_GRANULES(low_limit);
12629 granule_sz += granule_sz >> 3;
12630 if (granule_sz < orig_granule_sz)
12631 granule_sz = orig_granule_sz;
12632 }
12633 granule_sz = (granule_sz + 1) & ~1;
12634 if (granule_sz > MAXOBJGRANULES)
12635 granule_sz = MAXOBJGRANULES;
12636 number_of_objs = HBLK_GRANULES / granule_sz;
12637 GC_ASSERT(number_of_objs != 0);
12638 granule_sz = (HBLK_GRANULES / number_of_objs) & ~1;
12639 byte_sz = GRANULES_TO_BYTES(granule_sz) - EXTRA_BYTES;
12640 for (; low_limit <= byte_sz; low_limit++)
12641 GC_size_map[low_limit] = granule_sz;
12642}
12643GC_INNER void * GC_generic_malloc_inner(size_t lb, int k)
12644{
12645 void *op;
12646 GC_ASSERT(I_HOLD_LOCK());
12647 GC_ASSERT(k < MAXOBJKINDS);
12648 if (SMALL_OBJ(lb)) {
12649 struct obj_kind * kind = GC_obj_kinds + k;
12650 size_t lg = GC_size_map[lb];
12651 void ** opp = &(kind -> ok_freelist[lg]);
12652 op = *opp;
12653 if (EXPECT(0 == op, FALSE)) {
12654 if (lg == 0) {
12655 if (!EXPECT(GC_is_initialized, TRUE)) {
12656 DCL_LOCK_STATE;
12657 UNLOCK();
12658 GC_init();
12659 LOCK();
12660 lg = GC_size_map[lb];
12661 }
12662 if (0 == lg) {
12663 GC_extend_size_map(lb);
12664 lg = GC_size_map[lb];
12665 GC_ASSERT(lg != 0);
12666 }
12667 opp = &(kind -> ok_freelist[lg]);
12668 op = *opp;
12669 }
12670 if (0 == op) {
12671 if (0 == kind -> ok_reclaim_list &&
12672 !GC_alloc_reclaim_list(kind))
12673 return NULL;
12674 op = GC_allocobj(lg, k);
12675 if (0 == op)
12676 return NULL;
12677 }
12678 }
12679 *opp = obj_link(op);
12680 obj_link(op) = 0;
12681 GC_bytes_allocd += GRANULES_TO_BYTES((word)lg);
12682 } else {
12683 op = (ptr_t)GC_alloc_large_and_clear(ADD_SLOP(lb), k, 0);
12684 if (op != NULL)
12685 GC_bytes_allocd += lb;
12686 }
12687 return op;
12688}
12689#if defined(DBG_HDRS_ALL) || defined(GC_GCJ_SUPPORT) \
12690 || !defined(GC_NO_FINALIZATION)
12691 GC_INNER void * GC_generic_malloc_inner_ignore_off_page(size_t lb, int k)
12692 {
12693 word lb_adjusted;
12694 void * op;
12695 GC_ASSERT(I_HOLD_LOCK());
12696 if (lb <= HBLKSIZE)
12697 return GC_generic_malloc_inner(lb, k);
12698 GC_ASSERT(k < MAXOBJKINDS);
12699 lb_adjusted = ADD_SLOP(lb);
12700 op = GC_alloc_large_and_clear(lb_adjusted, k, IGNORE_OFF_PAGE);
12701 if (op != NULL)
12702 GC_bytes_allocd += lb_adjusted;
12703 return op;
12704 }
12705#endif
12706#ifdef GC_COLLECT_AT_MALLOC
12707#if defined(CPPCHECK)
12708 size_t GC_dbg_collect_at_malloc_min_lb = 16*1024;
12709#else
12710 size_t GC_dbg_collect_at_malloc_min_lb = (GC_COLLECT_AT_MALLOC);
12711#endif
12712#endif
12713GC_API GC_ATTR_MALLOC void * GC_CALL GC_generic_malloc(size_t lb, int k)
12714{
12715 void * result;
12716 DCL_LOCK_STATE;
12717 GC_ASSERT(k < MAXOBJKINDS);
12718 if (EXPECT(GC_have_errors, FALSE))
12719 GC_print_all_errors();
12720 GC_INVOKE_FINALIZERS();
12721 GC_DBG_COLLECT_AT_MALLOC(lb);
12722 if (SMALL_OBJ(lb)) {
12723 LOCK();
12724 result = GC_generic_malloc_inner(lb, k);
12725 UNLOCK();
12726 } else {
12727 size_t lg;
12728 size_t lb_rounded;
12729 word n_blocks;
12730 GC_bool init;
12731 lg = ROUNDED_UP_GRANULES(lb);
12732 lb_rounded = GRANULES_TO_BYTES(lg);
12733 n_blocks = OBJ_SZ_TO_BLOCKS(lb_rounded);
12734 init = GC_obj_kinds[k].ok_init;
12735 LOCK();
12736 result = (ptr_t)GC_alloc_large(lb_rounded, k, 0);
12737 if (0 != result) {
12738 if (GC_debugging_started) {
12739 BZERO(result, n_blocks * HBLKSIZE);
12740 } else {
12741#ifdef THREADS
12742 ((word *)result)[0] = 0;
12743 ((word *)result)[1] = 0;
12744 ((word *)result)[GRANULES_TO_WORDS(lg)-1] = 0;
12745 ((word *)result)[GRANULES_TO_WORDS(lg)-2] = 0;
12746#endif
12747 }
12748 GC_bytes_allocd += lb_rounded;
12749 }
12750 UNLOCK();
12751 if (init && !GC_debugging_started && 0 != result) {
12752 BZERO(result, n_blocks * HBLKSIZE);
12753 }
12754 }
12755 if (0 == result) {
12756 return((*GC_get_oom_fn())(lb));
12757 } else {
12758 return(result);
12759 }
12760}
12761GC_API GC_ATTR_MALLOC void * GC_CALL GC_malloc_kind_global(size_t lb, int k)
12762{
12763 GC_ASSERT(k < MAXOBJKINDS);
12764 if (SMALL_OBJ(lb)) {
12765 void *op;
12766 void **opp;
12767 size_t lg;
12768 DCL_LOCK_STATE;
12769 GC_DBG_COLLECT_AT_MALLOC(lb);
12770 LOCK();
12771 lg = GC_size_map[lb];
12772 opp = &GC_obj_kinds[k].ok_freelist[lg];
12773 op = *opp;
12774 if (EXPECT(op != NULL, TRUE)) {
12775 if (k == PTRFREE) {
12776 *opp = obj_link(op);
12777 } else {
12778 GC_ASSERT(0 == obj_link(op)
12779 || ((word)obj_link(op)
12780 <= (word)GC_greatest_plausible_heap_addr
12781 && (word)obj_link(op)
12782 >= (word)GC_least_plausible_heap_addr));
12783 *opp = obj_link(op);
12784 obj_link(op) = 0;
12785 }
12786 GC_bytes_allocd += GRANULES_TO_BYTES((word)lg);
12787 UNLOCK();
12788 return op;
12789 }
12790 UNLOCK();
12791 }
12792 return GC_clear_stack(GC_generic_malloc(lb, k));
12793}
12794#if defined(THREADS) && !defined(THREAD_LOCAL_ALLOC)
12795 GC_API GC_ATTR_MALLOC void * GC_CALL GC_malloc_kind(size_t lb, int k)
12796 {
12797 return GC_malloc_kind_global(lb, k);
12798 }
12799#endif
12800GC_API GC_ATTR_MALLOC void * GC_CALL GC_malloc_atomic(size_t lb)
12801{
12802 return GC_malloc_kind(lb, PTRFREE);
12803}
12804GC_API GC_ATTR_MALLOC void * GC_CALL GC_malloc(size_t lb)
12805{
12806 return GC_malloc_kind(lb, NORMAL);
12807}
12808GC_API GC_ATTR_MALLOC void * GC_CALL GC_generic_malloc_uncollectable(
12809 size_t lb, int k)
12810{
12811 void *op;
12812 DCL_LOCK_STATE;
12813 GC_ASSERT(k < MAXOBJKINDS);
12814 if (SMALL_OBJ(lb)) {
12815 void **opp;
12816 size_t lg;
12817 GC_DBG_COLLECT_AT_MALLOC(lb);
12818 if (EXTRA_BYTES != 0 && lb != 0) lb--;
12819 LOCK();
12820 lg = GC_size_map[lb];
12821 opp = &GC_obj_kinds[k].ok_freelist[lg];
12822 op = *opp;
12823 if (EXPECT(op != NULL, TRUE)) {
12824 *opp = obj_link(op);
12825 obj_link(op) = 0;
12826 GC_bytes_allocd += GRANULES_TO_BYTES((word)lg);
12827 GC_non_gc_bytes += GRANULES_TO_BYTES((word)lg);
12828 UNLOCK();
12829 } else {
12830 UNLOCK();
12831 op = GC_generic_malloc(lb, k);
12832 }
12833 GC_ASSERT(0 == op || GC_is_marked(op));
12834 } else {
12835 op = GC_generic_malloc(lb, k);
12836 if (op ) {
12837 hdr * hhdr = HDR(op);
12838 GC_ASSERT(((word)op & (HBLKSIZE - 1)) == 0);
12839 LOCK();
12840 set_mark_bit_from_hdr(hhdr, 0);
12841#ifndef THREADS
12842 GC_ASSERT(hhdr -> hb_n_marks == 0);
12843#endif
12844 hhdr -> hb_n_marks = 1;
12845 UNLOCK();
12846 }
12847 }
12848 return op;
12849}
12850GC_API GC_ATTR_MALLOC void * GC_CALL GC_malloc_uncollectable(size_t lb)
12851{
12852 return GC_generic_malloc_uncollectable(lb, UNCOLLECTABLE);
12853}
12854#ifdef GC_ATOMIC_UNCOLLECTABLE
12855 GC_API GC_ATTR_MALLOC void * GC_CALL
12856 GC_malloc_atomic_uncollectable(size_t lb)
12857 {
12858 return GC_generic_malloc_uncollectable(lb, AUNCOLLECTABLE);
12859 }
12860#endif
12861#if defined(REDIRECT_MALLOC) && !defined(REDIRECT_MALLOC_IN_HEADER)
12862#ifndef MSWINCE
12863#include <errno.h>
12864#endif
12865#define GC_debug_malloc_replacement(lb) GC_debug_malloc(lb, GC_DBG_EXTRAS)
12866#if defined(CPPCHECK)
12867#define REDIRECT_MALLOC_F GC_malloc
12868#else
12869#define REDIRECT_MALLOC_F REDIRECT_MALLOC
12870#endif
12871 void * malloc(size_t lb)
12872 {
12873#if defined(I386) && defined(GC_SOLARIS_THREADS)
12874 if (!EXPECT(GC_is_initialized, TRUE)) return sbrk(lb);
12875#endif
12876 return (void *)REDIRECT_MALLOC_F(lb);
12877 }
12878#if defined(GC_LINUX_THREADS)
12879 STATIC ptr_t GC_libpthread_start = 0;
12880 STATIC ptr_t GC_libpthread_end = 0;
12881 STATIC ptr_t GC_libld_start = 0;
12882 STATIC ptr_t GC_libld_end = 0;
12883 STATIC void GC_init_lib_bounds(void)
12884 {
12885 IF_CANCEL(int cancel_state;)
12886 if (GC_libpthread_start != 0) return;
12887 DISABLE_CANCEL(cancel_state);
12888 GC_init();
12889 if (!GC_text_mapping("libpthread-",
12890 &GC_libpthread_start, &GC_libpthread_end)) {
12891 WARN("Failed to find libpthread.so text mapping: Expect crash\n", 0);
12892 GC_libpthread_start = (ptr_t)1;
12893 }
12894 if (!GC_text_mapping("ld-", &GC_libld_start, &GC_libld_end)) {
12895 WARN("Failed to find ld.so text mapping: Expect crash\n", 0);
12896 }
12897 RESTORE_CANCEL(cancel_state);
12898 }
12899#endif
12900 void * calloc(size_t n, size_t lb)
12901 {
12902 if ((lb | n) > GC_SQRT_SIZE_MAX
12903 && lb && n > GC_SIZE_MAX / lb)
12904 return (*GC_get_oom_fn())(GC_SIZE_MAX);
12905#if defined(GC_LINUX_THREADS)
12906 {
12907 static GC_bool lib_bounds_set = FALSE;
12908 ptr_t caller = (ptr_t)__builtin_return_address(0);
12909 if (!EXPECT(lib_bounds_set, TRUE)) {
12910 GC_init_lib_bounds();
12911 lib_bounds_set = TRUE;
12912 }
12913 if (((word)caller >= (word)GC_libpthread_start
12914 && (word)caller < (word)GC_libpthread_end)
12915 || ((word)caller >= (word)GC_libld_start
12916 && (word)caller < (word)GC_libld_end))
12917 return GC_generic_malloc_uncollectable(n * lb, UNCOLLECTABLE);
12918 }
12919#endif
12920 return (void *)REDIRECT_MALLOC_F(n * lb);
12921 }
12922#ifndef strdup
12923 char *strdup(const char *s)
12924 {
12925 size_t lb = strlen(s) + 1;
12926 char *result = (char *)REDIRECT_MALLOC_F(lb);
12927 if (result == 0) {
12928 errno = ENOMEM;
12929 return 0;
12930 }
12931 BCOPY(s, result, lb);
12932 return result;
12933 }
12934#endif
12935#ifndef strndup
12936 char *strndup(const char *str, size_t size)
12937 {
12938 char *copy;
12939 size_t len = strlen(str);
12940 if (len > size)
12941 len = size;
12942 copy = (char *)REDIRECT_MALLOC_F(len + 1);
12943 if (copy == NULL) {
12944 errno = ENOMEM;
12945 return NULL;
12946 }
12947 if (EXPECT(len > 0, TRUE))
12948 BCOPY(str, copy, len);
12949 copy[len] = '\0';
12950 return copy;
12951 }
12952#endif
12953#undef GC_debug_malloc_replacement
12954#endif
12955GC_API void GC_CALL GC_free(void * p)
12956{
12957 struct hblk *h;
12958 hdr *hhdr;
12959 size_t sz;
12960 size_t ngranules;
12961 int knd;
12962 struct obj_kind * ok;
12963 DCL_LOCK_STATE;
12964 if (p ) {
12965 } else {
12966 return;
12967 }
12968#ifdef LOG_ALLOCS
12969 GC_log_printf("GC_free(%p) after GC #%lu\n",
12970 p, (unsigned long)GC_gc_no);
12971#endif
12972 h = HBLKPTR(p);
12973 hhdr = HDR(h);
12974#if defined(REDIRECT_MALLOC) && \
12975 ((defined(NEED_CALLINFO) && defined(GC_HAVE_BUILTIN_BACKTRACE)) \
12976 || defined(GC_SOLARIS_THREADS) || defined(GC_LINUX_THREADS) \
12977 || defined(MSWIN32))
12978 if (0 == hhdr) return;
12979#endif
12980 GC_ASSERT(GC_base(p) == p);
12981 sz = (size_t)hhdr->hb_sz;
12982 ngranules = BYTES_TO_GRANULES(sz);
12983 knd = hhdr -> hb_obj_kind;
12984 ok = &GC_obj_kinds[knd];
12985 if (EXPECT(ngranules <= MAXOBJGRANULES, TRUE)) {
12986 void **flh;
12987 LOCK();
12988 GC_bytes_freed += sz;
12989 if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= sz;
12990 if (ok -> ok_init && EXPECT(sz > sizeof(word), TRUE)) {
12991 BZERO((word *)p + 1, sz-sizeof(word));
12992 }
12993 flh = &(ok -> ok_freelist[ngranules]);
12994 obj_link(p) = *flh;
12995 *flh = (ptr_t)p;
12996 UNLOCK();
12997 } else {
12998 size_t nblocks = OBJ_SZ_TO_BLOCKS(sz);
12999 LOCK();
13000 GC_bytes_freed += sz;
13001 if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= sz;
13002 if (nblocks > 1) {
13003 GC_large_allocd_bytes -= nblocks * HBLKSIZE;
13004 }
13005 GC_freehblk(h);
13006 UNLOCK();
13007 }
13008}
13009#ifdef THREADS
13010 GC_INNER void GC_free_inner(void * p)
13011 {
13012 struct hblk *h;
13013 hdr *hhdr;
13014 size_t sz;
13015 size_t ngranules;
13016 int knd;
13017 struct obj_kind * ok;
13018 h = HBLKPTR(p);
13019 hhdr = HDR(h);
13020 knd = hhdr -> hb_obj_kind;
13021 sz = (size_t)hhdr->hb_sz;
13022 ngranules = BYTES_TO_GRANULES(sz);
13023 ok = &GC_obj_kinds[knd];
13024 if (ngranules <= MAXOBJGRANULES) {
13025 void ** flh;
13026 GC_bytes_freed += sz;
13027 if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= sz;
13028 if (ok -> ok_init && EXPECT(sz > sizeof(word), TRUE)) {
13029 BZERO((word *)p + 1, sz-sizeof(word));
13030 }
13031 flh = &(ok -> ok_freelist[ngranules]);
13032 obj_link(p) = *flh;
13033 *flh = (ptr_t)p;
13034 } else {
13035 size_t nblocks = OBJ_SZ_TO_BLOCKS(sz);
13036 GC_bytes_freed += sz;
13037 if (IS_UNCOLLECTABLE(knd)) GC_non_gc_bytes -= sz;
13038 if (nblocks > 1) {
13039 GC_large_allocd_bytes -= nblocks * HBLKSIZE;
13040 }
13041 GC_freehblk(h);
13042 }
13043 }
13044#endif
13045#if defined(REDIRECT_MALLOC) && !defined(REDIRECT_FREE)
13046#define REDIRECT_FREE GC_free
13047#endif
13048#if defined(REDIRECT_FREE) && !defined(REDIRECT_MALLOC_IN_HEADER)
13049#if defined(CPPCHECK)
13050#define REDIRECT_FREE_F GC_free
13051#else
13052#define REDIRECT_FREE_F REDIRECT_FREE
13053#endif
13054 void free(void * p)
13055 {
13056#ifndef IGNORE_FREE
13057#if defined(GC_LINUX_THREADS) && !defined(USE_PROC_FOR_LIBRARIES)
13058 ptr_t caller = (ptr_t)__builtin_return_address(0);
13059 if (((word)caller >= (word)GC_libpthread_start
13060 && (word)caller < (word)GC_libpthread_end)
13061 || ((word)caller >= (word)GC_libld_start
13062 && (word)caller < (word)GC_libld_end)) {
13063 GC_free(p);
13064 return;
13065 }
13066#endif
13067 REDIRECT_FREE_F(p);
13068#endif
13069 }
13070#endif
13071#include <stdio.h>
13072#include <string.h>
13073#ifndef MSWINCE
13074#include <errno.h>
13075#endif
13076#ifndef GC_ALLOC_PTRS_H
13077#define GC_ALLOC_PTRS_H
13078#ifdef __cplusplus
13079 extern "C" {
13080#endif
13081#ifndef GC_API_PRIV
13082#define GC_API_PRIV GC_API
13083#endif
13084#ifndef GC_APIVAR_CONST
13085#if defined(GC_BUILD) || !defined(GC_DLL)
13086#define GC_APIVAR_CONST const
13087#else
13088#define GC_APIVAR_CONST
13089#endif
13090#endif
13091GC_API_PRIV void ** GC_APIVAR_CONST GC_objfreelist_ptr;
13092GC_API_PRIV void ** GC_APIVAR_CONST GC_aobjfreelist_ptr;
13093GC_API_PRIV void ** GC_APIVAR_CONST GC_uobjfreelist_ptr;
13094#ifdef GC_ATOMIC_UNCOLLECTABLE
13095 GC_API_PRIV void ** GC_APIVAR_CONST GC_auobjfreelist_ptr;
13096#endif
13097GC_API_PRIV void GC_CALL GC_incr_bytes_allocd(size_t );
13098GC_API_PRIV void GC_CALL GC_incr_bytes_freed(size_t );
13099#ifdef __cplusplus
13100 }
13101#endif
13102#endif
13103void ** const GC_objfreelist_ptr = GC_objfreelist;
13104void ** const GC_aobjfreelist_ptr = GC_aobjfreelist;
13105void ** const GC_uobjfreelist_ptr = GC_uobjfreelist;
13106#ifdef GC_ATOMIC_UNCOLLECTABLE
13107 void ** const GC_auobjfreelist_ptr = GC_auobjfreelist;
13108#endif
13109GC_API int GC_CALL GC_get_kind_and_size(const void * p, size_t * psize)
13110{
13111 hdr * hhdr = HDR(p);
13112 if (psize != NULL) {
13113 *psize = (size_t)hhdr->hb_sz;
13114 }
13115 return hhdr -> hb_obj_kind;
13116}
13117GC_API GC_ATTR_MALLOC void * GC_CALL GC_generic_or_special_malloc(size_t lb,
13118 int knd)
13119{
13120 switch(knd) {
13121 case PTRFREE:
13122 case NORMAL:
13123 return GC_malloc_kind(lb, knd);
13124 case UNCOLLECTABLE:
13125#ifdef GC_ATOMIC_UNCOLLECTABLE
13126 case AUNCOLLECTABLE:
13127#endif
13128 return GC_generic_malloc_uncollectable(lb, knd);
13129 default:
13130 return GC_generic_malloc(lb, knd);
13131 }
13132}
13133GC_API void * GC_CALL GC_realloc(void * p, size_t lb)
13134{
13135 struct hblk * h;
13136 hdr * hhdr;
13137 void * result;
13138 size_t sz;
13139 size_t orig_sz;
13140 int obj_kind;
13141 if (p == 0) return(GC_malloc(lb));
13142 if (0 == lb) {
13143#ifndef IGNORE_FREE
13144 GC_free(p);
13145#endif
13146 return NULL;
13147 }
13148 h = HBLKPTR(p);
13149 hhdr = HDR(h);
13150 sz = (size_t)hhdr->hb_sz;
13151 obj_kind = hhdr -> hb_obj_kind;
13152 orig_sz = sz;
13153 if (sz > MAXOBJBYTES) {
13154 word descr = GC_obj_kinds[obj_kind].ok_descriptor;
13155 sz = (sz + HBLKSIZE-1) & ~HBLKMASK;
13156 if (GC_obj_kinds[obj_kind].ok_relocate_descr)
13157 descr += sz;
13158#ifdef AO_HAVE_store
13159 GC_STATIC_ASSERT(sizeof(hhdr->hb_sz) == sizeof(AO_t));
13160 AO_store((volatile AO_t *)&hhdr->hb_sz, (AO_t)sz);
13161 AO_store((volatile AO_t *)&hhdr->hb_descr, (AO_t)descr);
13162#else
13163 {
13164 DCL_LOCK_STATE;
13165 LOCK();
13166 hhdr -> hb_sz = sz;
13167 hhdr -> hb_descr = descr;
13168 UNLOCK();
13169 }
13170#endif
13171#ifdef MARK_BIT_PER_OBJ
13172 GC_ASSERT(hhdr -> hb_inv_sz == LARGE_INV_SZ);
13173#endif
13174#ifdef MARK_BIT_PER_GRANULE
13175 GC_ASSERT((hhdr -> hb_flags & LARGE_BLOCK) != 0
13176 && hhdr -> hb_map[ANY_INDEX] == 1);
13177#endif
13178 if (IS_UNCOLLECTABLE(obj_kind)) GC_non_gc_bytes += (sz - orig_sz);
13179 }
13180 if (ADD_SLOP(lb) <= sz) {
13181 if (lb >= (sz >> 1)) {
13182 if (orig_sz > lb) {
13183 BZERO(((ptr_t)p) + lb, orig_sz - lb);
13184 }
13185 return(p);
13186 }
13187 sz = lb;
13188 }
13189 result = GC_generic_or_special_malloc((word)lb, obj_kind);
13190 if (result != NULL) {
13191 BCOPY(p, result, sz);
13192#ifndef IGNORE_FREE
13193 GC_free(p);
13194#endif
13195 }
13196 return result;
13197}
13198#if defined(REDIRECT_MALLOC) && !defined(REDIRECT_REALLOC)
13199#define REDIRECT_REALLOC GC_realloc
13200#endif
13201#ifdef REDIRECT_REALLOC
13202#define GC_debug_realloc_replacement(p, lb) \
13203 GC_debug_realloc(p, lb, GC_DBG_EXTRAS)
13204#if !defined(REDIRECT_MALLOC_IN_HEADER)
13205 void * realloc(void * p, size_t lb)
13206 {
13207 return(REDIRECT_REALLOC(p, lb));
13208 }
13209#endif
13210#undef GC_debug_realloc_replacement
13211#endif
13212GC_API GC_ATTR_MALLOC void * GC_CALL
13213 GC_generic_malloc_ignore_off_page(size_t lb, int k)
13214{
13215 void *result;
13216 size_t lg;
13217 size_t lb_rounded;
13218 word n_blocks;
13219 GC_bool init;
13220 DCL_LOCK_STATE;
13221 if (SMALL_OBJ(lb))
13222 return GC_generic_malloc(lb, k);
13223 GC_ASSERT(k < MAXOBJKINDS);
13224 lg = ROUNDED_UP_GRANULES(lb);
13225 lb_rounded = GRANULES_TO_BYTES(lg);
13226 n_blocks = OBJ_SZ_TO_BLOCKS(lb_rounded);
13227 init = GC_obj_kinds[k].ok_init;
13228 if (EXPECT(GC_have_errors, FALSE))
13229 GC_print_all_errors();
13230 GC_INVOKE_FINALIZERS();
13231 GC_DBG_COLLECT_AT_MALLOC(lb);
13232 LOCK();
13233 result = (ptr_t)GC_alloc_large(ADD_SLOP(lb), k, IGNORE_OFF_PAGE);
13234 if (NULL == result) {
13235 GC_oom_func oom_fn = GC_oom_fn;
13236 UNLOCK();
13237 return (*oom_fn)(lb);
13238 }
13239 if (GC_debugging_started) {
13240 BZERO(result, n_blocks * HBLKSIZE);
13241 } else {
13242#ifdef THREADS
13243 ((word *)result)[0] = 0;
13244 ((word *)result)[1] = 0;
13245 ((word *)result)[GRANULES_TO_WORDS(lg)-1] = 0;
13246 ((word *)result)[GRANULES_TO_WORDS(lg)-2] = 0;
13247#endif
13248 }
13249 GC_bytes_allocd += lb_rounded;
13250 UNLOCK();
13251 if (init && !GC_debugging_started) {
13252 BZERO(result, n_blocks * HBLKSIZE);
13253 }
13254 return(result);
13255}
13256GC_API GC_ATTR_MALLOC void * GC_CALL GC_malloc_ignore_off_page(size_t lb)
13257{
13258 return GC_generic_malloc_ignore_off_page(lb, NORMAL);
13259}
13260GC_API GC_ATTR_MALLOC void * GC_CALL
13261 GC_malloc_atomic_ignore_off_page(size_t lb)
13262{
13263 return GC_generic_malloc_ignore_off_page(lb, PTRFREE);
13264}
13265void GC_CALL GC_incr_bytes_allocd(size_t n)
13266{
13267 GC_bytes_allocd += n;
13268}
13269void GC_CALL GC_incr_bytes_freed(size_t n)
13270{
13271 GC_bytes_freed += n;
13272}
13273GC_API size_t GC_CALL GC_get_expl_freed_bytes_since_gc(void)
13274{
13275 return (size_t)GC_bytes_freed;
13276}
13277#ifdef PARALLEL_MARK
13278 STATIC volatile AO_t GC_bytes_allocd_tmp = 0;
13279#endif
13280GC_API void GC_CALL GC_generic_malloc_many(size_t lb, int k, void **result)
13281{
13282 void *op;
13283 void *p;
13284 void **opp;
13285 size_t lw;
13286 size_t lg;
13287 signed_word my_bytes_allocd = 0;
13288 struct obj_kind * ok = &(GC_obj_kinds[k]);
13289 struct hblk ** rlh;
13290 DCL_LOCK_STATE;
13291 GC_ASSERT(lb != 0 && (lb & (GRANULE_BYTES-1)) == 0);
13292 if (!SMALL_OBJ(lb) || GC_manual_vdb) {
13293 op = GC_generic_malloc(lb, k);
13294 if (EXPECT(0 != op, TRUE))
13295 obj_link(op) = 0;
13296 *result = op;
13297#ifndef GC_DISABLE_INCREMENTAL
13298 if (GC_manual_vdb && GC_is_heap_ptr(result)) {
13299 GC_dirty_inner(result);
13300 REACHABLE_AFTER_DIRTY(op);
13301 }
13302#endif
13303 return;
13304 }
13305 GC_ASSERT(k < MAXOBJKINDS);
13306 lw = BYTES_TO_WORDS(lb);
13307 lg = BYTES_TO_GRANULES(lb);
13308 if (EXPECT(GC_have_errors, FALSE))
13309 GC_print_all_errors();
13310 GC_INVOKE_FINALIZERS();
13311 GC_DBG_COLLECT_AT_MALLOC(lb);
13312 if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
13313 LOCK();
13314 if (GC_incremental && !GC_dont_gc) {
13315 ENTER_GC();
13316 GC_collect_a_little_inner(1);
13317 EXIT_GC();
13318 }
13319 rlh = ok -> ok_reclaim_list;
13320 if (rlh != NULL) {
13321 struct hblk * hbp;
13322 hdr * hhdr;
13323 while ((hbp = rlh[lg]) != NULL) {
13324 hhdr = HDR(hbp);
13325 rlh[lg] = hhdr -> hb_next;
13326 GC_ASSERT(hhdr -> hb_sz == lb);
13327 hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no;
13328#ifdef PARALLEL_MARK
13329 if (GC_parallel) {
13330 signed_word my_bytes_allocd_tmp =
13331 (signed_word)AO_load(&GC_bytes_allocd_tmp);
13332 GC_ASSERT(my_bytes_allocd_tmp >= 0);
13333 if (my_bytes_allocd_tmp != 0) {
13334 (void)AO_fetch_and_add(&GC_bytes_allocd_tmp,
13335 (AO_t)(-my_bytes_allocd_tmp));
13336 GC_bytes_allocd += my_bytes_allocd_tmp;
13337 }
13338 GC_acquire_mark_lock();
13339 ++ GC_fl_builder_count;
13340 UNLOCK();
13341 GC_release_mark_lock();
13342 }
13343#endif
13344 op = GC_reclaim_generic(hbp, hhdr, lb,
13345 ok -> ok_init, 0, &my_bytes_allocd);
13346 if (op != 0) {
13347#ifdef PARALLEL_MARK
13348 if (GC_parallel) {
13349 *result = op;
13350 (void)AO_fetch_and_add(&GC_bytes_allocd_tmp,
13351 (AO_t)my_bytes_allocd);
13352 GC_acquire_mark_lock();
13353 -- GC_fl_builder_count;
13354 if (GC_fl_builder_count == 0) GC_notify_all_builder();
13355#ifdef THREAD_SANITIZER
13356 GC_release_mark_lock();
13357 LOCK();
13358 GC_bytes_found += my_bytes_allocd;
13359 UNLOCK();
13360#else
13361 GC_bytes_found += my_bytes_allocd;
13362 GC_release_mark_lock();
13363#endif
13364 (void) GC_clear_stack(0);
13365 return;
13366 }
13367#endif
13368 GC_bytes_found += my_bytes_allocd;
13369 GC_bytes_allocd += my_bytes_allocd;
13370 goto out;
13371 }
13372#ifdef PARALLEL_MARK
13373 if (GC_parallel) {
13374 GC_acquire_mark_lock();
13375 -- GC_fl_builder_count;
13376 if (GC_fl_builder_count == 0) GC_notify_all_builder();
13377 GC_release_mark_lock();
13378 LOCK();
13379 rlh = ok -> ok_reclaim_list;
13380 if (NULL == rlh) break;
13381 }
13382#endif
13383 }
13384 }
13385 opp = &(GC_obj_kinds[k].ok_freelist[lg]);
13386 if ( (op = *opp) != 0 ) {
13387 *opp = 0;
13388 my_bytes_allocd = 0;
13389 for (p = op; p != 0; p = obj_link(p)) {
13390 my_bytes_allocd += lb;
13391 if ((word)my_bytes_allocd >= HBLKSIZE) {
13392 *opp = obj_link(p);
13393 obj_link(p) = 0;
13394 break;
13395 }
13396 }
13397 GC_bytes_allocd += my_bytes_allocd;
13398 goto out;
13399 }
13400 {
13401 struct hblk *h = GC_allochblk(lb, k, 0);
13402 if (h ) {
13403 if (IS_UNCOLLECTABLE(k)) GC_set_hdr_marks(HDR(h));
13404 GC_bytes_allocd += HBLKSIZE - HBLKSIZE % lb;
13405#ifdef PARALLEL_MARK
13406 if (GC_parallel) {
13407 GC_acquire_mark_lock();
13408 ++ GC_fl_builder_count;
13409 UNLOCK();
13410 GC_release_mark_lock();
13411 op = GC_build_fl(h, lw,
13412 (ok -> ok_init || GC_debugging_started), 0);
13413 *result = op;
13414 GC_acquire_mark_lock();
13415 -- GC_fl_builder_count;
13416 if (GC_fl_builder_count == 0) GC_notify_all_builder();
13417 GC_release_mark_lock();
13418 (void) GC_clear_stack(0);
13419 return;
13420 }
13421#endif
13422 op = GC_build_fl(h, lw, (ok -> ok_init || GC_debugging_started), 0);
13423 goto out;
13424 }
13425 }
13426 op = GC_generic_malloc_inner(lb, k);
13427 if (0 != op) obj_link(op) = 0;
13428 out:
13429 *result = op;
13430 UNLOCK();
13431 (void) GC_clear_stack(0);
13432}
13433GC_API GC_ATTR_MALLOC void * GC_CALL GC_malloc_many(size_t lb)
13434{
13435 void *result;
13436 lb = SIZET_SAT_ADD(lb, EXTRA_BYTES + GRANULE_BYTES - 1)
13437 & ~(GRANULE_BYTES - 1);
13438 GC_generic_malloc_many(lb, NORMAL, &result);
13439 return result;
13440}
13441#include <limits.h>
13442GC_API GC_ATTR_MALLOC void * GC_CALL GC_memalign(size_t align, size_t lb)
13443{
13444 size_t new_lb;
13445 size_t offset;
13446 ptr_t result;
13447 if (align <= GRANULE_BYTES) return GC_malloc(lb);
13448 if (align >= HBLKSIZE/2 || lb >= HBLKSIZE/2) {
13449 if (align > HBLKSIZE) {
13450 return (*GC_get_oom_fn())(LONG_MAX-1024);
13451 }
13452 return GC_malloc(lb <= HBLKSIZE? HBLKSIZE : lb);
13453 }
13454 new_lb = SIZET_SAT_ADD(lb, align - 1);
13455 result = (ptr_t)GC_malloc(new_lb);
13456 offset = (word)result % align;
13457 if (offset != 0) {
13458 offset = align - offset;
13459 if (!GC_all_interior_pointers) {
13460 GC_STATIC_ASSERT(VALID_OFFSET_SZ <= HBLKSIZE);
13461 GC_ASSERT(offset < VALID_OFFSET_SZ);
13462 GC_register_displacement(offset);
13463 }
13464 }
13465 result += offset;
13466 GC_ASSERT((word)result % align == 0);
13467 return result;
13468}
13469GC_API int GC_CALL GC_posix_memalign(void **memptr, size_t align, size_t lb)
13470{
13471 size_t align_minus_one = align - 1;
13472 if (align < sizeof(void *) || (align_minus_one & align) != 0) {
13473#ifdef MSWINCE
13474 return ERROR_INVALID_PARAMETER;
13475#else
13476 return EINVAL;
13477#endif
13478 }
13479 if ((*memptr = GC_memalign(align, lb)) == NULL) {
13480#ifdef MSWINCE
13481 return ERROR_NOT_ENOUGH_MEMORY;
13482#else
13483 return ENOMEM;
13484#endif
13485 }
13486 return 0;
13487}
13488GC_API GC_ATTR_MALLOC char * GC_CALL GC_strdup(const char *s)
13489{
13490 char *copy;
13491 size_t lb;
13492 if (s == NULL) return NULL;
13493 lb = strlen(s) + 1;
13494 copy = (char *)GC_malloc_atomic(lb);
13495 if (NULL == copy) {
13496#ifndef MSWINCE
13497 errno = ENOMEM;
13498#endif
13499 return NULL;
13500 }
13501 BCOPY(s, copy, lb);
13502 return copy;
13503}
13504GC_API GC_ATTR_MALLOC char * GC_CALL GC_strndup(const char *str, size_t size)
13505{
13506 char *copy;
13507 size_t len = strlen(str);
13508 if (len > size)
13509 len = size;
13510 copy = (char *)GC_malloc_atomic(len + 1);
13511 if (copy == NULL) {
13512#ifndef MSWINCE
13513 errno = ENOMEM;
13514#endif
13515 return NULL;
13516 }
13517 if (EXPECT(len > 0, TRUE))
13518 BCOPY(str, copy, len);
13519 copy[len] = '\0';
13520 return copy;
13521}
13522#ifdef GC_REQUIRE_WCSDUP
13523#include <wchar.h>
13524 GC_API GC_ATTR_MALLOC wchar_t * GC_CALL GC_wcsdup(const wchar_t *str)
13525 {
13526 size_t lb = (wcslen(str) + 1) * sizeof(wchar_t);
13527 wchar_t *copy = (wchar_t *)GC_malloc_atomic(lb);
13528 if (copy == NULL) {
13529#ifndef MSWINCE
13530 errno = ENOMEM;
13531#endif
13532 return NULL;
13533 }
13534 BCOPY(str, copy, lb);
13535 return copy;
13536 }
13537#endif
13538#ifndef CPPCHECK
13539 GC_API void * GC_CALL GC_malloc_stubborn(size_t lb)
13540 {
13541 return GC_malloc(lb);
13542 }
13543 GC_API void GC_CALL GC_change_stubborn(const void *p GC_ATTR_UNUSED)
13544 {
13545 }
13546#endif
13547GC_API void GC_CALL GC_end_stubborn_change(const void *p)
13548{
13549 GC_dirty(p);
13550}
13551GC_API void GC_CALL GC_ptr_store_and_dirty(void *p, const void *q)
13552{
13553 *(const void **)p = q;
13554 GC_dirty(p);
13555 REACHABLE_AFTER_DIRTY(q);
13556}
13557#if defined(__MINGW32__) && !defined(__MINGW_EXCPT_DEFINE_PSDK) \
13558 && defined(__i386__)
13559#define __MINGW_EXCPT_DEFINE_PSDK 1
13560#endif
13561#include <stdio.h>
13562#if defined(MSWIN32) && defined(__GNUC__)
13563#include <excpt.h>
13564#endif
13565GC_ATTR_NOINLINE
13566void GC_noop6(word arg1 GC_ATTR_UNUSED, word arg2 GC_ATTR_UNUSED,
13567 word arg3 GC_ATTR_UNUSED, word arg4 GC_ATTR_UNUSED,
13568 word arg5 GC_ATTR_UNUSED, word arg6 GC_ATTR_UNUSED)
13569{
13570#if defined(AO_HAVE_compiler_barrier) && !defined(BASE_ATOMIC_OPS_EMULATED)
13571 AO_compiler_barrier();
13572#else
13573 GC_noop1(0);
13574#endif
13575}
13576volatile word GC_noop_sink;
13577GC_ATTR_NO_SANITIZE_THREAD
13578GC_API void GC_CALL GC_noop1(word x)
13579{
13580 GC_noop_sink = x;
13581}
13582GC_INNER struct obj_kind GC_obj_kinds[MAXOBJKINDS] = {
13583 { &GC_aobjfreelist[0], 0 ,
13584 GC_DS_LENGTH, FALSE, FALSE
13585 OK_DISCLAIM_INITZ },
13586 { &GC_objfreelist[0], 0,
13587 GC_DS_LENGTH,
13588 TRUE , TRUE
13589 OK_DISCLAIM_INITZ },
13590 { &GC_uobjfreelist[0], 0,
13591 GC_DS_LENGTH, TRUE , TRUE
13592 OK_DISCLAIM_INITZ },
13593#ifdef GC_ATOMIC_UNCOLLECTABLE
13594 { &GC_auobjfreelist[0], 0,
13595 GC_DS_LENGTH, FALSE , FALSE
13596 OK_DISCLAIM_INITZ },
13597#endif
13598};
13599#ifndef INITIAL_MARK_STACK_SIZE
13600#define INITIAL_MARK_STACK_SIZE (1*HBLKSIZE)
13601#endif
13602#if !defined(GC_DISABLE_INCREMENTAL)
13603 STATIC word GC_n_rescuing_pages = 0;
13604#endif
13605#ifdef PARALLEL_MARK
13606 GC_INNER GC_bool GC_parallel_mark_disabled = FALSE;
13607#endif
13608GC_INNER GC_bool GC_collection_in_progress(void)
13609{
13610 return(GC_mark_state != MS_NONE);
13611}
13612GC_INNER void GC_clear_hdr_marks(hdr *hhdr)
13613{
13614 size_t last_bit;
13615#ifdef AO_HAVE_load
13616 last_bit = FINAL_MARK_BIT((size_t)AO_load((volatile AO_t *)&hhdr->hb_sz));
13617#else
13618 last_bit = FINAL_MARK_BIT((size_t)hhdr->hb_sz);
13619#endif
13620 BZERO(hhdr -> hb_marks, sizeof(hhdr->hb_marks));
13621 set_mark_bit_from_hdr(hhdr, last_bit);
13622 hhdr -> hb_n_marks = 0;
13623}
13624GC_INNER void GC_set_hdr_marks(hdr *hhdr)
13625{
13626 unsigned i;
13627 size_t sz = (size_t)hhdr->hb_sz;
13628 unsigned n_marks = (unsigned)FINAL_MARK_BIT(sz);
13629#ifdef USE_MARK_BYTES
13630 for (i = 0; i <= n_marks; i += (unsigned)MARK_BIT_OFFSET(sz)) {
13631 hhdr -> hb_marks[i] = 1;
13632 }
13633#else
13634 for (i = 0; i < divWORDSZ(n_marks + WORDSZ); ++i) {
13635 hhdr -> hb_marks[i] = GC_WORD_MAX;
13636 }
13637#endif
13638#ifdef MARK_BIT_PER_OBJ
13639 hhdr -> hb_n_marks = n_marks;
13640#else
13641 hhdr -> hb_n_marks = HBLK_OBJS(sz);
13642#endif
13643}
13644static void clear_marks_for_block(struct hblk *h, word dummy GC_ATTR_UNUSED)
13645{
13646 hdr * hhdr = HDR(h);
13647 if (IS_UNCOLLECTABLE(hhdr -> hb_obj_kind)) return;
13648 GC_clear_hdr_marks(hhdr);
13649}
13650GC_API void GC_CALL GC_set_mark_bit(const void *p)
13651{
13652 struct hblk *h = HBLKPTR(p);
13653 hdr * hhdr = HDR(h);
13654 word bit_no = MARK_BIT_NO((ptr_t)p - (ptr_t)h, hhdr -> hb_sz);
13655 if (!mark_bit_from_hdr(hhdr, bit_no)) {
13656 set_mark_bit_from_hdr(hhdr, bit_no);
13657 ++hhdr -> hb_n_marks;
13658 }
13659}
13660GC_API void GC_CALL GC_clear_mark_bit(const void *p)
13661{
13662 struct hblk *h = HBLKPTR(p);
13663 hdr * hhdr = HDR(h);
13664 word bit_no = MARK_BIT_NO((ptr_t)p - (ptr_t)h, hhdr -> hb_sz);
13665 if (mark_bit_from_hdr(hhdr, bit_no)) {
13666 size_t n_marks = hhdr -> hb_n_marks;
13667 GC_ASSERT(n_marks != 0);
13668 clear_mark_bit_from_hdr(hhdr, bit_no);
13669 n_marks--;
13670#ifdef PARALLEL_MARK
13671 if (n_marks != 0 || !GC_parallel)
13672 hhdr -> hb_n_marks = n_marks;
13673#else
13674 hhdr -> hb_n_marks = n_marks;
13675#endif
13676 }
13677}
13678GC_API int GC_CALL GC_is_marked(const void *p)
13679{
13680 struct hblk *h = HBLKPTR(p);
13681 hdr * hhdr = HDR(h);
13682 word bit_no = MARK_BIT_NO((ptr_t)p - (ptr_t)h, hhdr -> hb_sz);
13683 return (int)mark_bit_from_hdr(hhdr, bit_no);
13684}
13685GC_INNER void GC_clear_marks(void)
13686{
13687 GC_apply_to_all_blocks(clear_marks_for_block, (word)0);
13688 GC_objects_are_marked = FALSE;
13689 GC_mark_state = MS_INVALID;
13690 GC_scan_ptr = NULL;
13691}
13692GC_INNER void GC_initiate_gc(void)
13693{
13694 GC_ASSERT(I_HOLD_LOCK());
13695#ifndef GC_DISABLE_INCREMENTAL
13696 if (GC_incremental) {
13697#ifdef CHECKSUMS
13698 GC_read_dirty(FALSE);
13699 GC_check_dirty();
13700#else
13701 GC_read_dirty(GC_mark_state == MS_INVALID);
13702#endif
13703 }
13704 GC_n_rescuing_pages = 0;
13705#endif
13706 if (GC_mark_state == MS_NONE) {
13707 GC_mark_state = MS_PUSH_RESCUERS;
13708 } else if (GC_mark_state != MS_INVALID) {
13709 ABORT("Unexpected state");
13710 }
13711 GC_scan_ptr = NULL;
13712}
13713#ifdef PARALLEL_MARK
13714 STATIC void GC_do_parallel_mark(void);
13715#endif
13716#ifdef GC_DISABLE_INCREMENTAL
13717#define GC_push_next_marked_dirty(h) GC_push_next_marked(h)
13718#else
13719 STATIC struct hblk * GC_push_next_marked_dirty(struct hblk *h);
13720#endif
13721STATIC struct hblk * GC_push_next_marked(struct hblk *h);
13722STATIC struct hblk * GC_push_next_marked_uncollectable(struct hblk *h);
13723static void alloc_mark_stack(size_t);
13724#ifdef WRAP_MARK_SOME
13725 STATIC GC_bool GC_mark_some_inner(ptr_t cold_gc_frame)
13726#else
13727 GC_INNER GC_bool GC_mark_some(ptr_t cold_gc_frame)
13728#endif
13729{
13730 switch(GC_mark_state) {
13731 case MS_NONE:
13732 break;
13733 case MS_PUSH_RESCUERS:
13734 if ((word)GC_mark_stack_top
13735 >= (word)(GC_mark_stack_limit - INITIAL_MARK_STACK_SIZE/2)) {
13736 GC_mark_stack_too_small = TRUE;
13737 MARK_FROM_MARK_STACK();
13738 break;
13739 } else {
13740 GC_scan_ptr = GC_push_next_marked_dirty(GC_scan_ptr);
13741 if (NULL == GC_scan_ptr) {
13742#if !defined(GC_DISABLE_INCREMENTAL)
13743 GC_COND_LOG_PRINTF("Marked from %lu dirty pages\n",
13744 (unsigned long)GC_n_rescuing_pages);
13745#endif
13746 GC_push_roots(FALSE, cold_gc_frame);
13747 GC_objects_are_marked = TRUE;
13748 if (GC_mark_state != MS_INVALID) {
13749 GC_mark_state = MS_ROOTS_PUSHED;
13750 }
13751 }
13752 }
13753 break;
13754 case MS_PUSH_UNCOLLECTABLE:
13755 if ((word)GC_mark_stack_top
13756 >= (word)(GC_mark_stack + GC_mark_stack_size/4)) {
13757#ifdef PARALLEL_MARK
13758 if (GC_parallel) GC_mark_stack_too_small = TRUE;
13759#endif
13760 MARK_FROM_MARK_STACK();
13761 break;
13762 } else {
13763 GC_scan_ptr = GC_push_next_marked_uncollectable(GC_scan_ptr);
13764 if (NULL == GC_scan_ptr) {
13765 GC_push_roots(TRUE, cold_gc_frame);
13766 GC_objects_are_marked = TRUE;
13767 if (GC_mark_state != MS_INVALID) {
13768 GC_mark_state = MS_ROOTS_PUSHED;
13769 }
13770 }
13771 }
13772 break;
13773 case MS_ROOTS_PUSHED:
13774#ifdef PARALLEL_MARK
13775 if (GC_parallel && !GC_parallel_mark_disabled) {
13776 GC_do_parallel_mark();
13777 GC_ASSERT((word)GC_mark_stack_top < (word)GC_first_nonempty);
13778 GC_mark_stack_top = GC_mark_stack - 1;
13779 if (GC_mark_stack_too_small) {
13780 alloc_mark_stack(2*GC_mark_stack_size);
13781 }
13782 if (GC_mark_state == MS_ROOTS_PUSHED) {
13783 GC_mark_state = MS_NONE;
13784 return(TRUE);
13785 }
13786 break;
13787 }
13788#endif
13789 if ((word)GC_mark_stack_top >= (word)GC_mark_stack) {
13790 MARK_FROM_MARK_STACK();
13791 break;
13792 } else {
13793 GC_mark_state = MS_NONE;
13794 if (GC_mark_stack_too_small) {
13795 alloc_mark_stack(2*GC_mark_stack_size);
13796 }
13797 return(TRUE);
13798 }
13799 case MS_INVALID:
13800 case MS_PARTIALLY_INVALID:
13801 if (!GC_objects_are_marked) {
13802 GC_mark_state = MS_PUSH_UNCOLLECTABLE;
13803 break;
13804 }
13805 if ((word)GC_mark_stack_top >= (word)GC_mark_stack) {
13806 MARK_FROM_MARK_STACK();
13807 break;
13808 }
13809 if (NULL == GC_scan_ptr && GC_mark_state == MS_INVALID) {
13810 if (GC_mark_stack_too_small) {
13811 alloc_mark_stack(2*GC_mark_stack_size);
13812 }
13813 GC_mark_state = MS_PARTIALLY_INVALID;
13814 }
13815 GC_scan_ptr = GC_push_next_marked(GC_scan_ptr);
13816 if (NULL == GC_scan_ptr && GC_mark_state == MS_PARTIALLY_INVALID) {
13817 GC_push_roots(TRUE, cold_gc_frame);
13818 GC_objects_are_marked = TRUE;
13819 if (GC_mark_state != MS_INVALID) {
13820 GC_mark_state = MS_ROOTS_PUSHED;
13821 }
13822 }
13823 break;
13824 default:
13825 ABORT("GC_mark_some: bad state");
13826 }
13827 return(FALSE);
13828}
13829#ifdef WRAP_MARK_SOME
13830#if (defined(MSWIN32) || defined(MSWINCE)) && defined(__GNUC__)
13831 typedef struct {
13832 EXCEPTION_REGISTRATION ex_reg;
13833 void *alt_path;
13834 } ext_ex_regn;
13835 static EXCEPTION_DISPOSITION mark_ex_handler(
13836 struct _EXCEPTION_RECORD *ex_rec,
13837 void *est_frame,
13838 struct _CONTEXT *context,
13839 void *disp_ctxt GC_ATTR_UNUSED)
13840 {
13841 if (ex_rec->ExceptionCode == STATUS_ACCESS_VIOLATION) {
13842 ext_ex_regn *xer = (ext_ex_regn *)est_frame;
13843 context->Esp = context->Ebp;
13844 context->Ebp = *((DWORD *)context->Esp);
13845 context->Esp = context->Esp - 8;
13846 context->Eip = (DWORD )(xer->alt_path);
13847 return ExceptionContinueExecution;
13848 } else {
13849 return ExceptionContinueSearch;
13850 }
13851 }
13852#endif
13853 GC_INNER GC_bool GC_mark_some(ptr_t cold_gc_frame)
13854 {
13855 GC_bool ret_val;
13856#if defined(MSWIN32) || defined(MSWINCE)
13857#ifndef __GNUC__
13858 __try {
13859 ret_val = GC_mark_some_inner(cold_gc_frame);
13860 } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
13861 EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
13862 goto handle_ex;
13863 }
13864#if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
13865 if (GC_started_thread_while_stopped())
13866 goto handle_thr_start;
13867#endif
13868 rm_handler:
13869 return ret_val;
13870#else
13871 ext_ex_regn er;
13872#if GC_GNUC_PREREQ(4, 7) || GC_CLANG_PREREQ(3, 3)
13873#pragma GCC diagnostic push
13874#if defined(__clang__) || GC_GNUC_PREREQ(6, 4)
13875#pragma GCC diagnostic ignored "-Wpedantic"
13876#else
13877#pragma GCC diagnostic ignored "-pedantic"
13878#endif
13879 er.alt_path = &&handle_ex;
13880#pragma GCC diagnostic pop
13881#elif !defined(CPPCHECK)
13882 er.alt_path = &&handle_ex;
13883#endif
13884 er.ex_reg.handler = mark_ex_handler;
13885 __asm__ __volatile__ ("movl %%fs:0, %0" : "=r" (er.ex_reg.prev));
13886 __asm__ __volatile__ ("movl %0, %%fs:0" : : "r" (&er));
13887 ret_val = GC_mark_some_inner(cold_gc_frame);
13888 if (er.alt_path == 0)
13889 goto handle_ex;
13890#if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
13891 if (GC_started_thread_while_stopped())
13892 goto handle_thr_start;
13893#endif
13894 rm_handler:
13895 __asm__ __volatile__ ("mov %0, %%fs:0" : : "r" (er.ex_reg.prev));
13896 return ret_val;
13897#endif
13898#else
13899#ifndef DEFAULT_VDB
13900 if (GC_auto_incremental) {
13901 static GC_bool is_warned = FALSE;
13902 if (!is_warned) {
13903 is_warned = TRUE;
13904 WARN("Incremental GC incompatible with /proc roots\n", 0);
13905 }
13906 }
13907#endif
13908 GC_setup_temporary_fault_handler();
13909 if(SETJMP(GC_jmp_buf) != 0) goto handle_ex;
13910 ret_val = GC_mark_some_inner(cold_gc_frame);
13911 rm_handler:
13912 GC_reset_fault_handler();
13913 return ret_val;
13914#endif
13915handle_ex:
13916 {
13917 static word warned_gc_no;
13918 if (warned_gc_no != GC_gc_no) {
13919 WARN("Caught ACCESS_VIOLATION in marker;"
13920 " memory mapping disappeared\n", 0);
13921 warned_gc_no = GC_gc_no;
13922 }
13923 }
13924#if (defined(MSWIN32) || defined(MSWINCE)) && defined(GC_WIN32_THREADS) \
13925 && !defined(GC_PTHREADS)
13926 handle_thr_start:
13927#endif
13928#ifdef REGISTER_LIBRARIES_EARLY
13929 START_WORLD();
13930 GC_cond_register_dynamic_libraries();
13931 STOP_WORLD();
13932#endif
13933 GC_invalidate_mark_state();
13934 GC_scan_ptr = NULL;
13935 ret_val = FALSE;
13936 goto rm_handler;
13937 }
13938#endif
13939GC_INNER void GC_invalidate_mark_state(void)
13940{
13941 GC_mark_state = MS_INVALID;
13942 GC_mark_stack_top = GC_mark_stack-1;
13943}
13944GC_INNER mse * GC_signal_mark_stack_overflow(mse *msp)
13945{
13946 GC_mark_state = MS_INVALID;
13947#ifdef PARALLEL_MARK
13948 if (!GC_parallel)
13949 GC_mark_stack_too_small = TRUE;
13950#else
13951 GC_mark_stack_too_small = TRUE;
13952#endif
13953 GC_COND_LOG_PRINTF("Mark stack overflow; current size: %lu entries\n",
13954 (unsigned long)GC_mark_stack_size);
13955 return(msp - GC_MARK_STACK_DISCARDS);
13956}
13957GC_ATTR_NO_SANITIZE_ADDR GC_ATTR_NO_SANITIZE_MEMORY GC_ATTR_NO_SANITIZE_THREAD
13958GC_INNER mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack,
13959 mse *mark_stack_limit)
13960{
13961 signed_word credit = HBLKSIZE;
13962 ptr_t current_p;
13963 word current;
13964 ptr_t limit = 0;
13965 word descr;
13966 ptr_t greatest_ha = (ptr_t)GC_greatest_plausible_heap_addr;
13967 ptr_t least_ha = (ptr_t)GC_least_plausible_heap_addr;
13968 DECLARE_HDR_CACHE;
13969#define SPLIT_RANGE_WORDS 128
13970 GC_objects_are_marked = TRUE;
13971 INIT_HDR_CACHE;
13972#ifdef OS2
13973 while ((word)mark_stack_top >= (word)mark_stack && credit >= 0)
13974#else
13975 while (((((word)mark_stack_top - (word)mark_stack) | (word)credit)
13976 & SIGNB) == 0)
13977#endif
13978 {
13979 current_p = mark_stack_top -> mse_start;
13980 descr = mark_stack_top -> mse_descr.w;
13981 retry:
13982 if (descr & ((~(WORDS_TO_BYTES(SPLIT_RANGE_WORDS) - 1)) | GC_DS_TAGS)) {
13983 word tag = descr & GC_DS_TAGS;
13984 GC_STATIC_ASSERT(GC_DS_TAGS == 0x3);
13985 switch(tag) {
13986 case GC_DS_LENGTH:
13987 GC_ASSERT(descr < (word)GC_greatest_plausible_heap_addr
13988 - (word)GC_least_plausible_heap_addr
13989 || (word)(current_p + descr)
13990 <= (word)GC_least_plausible_heap_addr
13991 || (word)current_p >= (word)GC_greatest_plausible_heap_addr);
13992#ifdef PARALLEL_MARK
13993#define SHARE_BYTES 2048
13994 if (descr > SHARE_BYTES && GC_parallel
13995 && (word)mark_stack_top < (word)(mark_stack_limit - 1)) {
13996 word new_size = (descr/2) & ~(word)(sizeof(word)-1);
13997 mark_stack_top -> mse_start = current_p;
13998 mark_stack_top -> mse_descr.w = new_size + sizeof(word);
13999 mark_stack_top++;
14000#ifdef ENABLE_TRACE
14001 if ((word)GC_trace_addr >= (word)current_p
14002 && (word)GC_trace_addr < (word)(current_p + descr)) {
14003 GC_log_printf("GC #%lu: large section; start %p, len %lu,"
14004 " splitting (parallel) at %p\n",
14005 (unsigned long)GC_gc_no, (void *)current_p,
14006 (unsigned long)descr,
14007 (void *)(current_p + new_size));
14008 }
14009#endif
14010 current_p += new_size;
14011 descr -= new_size;
14012 goto retry;
14013 }
14014#endif
14015 mark_stack_top -> mse_start =
14016 limit = current_p + WORDS_TO_BYTES(SPLIT_RANGE_WORDS-1);
14017 mark_stack_top -> mse_descr.w =
14018 descr - WORDS_TO_BYTES(SPLIT_RANGE_WORDS-1);
14019#ifdef ENABLE_TRACE
14020 if ((word)GC_trace_addr >= (word)current_p
14021 && (word)GC_trace_addr < (word)(current_p + descr)) {
14022 GC_log_printf("GC #%lu: large section; start %p, len %lu,"
14023 " splitting at %p\n",
14024 (unsigned long)GC_gc_no, (void *)current_p,
14025 (unsigned long)descr, (void *)limit);
14026 }
14027#endif
14028 limit += sizeof(word) - ALIGNMENT;
14029 break;
14030 case GC_DS_BITMAP:
14031 mark_stack_top--;
14032#ifdef ENABLE_TRACE
14033 if ((word)GC_trace_addr >= (word)current_p
14034 && (word)GC_trace_addr < (word)(current_p
14035 + WORDS_TO_BYTES(WORDSZ-2))) {
14036 GC_log_printf("GC #%lu: tracing from %p bitmap descr %lu\n",
14037 (unsigned long)GC_gc_no, (void *)current_p,
14038 (unsigned long)descr);
14039 }
14040#endif
14041 descr &= ~GC_DS_TAGS;
14042 credit -= WORDS_TO_BYTES(WORDSZ/2);
14043 while (descr != 0) {
14044 if ((descr & SIGNB) != 0) {
14045 current = *(word *)current_p;
14046 FIXUP_POINTER(current);
14047 if (current >= (word)least_ha && current < (word)greatest_ha) {
14048 PREFETCH((ptr_t)current);
14049#ifdef ENABLE_TRACE
14050 if (GC_trace_addr == current_p) {
14051 GC_log_printf("GC #%lu: considering(3) %p -> %p\n",
14052 (unsigned long)GC_gc_no, (void *)current_p,
14053 (void *)current);
14054 }
14055#endif
14056 PUSH_CONTENTS((ptr_t)current, mark_stack_top,
14057 mark_stack_limit, current_p);
14058 }
14059 }
14060 descr <<= 1;
14061 current_p += sizeof(word);
14062 }
14063 continue;
14064 case GC_DS_PROC:
14065 mark_stack_top--;
14066#ifdef ENABLE_TRACE
14067 if ((word)GC_trace_addr >= (word)current_p
14068 && GC_base(current_p) != 0
14069 && GC_base(current_p) == GC_base(GC_trace_addr)) {
14070 GC_log_printf("GC #%lu: tracing from %p, proc descr %lu\n",
14071 (unsigned long)GC_gc_no, (void *)current_p,
14072 (unsigned long)descr);
14073 }
14074#endif
14075 credit -= GC_PROC_BYTES;
14076 mark_stack_top = (*PROC(descr))((word *)current_p, mark_stack_top,
14077 mark_stack_limit, ENV(descr));
14078 continue;
14079 case GC_DS_PER_OBJECT:
14080 if ((signed_word)descr >= 0) {
14081 descr = *(word *)(current_p + descr - GC_DS_PER_OBJECT);
14082 } else {
14083 ptr_t type_descr = *(ptr_t *)current_p;
14084 if (EXPECT(0 == type_descr, FALSE)) {
14085 mark_stack_top--;
14086 continue;
14087 }
14088 descr = *(word *)(type_descr
14089 - ((signed_word)descr + (GC_INDIR_PER_OBJ_BIAS
14090 - GC_DS_PER_OBJECT)));
14091 }
14092 if (0 == descr) {
14093 mark_stack_top--;
14094 continue;
14095 }
14096 goto retry;
14097 }
14098 } else {
14099 mark_stack_top--;
14100#ifndef SMALL_CONFIG
14101 if (descr < sizeof(word))
14102 continue;
14103#endif
14104#ifdef ENABLE_TRACE
14105 if ((word)GC_trace_addr >= (word)current_p
14106 && (word)GC_trace_addr < (word)(current_p + descr)) {
14107 GC_log_printf("GC #%lu: small object; start %p, len %lu\n",
14108 (unsigned long)GC_gc_no, (void *)current_p,
14109 (unsigned long)descr);
14110 }
14111#endif
14112 limit = current_p + (word)descr;
14113 }
14114 GC_ASSERT(!((word)current_p & (ALIGNMENT-1)));
14115 credit -= limit - current_p;
14116 limit -= sizeof(word);
14117 {
14118#define PREF_DIST 4
14119#ifndef SMALL_CONFIG
14120 word deferred;
14121 for(;;) {
14122 PREFETCH(limit - PREF_DIST*CACHE_LINE_SIZE);
14123 GC_ASSERT((word)limit >= (word)current_p);
14124 deferred = *(word *)limit;
14125 FIXUP_POINTER(deferred);
14126 limit -= ALIGNMENT;
14127 if (deferred >= (word)least_ha && deferred < (word)greatest_ha) {
14128 PREFETCH((ptr_t)deferred);
14129 break;
14130 }
14131 if ((word)current_p > (word)limit) goto next_object;
14132 deferred = *(word *)limit;
14133 FIXUP_POINTER(deferred);
14134 limit -= ALIGNMENT;
14135 if (deferred >= (word)least_ha && deferred < (word)greatest_ha) {
14136 PREFETCH((ptr_t)deferred);
14137 break;
14138 }
14139 if ((word)current_p > (word)limit) goto next_object;
14140 }
14141#endif
14142 while ((word)current_p <= (word)limit) {
14143 current = *(word *)current_p;
14144 FIXUP_POINTER(current);
14145 PREFETCH(current_p + PREF_DIST*CACHE_LINE_SIZE);
14146 if (current >= (word)least_ha && current < (word)greatest_ha) {
14147 PREFETCH((ptr_t)current);
14148#ifdef ENABLE_TRACE
14149 if (GC_trace_addr == current_p) {
14150 GC_log_printf("GC #%lu: considering(1) %p -> %p\n",
14151 (unsigned long)GC_gc_no, (void *)current_p,
14152 (void *)current);
14153 }
14154#endif
14155 PUSH_CONTENTS((ptr_t)current, mark_stack_top,
14156 mark_stack_limit, current_p);
14157 }
14158 current_p += ALIGNMENT;
14159 }
14160#ifndef SMALL_CONFIG
14161#ifdef ENABLE_TRACE
14162 if (GC_trace_addr == current_p) {
14163 GC_log_printf("GC #%lu: considering(2) %p -> %p\n",
14164 (unsigned long)GC_gc_no, (void *)current_p,
14165 (void *)deferred);
14166 }
14167#endif
14168 PUSH_CONTENTS((ptr_t)deferred, mark_stack_top,
14169 mark_stack_limit, current_p);
14170 next_object:;
14171#endif
14172 }
14173 }
14174 return mark_stack_top;
14175}
14176#ifdef PARALLEL_MARK
14177STATIC GC_bool GC_help_wanted = FALSE;
14178STATIC unsigned GC_helper_count = 0;
14179STATIC unsigned GC_active_count = 0;
14180GC_INNER word GC_mark_no = 0;
14181#ifdef LINT2
14182#define LOCAL_MARK_STACK_SIZE (HBLKSIZE / 8)
14183#else
14184#define LOCAL_MARK_STACK_SIZE HBLKSIZE
14185#endif
14186GC_INNER void GC_wait_for_markers_init(void)
14187{
14188 signed_word count;
14189 if (GC_markers_m1 == 0)
14190 return;
14191#ifndef CAN_HANDLE_FORK
14192 GC_ASSERT(NULL == GC_main_local_mark_stack);
14193#else
14194 if (NULL == GC_main_local_mark_stack)
14195#endif
14196 {
14197 size_t bytes_to_get =
14198 ROUNDUP_PAGESIZE_IF_MMAP(LOCAL_MARK_STACK_SIZE * sizeof(mse));
14199 GC_ASSERT(GC_page_size != 0);
14200 GC_main_local_mark_stack = (mse *)GET_MEM(bytes_to_get);
14201 if (NULL == GC_main_local_mark_stack)
14202 ABORT("Insufficient memory for main local_mark_stack");
14203 GC_add_to_our_memory((ptr_t)GC_main_local_mark_stack, bytes_to_get);
14204 }
14205 GC_acquire_mark_lock();
14206 GC_fl_builder_count += GC_markers_m1;
14207 count = GC_fl_builder_count;
14208 GC_release_mark_lock();
14209 if (count != 0) {
14210 GC_ASSERT(count > 0);
14211 GC_wait_for_reclaim();
14212 }
14213}
14214STATIC mse * GC_steal_mark_stack(mse * low, mse * high, mse * local,
14215 unsigned max, mse **next)
14216{
14217 mse *p;
14218 mse *top = local - 1;
14219 unsigned i = 0;
14220 GC_ASSERT((word)high >= (word)(low - 1)
14221 && (word)(high - low + 1) <= GC_mark_stack_size);
14222 for (p = low; (word)p <= (word)high && i <= max; ++p) {
14223 word descr = (word)AO_load(&p->mse_descr.ao);
14224 if (descr != 0) {
14225 AO_store_release_write(&p->mse_descr.ao, 0);
14226 ++top;
14227 top -> mse_descr.w = descr;
14228 top -> mse_start = p -> mse_start;
14229 GC_ASSERT((descr & GC_DS_TAGS) != GC_DS_LENGTH
14230 || descr < (word)GC_greatest_plausible_heap_addr
14231 - (word)GC_least_plausible_heap_addr
14232 || (word)(p->mse_start + descr)
14233 <= (word)GC_least_plausible_heap_addr
14234 || (word)p->mse_start
14235 >= (word)GC_greatest_plausible_heap_addr);
14236 ++i;
14237 if ((descr & GC_DS_TAGS) == GC_DS_LENGTH) i += (int)(descr >> 8);
14238 }
14239 }
14240 *next = p;
14241 return top;
14242}
14243STATIC void GC_return_mark_stack(mse * low, mse * high)
14244{
14245 mse * my_top;
14246 mse * my_start;
14247 size_t stack_size;
14248 if ((word)high < (word)low) return;
14249 stack_size = high - low + 1;
14250 GC_acquire_mark_lock();
14251 my_top = GC_mark_stack_top;
14252 my_start = my_top + 1;
14253 if ((word)(my_start - GC_mark_stack + stack_size)
14254 > (word)GC_mark_stack_size) {
14255 GC_COND_LOG_PRINTF("No room to copy back mark stack\n");
14256 GC_mark_state = MS_INVALID;
14257 GC_mark_stack_too_small = TRUE;
14258 } else {
14259 BCOPY(low, my_start, stack_size * sizeof(mse));
14260 GC_ASSERT((mse *)AO_load((volatile AO_t *)(&GC_mark_stack_top))
14261 == my_top);
14262 AO_store_release_write((volatile AO_t *)(&GC_mark_stack_top),
14263 (AO_t)(my_top + stack_size));
14264 }
14265 GC_release_mark_lock();
14266 GC_notify_all_marker();
14267}
14268#ifndef N_LOCAL_ITERS
14269#define N_LOCAL_ITERS 1
14270#endif
14271static GC_bool has_inactive_helpers(void)
14272{
14273 GC_bool res;
14274 GC_acquire_mark_lock();
14275 res = GC_active_count < GC_helper_count;
14276 GC_release_mark_lock();
14277 return res;
14278}
14279STATIC void GC_do_local_mark(mse *local_mark_stack, mse *local_top)
14280{
14281 unsigned n;
14282 for (;;) {
14283 for (n = 0; n < N_LOCAL_ITERS; ++n) {
14284 local_top = GC_mark_from(local_top, local_mark_stack,
14285 local_mark_stack + LOCAL_MARK_STACK_SIZE);
14286 if ((word)local_top < (word)local_mark_stack) return;
14287 if ((word)(local_top - local_mark_stack)
14288 >= LOCAL_MARK_STACK_SIZE / 2) {
14289 GC_return_mark_stack(local_mark_stack, local_top);
14290 return;
14291 }
14292 }
14293 if ((word)AO_load((volatile AO_t *)&GC_mark_stack_top)
14294 < (word)AO_load(&GC_first_nonempty)
14295 && (word)local_top > (word)(local_mark_stack + 1)
14296 && has_inactive_helpers()) {
14297 mse * new_bottom = local_mark_stack
14298 + (local_top - local_mark_stack)/2;
14299 GC_ASSERT((word)new_bottom > (word)local_mark_stack
14300 && (word)new_bottom < (word)local_top);
14301 GC_return_mark_stack(local_mark_stack, new_bottom - 1);
14302 memmove(local_mark_stack, new_bottom,
14303 (local_top - new_bottom + 1) * sizeof(mse));
14304 local_top -= (new_bottom - local_mark_stack);
14305 }
14306 }
14307}
14308#ifndef ENTRIES_TO_GET
14309#define ENTRIES_TO_GET 5
14310#endif
14311STATIC void GC_mark_local(mse *local_mark_stack, int id)
14312{
14313 mse * my_first_nonempty;
14314 GC_active_count++;
14315 my_first_nonempty = (mse *)AO_load(&GC_first_nonempty);
14316 GC_ASSERT((word)GC_mark_stack <= (word)my_first_nonempty);
14317 GC_ASSERT((word)my_first_nonempty
14318 <= (word)AO_load((volatile AO_t *)&GC_mark_stack_top) + sizeof(mse));
14319 GC_VERBOSE_LOG_PRINTF("Starting mark helper %d\n", id);
14320 GC_release_mark_lock();
14321 for (;;) {
14322 size_t n_on_stack;
14323 unsigned n_to_get;
14324 mse * my_top;
14325 mse * local_top;
14326 mse * global_first_nonempty = (mse *)AO_load(&GC_first_nonempty);
14327 GC_ASSERT((word)my_first_nonempty >= (word)GC_mark_stack &&
14328 (word)my_first_nonempty <=
14329 (word)AO_load((volatile AO_t *)&GC_mark_stack_top)
14330 + sizeof(mse));
14331 GC_ASSERT((word)global_first_nonempty >= (word)GC_mark_stack);
14332 if ((word)my_first_nonempty < (word)global_first_nonempty) {
14333 my_first_nonempty = global_first_nonempty;
14334 } else if ((word)global_first_nonempty < (word)my_first_nonempty) {
14335 (void)AO_compare_and_swap(&GC_first_nonempty,
14336 (AO_t)global_first_nonempty,
14337 (AO_t)my_first_nonempty);
14338 }
14339 my_top = (mse *)AO_load_acquire((volatile AO_t *)(&GC_mark_stack_top));
14340 if ((word)my_top < (word)my_first_nonempty) {
14341 GC_acquire_mark_lock();
14342 my_top = GC_mark_stack_top;
14343 n_on_stack = my_top - my_first_nonempty + 1;
14344 if (0 == n_on_stack) {
14345 GC_active_count--;
14346 GC_ASSERT(GC_active_count <= GC_helper_count);
14347 if (0 == GC_active_count) GC_notify_all_marker();
14348 while (GC_active_count > 0
14349 && (word)AO_load(&GC_first_nonempty)
14350 > (word)GC_mark_stack_top) {
14351 GC_wait_marker();
14352 }
14353 if (GC_active_count == 0
14354 && (word)AO_load(&GC_first_nonempty)
14355 > (word)GC_mark_stack_top) {
14356 GC_bool need_to_notify = FALSE;
14357 GC_helper_count--;
14358 if (0 == GC_helper_count) need_to_notify = TRUE;
14359 GC_VERBOSE_LOG_PRINTF("Finished mark helper %d\n", id);
14360 if (need_to_notify) GC_notify_all_marker();
14361 return;
14362 }
14363 GC_active_count++;
14364 GC_ASSERT(GC_active_count > 0);
14365 GC_release_mark_lock();
14366 continue;
14367 } else {
14368 GC_release_mark_lock();
14369 }
14370 } else {
14371 n_on_stack = my_top - my_first_nonempty + 1;
14372 }
14373 n_to_get = ENTRIES_TO_GET;
14374 if (n_on_stack < 2 * ENTRIES_TO_GET) n_to_get = 1;
14375 local_top = GC_steal_mark_stack(my_first_nonempty, my_top,
14376 local_mark_stack, n_to_get,
14377 &my_first_nonempty);
14378 GC_ASSERT((word)my_first_nonempty >= (word)GC_mark_stack &&
14379 (word)my_first_nonempty <=
14380 (word)AO_load((volatile AO_t *)&GC_mark_stack_top)
14381 + sizeof(mse));
14382 GC_do_local_mark(local_mark_stack, local_top);
14383 }
14384}
14385STATIC void GC_do_parallel_mark(void)
14386{
14387 GC_acquire_mark_lock();
14388 GC_ASSERT(I_HOLD_LOCK());
14389 if (GC_help_wanted || GC_active_count != 0 || GC_helper_count != 0)
14390 ABORT("Tried to start parallel mark in bad state");
14391 GC_VERBOSE_LOG_PRINTF("Starting marking for mark phase number %lu\n",
14392 (unsigned long)GC_mark_no);
14393 GC_first_nonempty = (AO_t)GC_mark_stack;
14394 GC_active_count = 0;
14395 GC_helper_count = 1;
14396 GC_help_wanted = TRUE;
14397 GC_notify_all_marker();
14398 GC_mark_local(GC_main_local_mark_stack, 0);
14399 GC_help_wanted = FALSE;
14400 while (GC_helper_count > 0) {
14401 GC_wait_marker();
14402 }
14403 GC_VERBOSE_LOG_PRINTF("Finished marking for mark phase number %lu\n",
14404 (unsigned long)GC_mark_no);
14405 GC_mark_no++;
14406 GC_release_mark_lock();
14407 GC_notify_all_marker();
14408}
14409GC_INNER void GC_help_marker(word my_mark_no)
14410{
14411#define my_id my_id_mse.mse_descr.w
14412 mse my_id_mse;
14413 mse local_mark_stack[LOCAL_MARK_STACK_SIZE];
14414 GC_ASSERT(GC_parallel);
14415 while (GC_mark_no < my_mark_no
14416 || (!GC_help_wanted && GC_mark_no == my_mark_no)) {
14417 GC_wait_marker();
14418 }
14419 my_id = GC_helper_count;
14420 if (GC_mark_no != my_mark_no || my_id > (unsigned)GC_markers_m1) {
14421 return;
14422 }
14423 GC_helper_count = (unsigned)my_id + 1;
14424 GC_mark_local(local_mark_stack, (int)my_id);
14425#undef my_id
14426}
14427#endif
14428static void alloc_mark_stack(size_t n)
14429{
14430 mse * new_stack = (mse *)GC_scratch_alloc(n * sizeof(struct GC_ms_entry));
14431#ifdef GWW_VDB
14432 static GC_bool GC_incremental_at_stack_alloc = FALSE;
14433 GC_bool recycle_old = !GC_auto_incremental
14434 || GC_incremental_at_stack_alloc;
14435 GC_incremental_at_stack_alloc = GC_auto_incremental;
14436#else
14437#define recycle_old TRUE
14438#endif
14439 GC_mark_stack_too_small = FALSE;
14440 if (GC_mark_stack != NULL) {
14441 if (new_stack != 0) {
14442 if (recycle_old) {
14443 GC_scratch_recycle_inner(GC_mark_stack,
14444 GC_mark_stack_size * sizeof(struct GC_ms_entry));
14445 }
14446 GC_mark_stack = new_stack;
14447 GC_mark_stack_size = n;
14448 GC_mark_stack_limit = new_stack + n;
14449 GC_COND_LOG_PRINTF("Grew mark stack to %lu frames\n",
14450 (unsigned long)GC_mark_stack_size);
14451 } else {
14452 WARN("Failed to grow mark stack to %" WARN_PRIdPTR " frames\n", n);
14453 }
14454 } else if (NULL == new_stack) {
14455 GC_err_printf("No space for mark stack\n");
14456 EXIT();
14457 } else {
14458 GC_mark_stack = new_stack;
14459 GC_mark_stack_size = n;
14460 GC_mark_stack_limit = new_stack + n;
14461 }
14462 GC_mark_stack_top = GC_mark_stack-1;
14463}
14464GC_INNER void GC_mark_init(void)
14465{
14466 alloc_mark_stack(INITIAL_MARK_STACK_SIZE);
14467}
14468GC_API void GC_CALL GC_push_all(void *bottom, void *top)
14469{
14470 word length;
14471 bottom = (void *)(((word)bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
14472 top = (void *)((word)top & ~(ALIGNMENT-1));
14473 if ((word)bottom >= (word)top) return;
14474 GC_mark_stack_top++;
14475 if ((word)GC_mark_stack_top >= (word)GC_mark_stack_limit) {
14476 ABORT("Unexpected mark stack overflow");
14477 }
14478 length = (word)top - (word)bottom;
14479#if GC_DS_TAGS > ALIGNMENT - 1
14480 length += GC_DS_TAGS;
14481 length &= ~GC_DS_TAGS;
14482#endif
14483 GC_mark_stack_top -> mse_start = (ptr_t)bottom;
14484 GC_mark_stack_top -> mse_descr.w = length;
14485}
14486#ifndef GC_DISABLE_INCREMENTAL
14487 STATIC void GC_push_selected(ptr_t bottom, ptr_t top,
14488 GC_bool (*dirty_fn)(struct hblk *))
14489 {
14490 struct hblk * h;
14491 bottom = (ptr_t)(((word) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
14492 top = (ptr_t)(((word) top) & ~(ALIGNMENT-1));
14493 if ((word)bottom >= (word)top) return;
14494 h = HBLKPTR(bottom + HBLKSIZE);
14495 if ((word)top <= (word)h) {
14496 if ((*dirty_fn)(h-1)) {
14497 GC_push_all(bottom, top);
14498 }
14499 return;
14500 }
14501 if ((*dirty_fn)(h-1)) {
14502 if ((word)(GC_mark_stack_top - GC_mark_stack)
14503 > 3 * GC_mark_stack_size / 4) {
14504 GC_push_all(bottom, top);
14505 return;
14506 }
14507 GC_push_all(bottom, h);
14508 }
14509 while ((word)(h+1) <= (word)top) {
14510 if ((*dirty_fn)(h)) {
14511 if ((word)(GC_mark_stack_top - GC_mark_stack)
14512 > 3 * GC_mark_stack_size / 4) {
14513 GC_push_all(h, top);
14514 return;
14515 } else {
14516 GC_push_all(h, h + 1);
14517 }
14518 }
14519 h++;
14520 }
14521 if ((ptr_t)h != top && (*dirty_fn)(h)) {
14522 GC_push_all(h, top);
14523 }
14524 }
14525 GC_API void GC_CALL GC_push_conditional(void *bottom, void *top, int all)
14526 {
14527 if (!all) {
14528 GC_push_selected((ptr_t)bottom, (ptr_t)top, GC_page_was_dirty);
14529 } else {
14530#ifdef PROC_VDB
14531 if (GC_auto_incremental) {
14532 GC_push_selected((ptr_t)bottom, (ptr_t)top, GC_page_was_ever_dirty);
14533 } else
14534#endif
14535 {
14536 GC_push_all(bottom, top);
14537 }
14538 }
14539 }
14540#ifndef NO_VDB_FOR_STATIC_ROOTS
14541#ifndef PROC_VDB
14542 STATIC GC_bool GC_static_page_was_dirty(struct hblk *h)
14543 {
14544 return get_pht_entry_from_index(GC_grungy_pages, PHT_HASH(h));
14545 }
14546#endif
14547 GC_INNER void GC_push_conditional_static(void *bottom, void *top,
14548 GC_bool all)
14549 {
14550#ifdef PROC_VDB
14551 GC_push_conditional(bottom, top, all);
14552#else
14553 if (all || !GC_is_vdb_for_static_roots()) {
14554 GC_push_all(bottom, top);
14555 } else {
14556 GC_push_selected((ptr_t)bottom, (ptr_t)top,
14557 GC_static_page_was_dirty);
14558 }
14559#endif
14560 }
14561#endif
14562#else
14563 GC_API void GC_CALL GC_push_conditional(void *bottom, void *top,
14564 int all GC_ATTR_UNUSED)
14565 {
14566 GC_push_all(bottom, top);
14567 }
14568#endif
14569#if defined(AMIGA) || defined(MACOS) || defined(GC_DARWIN_THREADS)
14570 void GC_push_one(word p)
14571 {
14572 GC_PUSH_ONE_STACK(p, MARKED_FROM_REGISTER);
14573 }
14574#endif
14575#ifdef GC_WIN32_THREADS
14576 GC_INNER void GC_push_many_regs(const word *regs, unsigned count)
14577 {
14578 unsigned i;
14579 for (i = 0; i < count; i++)
14580 GC_PUSH_ONE_STACK(regs[i], MARKED_FROM_REGISTER);
14581 }
14582#endif
14583GC_API struct GC_ms_entry * GC_CALL GC_mark_and_push(void *obj,
14584 mse *mark_stack_ptr,
14585 mse *mark_stack_limit,
14586 void ** src GC_ATTR_UNUSED)
14587{
14588 hdr * hhdr;
14589 PREFETCH(obj);
14590 GET_HDR(obj, hhdr);
14591 if ((EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr), FALSE)
14592 && (!GC_all_interior_pointers
14593 || NULL == (hhdr = GC_find_header((ptr_t)GC_base(obj)))))
14594 || EXPECT(HBLK_IS_FREE(hhdr), FALSE)) {
14595 GC_ADD_TO_BLACK_LIST_NORMAL(obj, (ptr_t)src);
14596 return mark_stack_ptr;
14597 }
14598 return GC_push_contents_hdr((ptr_t)obj, mark_stack_ptr, mark_stack_limit,
14599 (ptr_t)src, hhdr, TRUE);
14600}
14601#if defined(PRINT_BLACK_LIST) || defined(KEEP_BACK_PTRS)
14602 GC_INNER void GC_mark_and_push_stack(ptr_t p, ptr_t source)
14603#else
14604 GC_INNER void GC_mark_and_push_stack(ptr_t p)
14605#define source ((ptr_t)0)
14606#endif
14607{
14608 hdr * hhdr;
14609 ptr_t r = p;
14610 PREFETCH(p);
14611 GET_HDR(p, hhdr);
14612 if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr), FALSE)) {
14613 if (NULL == hhdr
14614 || (r = (ptr_t)GC_base(p)) == NULL
14615 || (hhdr = HDR(r)) == NULL) {
14616 GC_ADD_TO_BLACK_LIST_STACK(p, source);
14617 return;
14618 }
14619 }
14620 if (EXPECT(HBLK_IS_FREE(hhdr), FALSE)) {
14621 GC_ADD_TO_BLACK_LIST_NORMAL(p, source);
14622 return;
14623 }
14624#ifdef THREADS
14625 GC_dirty(p);
14626#endif
14627 GC_mark_stack_top = GC_push_contents_hdr(r, GC_mark_stack_top,
14628 GC_mark_stack_limit,
14629 source, hhdr, FALSE);
14630}
14631#undef source
14632#ifdef TRACE_BUF
14633#ifndef TRACE_ENTRIES
14634#define TRACE_ENTRIES 1000
14635#endif
14636struct trace_entry {
14637 char * kind;
14638 word gc_no;
14639 word bytes_allocd;
14640 word arg1;
14641 word arg2;
14642} GC_trace_buf[TRACE_ENTRIES] = { { NULL, 0, 0, 0, 0 } };
14643void GC_add_trace_entry(char *kind, word arg1, word arg2)
14644{
14645 GC_trace_buf[GC_trace_buf_ptr].kind = kind;
14646 GC_trace_buf[GC_trace_buf_ptr].gc_no = GC_gc_no;
14647 GC_trace_buf[GC_trace_buf_ptr].bytes_allocd = GC_bytes_allocd;
14648 GC_trace_buf[GC_trace_buf_ptr].arg1 = arg1 ^ 0x80000000;
14649 GC_trace_buf[GC_trace_buf_ptr].arg2 = arg2 ^ 0x80000000;
14650 GC_trace_buf_ptr++;
14651 if (GC_trace_buf_ptr >= TRACE_ENTRIES) GC_trace_buf_ptr = 0;
14652}
14653GC_API void GC_CALL GC_print_trace_inner(word gc_no)
14654{
14655 int i;
14656 for (i = GC_trace_buf_ptr-1; i != GC_trace_buf_ptr; i--) {
14657 struct trace_entry *p;
14658 if (i < 0) i = TRACE_ENTRIES-1;
14659 p = GC_trace_buf + i;
14660 if (p -> gc_no < gc_no || p -> kind == 0) {
14661 return;
14662 }
14663 GC_printf("Trace:%s (gc:%u, bytes:%lu) 0x%lX, 0x%lX\n",
14664 p -> kind, (unsigned)p -> gc_no,
14665 (unsigned long)p -> bytes_allocd,
14666 (long)p->arg1 ^ 0x80000000L, (long)p->arg2 ^ 0x80000000L);
14667 }
14668 GC_printf("Trace incomplete\n");
14669}
14670GC_API void GC_CALL GC_print_trace(word gc_no)
14671{
14672 DCL_LOCK_STATE;
14673 LOCK();
14674 GC_print_trace_inner(gc_no);
14675 UNLOCK();
14676}
14677#endif
14678GC_ATTR_NO_SANITIZE_ADDR GC_ATTR_NO_SANITIZE_MEMORY GC_ATTR_NO_SANITIZE_THREAD
14679GC_API void GC_CALL GC_push_all_eager(void *bottom, void *top)
14680{
14681 word * b = (word *)(((word) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
14682 word * t = (word *)(((word) top) & ~(ALIGNMENT-1));
14683 REGISTER word *p;
14684 REGISTER word *lim;
14685 REGISTER ptr_t greatest_ha = (ptr_t)GC_greatest_plausible_heap_addr;
14686 REGISTER ptr_t least_ha = (ptr_t)GC_least_plausible_heap_addr;
14687#define GC_greatest_plausible_heap_addr greatest_ha
14688#define GC_least_plausible_heap_addr least_ha
14689 if (top == 0) return;
14690 lim = t - 1 ;
14691 for (p = b; (word)p <= (word)lim;
14692 p = (word *)(((ptr_t)p) + ALIGNMENT)) {
14693 REGISTER word q = *p;
14694 GC_PUSH_ONE_STACK(q, p);
14695 }
14696#undef GC_greatest_plausible_heap_addr
14697#undef GC_least_plausible_heap_addr
14698}
14699GC_INNER void GC_push_all_stack(ptr_t bottom, ptr_t top)
14700{
14701#ifndef NEED_FIXUP_POINTER
14702 if (GC_all_interior_pointers
14703#if defined(THREADS) && defined(MPROTECT_VDB)
14704 && !GC_auto_incremental
14705#endif
14706 && (word)GC_mark_stack_top
14707 < (word)(GC_mark_stack_limit - INITIAL_MARK_STACK_SIZE/8)) {
14708 GC_push_all(bottom, top);
14709 } else
14710#endif
14711 {
14712 GC_push_all_eager(bottom, top);
14713 }
14714}
14715#if defined(WRAP_MARK_SOME) && defined(PARALLEL_MARK)
14716 GC_ATTR_NO_SANITIZE_ADDR GC_ATTR_NO_SANITIZE_MEMORY
14717 GC_ATTR_NO_SANITIZE_THREAD
14718 GC_INNER void GC_push_conditional_eager(void *bottom, void *top,
14719 GC_bool all)
14720 {
14721 word * b = (word *)(((word) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
14722 word * t = (word *)(((word) top) & ~(ALIGNMENT-1));
14723 REGISTER word *p;
14724 REGISTER word *lim;
14725 REGISTER ptr_t greatest_ha = (ptr_t)GC_greatest_plausible_heap_addr;
14726 REGISTER ptr_t least_ha = (ptr_t)GC_least_plausible_heap_addr;
14727#define GC_greatest_plausible_heap_addr greatest_ha
14728#define GC_least_plausible_heap_addr least_ha
14729 if (top == NULL)
14730 return;
14731 (void)all;
14732 lim = t - 1;
14733 for (p = b; (word)p <= (word)lim; p = (word *)((ptr_t)p + ALIGNMENT)) {
14734 REGISTER word q = *p;
14735 GC_PUSH_ONE_HEAP(q, p, GC_mark_stack_top);
14736 }
14737#undef GC_greatest_plausible_heap_addr
14738#undef GC_least_plausible_heap_addr
14739 }
14740#endif
14741#if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES) && \
14742 defined(MARK_BIT_PER_GRANULE)
14743#if GC_GRANULE_WORDS == 1
14744#define USE_PUSH_MARKED_ACCELERATORS
14745#define PUSH_GRANULE(q) \
14746 do { \
14747 word qcontents = (q)[0]; \
14748 GC_PUSH_ONE_HEAP(qcontents, q, GC_mark_stack_top); \
14749 } while (0)
14750#elif GC_GRANULE_WORDS == 2
14751#define USE_PUSH_MARKED_ACCELERATORS
14752#define PUSH_GRANULE(q) \
14753 do { \
14754 word qcontents = (q)[0]; \
14755 GC_PUSH_ONE_HEAP(qcontents, q, GC_mark_stack_top); \
14756 qcontents = (q)[1]; \
14757 GC_PUSH_ONE_HEAP(qcontents, (q)+1, GC_mark_stack_top); \
14758 } while (0)
14759#elif GC_GRANULE_WORDS == 4
14760#define USE_PUSH_MARKED_ACCELERATORS
14761#define PUSH_GRANULE(q) \
14762 do { \
14763 word qcontents = (q)[0]; \
14764 GC_PUSH_ONE_HEAP(qcontents, q, GC_mark_stack_top); \
14765 qcontents = (q)[1]; \
14766 GC_PUSH_ONE_HEAP(qcontents, (q)+1, GC_mark_stack_top); \
14767 qcontents = (q)[2]; \
14768 GC_PUSH_ONE_HEAP(qcontents, (q)+2, GC_mark_stack_top); \
14769 qcontents = (q)[3]; \
14770 GC_PUSH_ONE_HEAP(qcontents, (q)+3, GC_mark_stack_top); \
14771 } while (0)
14772#endif
14773#endif
14774#ifdef USE_PUSH_MARKED_ACCELERATORS
14775STATIC void GC_push_marked1(struct hblk *h, hdr *hhdr)
14776{
14777 word * mark_word_addr = &(hhdr->hb_marks[0]);
14778 word *p;
14779 word *plim;
14780 ptr_t greatest_ha = (ptr_t)GC_greatest_plausible_heap_addr;
14781 ptr_t least_ha = (ptr_t)GC_least_plausible_heap_addr;
14782 mse * mark_stack_top = GC_mark_stack_top;
14783 mse * mark_stack_limit = GC_mark_stack_limit;
14784#undef GC_mark_stack_top
14785#undef GC_mark_stack_limit
14786#define GC_mark_stack_top mark_stack_top
14787#define GC_mark_stack_limit mark_stack_limit
14788#define GC_greatest_plausible_heap_addr greatest_ha
14789#define GC_least_plausible_heap_addr least_ha
14790 p = (word *)(h->hb_body);
14791 plim = (word *)(((word)h) + HBLKSIZE);
14792 while ((word)p < (word)plim) {
14793 word mark_word = *mark_word_addr++;
14794 word *q = p;
14795 while(mark_word != 0) {
14796 if (mark_word & 1) {
14797 PUSH_GRANULE(q);
14798 }
14799 q += GC_GRANULE_WORDS;
14800 mark_word >>= 1;
14801 }
14802 p += WORDSZ*GC_GRANULE_WORDS;
14803 }
14804#undef GC_greatest_plausible_heap_addr
14805#undef GC_least_plausible_heap_addr
14806#undef GC_mark_stack_top
14807#undef GC_mark_stack_limit
14808#define GC_mark_stack_limit GC_arrays._mark_stack_limit
14809#define GC_mark_stack_top GC_arrays._mark_stack_top
14810 GC_mark_stack_top = mark_stack_top;
14811}
14812#ifndef UNALIGNED_PTRS
14813STATIC void GC_push_marked2(struct hblk *h, hdr *hhdr)
14814{
14815 word * mark_word_addr = &(hhdr->hb_marks[0]);
14816 word *p;
14817 word *plim;
14818 ptr_t greatest_ha = (ptr_t)GC_greatest_plausible_heap_addr;
14819 ptr_t least_ha = (ptr_t)GC_least_plausible_heap_addr;
14820 mse * mark_stack_top = GC_mark_stack_top;
14821 mse * mark_stack_limit = GC_mark_stack_limit;
14822#undef GC_mark_stack_top
14823#undef GC_mark_stack_limit
14824#define GC_mark_stack_top mark_stack_top
14825#define GC_mark_stack_limit mark_stack_limit
14826#define GC_greatest_plausible_heap_addr greatest_ha
14827#define GC_least_plausible_heap_addr least_ha
14828 p = (word *)(h->hb_body);
14829 plim = (word *)(((word)h) + HBLKSIZE);
14830 while ((word)p < (word)plim) {
14831 word mark_word = *mark_word_addr++;
14832 word *q = p;
14833 while(mark_word != 0) {
14834 if (mark_word & 1) {
14835 PUSH_GRANULE(q);
14836 PUSH_GRANULE(q + GC_GRANULE_WORDS);
14837 }
14838 q += 2 * GC_GRANULE_WORDS;
14839 mark_word >>= 2;
14840 }
14841 p += WORDSZ*GC_GRANULE_WORDS;
14842 }
14843#undef GC_greatest_plausible_heap_addr
14844#undef GC_least_plausible_heap_addr
14845#undef GC_mark_stack_top
14846#undef GC_mark_stack_limit
14847#define GC_mark_stack_limit GC_arrays._mark_stack_limit
14848#define GC_mark_stack_top GC_arrays._mark_stack_top
14849 GC_mark_stack_top = mark_stack_top;
14850}
14851#if GC_GRANULE_WORDS < 4
14852STATIC void GC_push_marked4(struct hblk *h, hdr *hhdr)
14853{
14854 word * mark_word_addr = &(hhdr->hb_marks[0]);
14855 word *p;
14856 word *plim;
14857 ptr_t greatest_ha = (ptr_t)GC_greatest_plausible_heap_addr;
14858 ptr_t least_ha = (ptr_t)GC_least_plausible_heap_addr;
14859 mse * mark_stack_top = GC_mark_stack_top;
14860 mse * mark_stack_limit = GC_mark_stack_limit;
14861#undef GC_mark_stack_top
14862#undef GC_mark_stack_limit
14863#define GC_mark_stack_top mark_stack_top
14864#define GC_mark_stack_limit mark_stack_limit
14865#define GC_greatest_plausible_heap_addr greatest_ha
14866#define GC_least_plausible_heap_addr least_ha
14867 p = (word *)(h->hb_body);
14868 plim = (word *)(((word)h) + HBLKSIZE);
14869 while ((word)p < (word)plim) {
14870 word mark_word = *mark_word_addr++;
14871 word *q = p;
14872 while(mark_word != 0) {
14873 if (mark_word & 1) {
14874 PUSH_GRANULE(q);
14875 PUSH_GRANULE(q + GC_GRANULE_WORDS);
14876 PUSH_GRANULE(q + 2*GC_GRANULE_WORDS);
14877 PUSH_GRANULE(q + 3*GC_GRANULE_WORDS);
14878 }
14879 q += 4 * GC_GRANULE_WORDS;
14880 mark_word >>= 4;
14881 }
14882 p += WORDSZ*GC_GRANULE_WORDS;
14883 }
14884#undef GC_greatest_plausible_heap_addr
14885#undef GC_least_plausible_heap_addr
14886#undef GC_mark_stack_top
14887#undef GC_mark_stack_limit
14888#define GC_mark_stack_limit GC_arrays._mark_stack_limit
14889#define GC_mark_stack_top GC_arrays._mark_stack_top
14890 GC_mark_stack_top = mark_stack_top;
14891}
14892#endif
14893#endif
14894#endif
14895STATIC void GC_push_marked(struct hblk *h, hdr *hhdr)
14896{
14897 word sz = hhdr -> hb_sz;
14898 word descr = hhdr -> hb_descr;
14899 ptr_t p;
14900 word bit_no;
14901 ptr_t lim;
14902 mse * GC_mark_stack_top_reg;
14903 mse * mark_stack_limit = GC_mark_stack_limit;
14904 if (( GC_DS_LENGTH) == descr) return;
14905 if (GC_block_empty(hhdr)) return;
14906#if !defined(GC_DISABLE_INCREMENTAL)
14907 GC_n_rescuing_pages++;
14908#endif
14909 GC_objects_are_marked = TRUE;
14910 if (sz > MAXOBJBYTES) {
14911 lim = h -> hb_body;
14912 } else {
14913 lim = (ptr_t)((word)(h + 1)->hb_body - sz);
14914 }
14915 switch(BYTES_TO_GRANULES(sz)) {
14916#if defined(USE_PUSH_MARKED_ACCELERATORS)
14917 case 1:
14918 GC_push_marked1(h, hhdr);
14919 break;
14920#if !defined(UNALIGNED_PTRS)
14921 case 2:
14922 GC_push_marked2(h, hhdr);
14923 break;
14924#if GC_GRANULE_WORDS < 4
14925 case 4:
14926 GC_push_marked4(h, hhdr);
14927 break;
14928#endif
14929#endif
14930#else
14931 case 1:
14932#endif
14933 default:
14934 GC_mark_stack_top_reg = GC_mark_stack_top;
14935 for (p = h -> hb_body, bit_no = 0; (word)p <= (word)lim;
14936 p += sz, bit_no += MARK_BIT_OFFSET(sz)) {
14937 if (mark_bit_from_hdr(hhdr, bit_no)) {
14938 GC_mark_stack_top_reg = GC_push_obj(p, hhdr, GC_mark_stack_top_reg,
14939 mark_stack_limit);
14940 }
14941 }
14942 GC_mark_stack_top = GC_mark_stack_top_reg;
14943 }
14944}
14945#ifdef ENABLE_DISCLAIM
14946 STATIC void GC_push_unconditionally(struct hblk *h, hdr *hhdr)
14947 {
14948 word sz = hhdr -> hb_sz;
14949 word descr = hhdr -> hb_descr;
14950 ptr_t p;
14951 ptr_t lim;
14952 mse * GC_mark_stack_top_reg;
14953 mse * mark_stack_limit = GC_mark_stack_limit;
14954 if (( GC_DS_LENGTH) == descr)
14955 return;
14956#if !defined(GC_DISABLE_INCREMENTAL)
14957 GC_n_rescuing_pages++;
14958#endif
14959 GC_objects_are_marked = TRUE;
14960 if (sz > MAXOBJBYTES)
14961 lim = h -> hb_body;
14962 else
14963 lim = (ptr_t)((word)(h + 1)->hb_body - sz);
14964 GC_mark_stack_top_reg = GC_mark_stack_top;
14965 for (p = h -> hb_body; (word)p <= (word)lim; p += sz)
14966 if ((*(word *)p & 0x3) != 0)
14967 GC_mark_stack_top_reg = GC_push_obj(p, hhdr, GC_mark_stack_top_reg,
14968 mark_stack_limit);
14969 GC_mark_stack_top = GC_mark_stack_top_reg;
14970 }
14971#endif
14972#ifndef GC_DISABLE_INCREMENTAL
14973 STATIC GC_bool GC_block_was_dirty(struct hblk *h, hdr *hhdr)
14974 {
14975 word sz = hhdr -> hb_sz;
14976 if (sz <= MAXOBJBYTES) {
14977 return(GC_page_was_dirty(h));
14978 } else {
14979 ptr_t p = (ptr_t)h;
14980 while ((word)p < (word)h + sz) {
14981 if (GC_page_was_dirty((struct hblk *)p)) return(TRUE);
14982 p += HBLKSIZE;
14983 }
14984 return(FALSE);
14985 }
14986 }
14987#endif
14988STATIC struct hblk * GC_push_next_marked(struct hblk *h)
14989{
14990 hdr * hhdr = HDR(h);
14991 if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr) || HBLK_IS_FREE(hhdr), FALSE)) {
14992 h = GC_next_block(h, FALSE);
14993 if (NULL == h) return NULL;
14994 hhdr = GC_find_header((ptr_t)h);
14995 } else {
14996#ifdef LINT2
14997 if (NULL == h) ABORT("Bad HDR() definition");
14998#endif
14999 }
15000 GC_push_marked(h, hhdr);
15001 return(h + OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz));
15002}
15003#ifndef GC_DISABLE_INCREMENTAL
15004 STATIC struct hblk * GC_push_next_marked_dirty(struct hblk *h)
15005 {
15006 hdr * hhdr = HDR(h);
15007 if (!GC_incremental) ABORT("Dirty bits not set up");
15008 for (;;) {
15009 if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr)
15010 || HBLK_IS_FREE(hhdr), FALSE)) {
15011 h = GC_next_block(h, FALSE);
15012 if (NULL == h) return NULL;
15013 hhdr = GC_find_header((ptr_t)h);
15014 } else {
15015#ifdef LINT2
15016 if (NULL == h) ABORT("Bad HDR() definition");
15017#endif
15018 }
15019 if (GC_block_was_dirty(h, hhdr))
15020 break;
15021 h += OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
15022 hhdr = HDR(h);
15023 }
15024#ifdef ENABLE_DISCLAIM
15025 if ((hhdr -> hb_flags & MARK_UNCONDITIONALLY) != 0) {
15026 GC_push_unconditionally(h, hhdr);
15027 } else
15028#endif
15029 {
15030 GC_push_marked(h, hhdr);
15031 }
15032 return(h + OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz));
15033 }
15034#endif
15035STATIC struct hblk * GC_push_next_marked_uncollectable(struct hblk *h)
15036{
15037 hdr * hhdr = HDR(h);
15038 for (;;) {
15039 if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr)
15040 || HBLK_IS_FREE(hhdr), FALSE)) {
15041 h = GC_next_block(h, FALSE);
15042 if (NULL == h) return NULL;
15043 hhdr = GC_find_header((ptr_t)h);
15044 } else {
15045#ifdef LINT2
15046 if (NULL == h) ABORT("Bad HDR() definition");
15047#endif
15048 }
15049 if (hhdr -> hb_obj_kind == UNCOLLECTABLE) {
15050 GC_push_marked(h, hhdr);
15051 break;
15052 }
15053#ifdef ENABLE_DISCLAIM
15054 if ((hhdr -> hb_flags & MARK_UNCONDITIONALLY) != 0) {
15055 GC_push_unconditionally(h, hhdr);
15056 break;
15057 }
15058#endif
15059 h += OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
15060 hhdr = HDR(h);
15061 }
15062 return(h + OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz));
15063}
15064#include <stdio.h>
15065int GC_no_dls = 0;
15066#if !defined(NO_DEBUGGING) || defined(GC_ASSERTIONS)
15067 GC_INNER word GC_compute_root_size(void)
15068 {
15069 int i;
15070 word size = 0;
15071 for (i = 0; i < n_root_sets; i++) {
15072 size += GC_static_roots[i].r_end - GC_static_roots[i].r_start;
15073 }
15074 return size;
15075 }
15076#endif
15077#if !defined(NO_DEBUGGING)
15078 void GC_print_static_roots(void)
15079 {
15080 int i;
15081 word size;
15082 for (i = 0; i < n_root_sets; i++) {
15083 GC_printf("From %p to %p%s\n",
15084 (void *)GC_static_roots[i].r_start,
15085 (void *)GC_static_roots[i].r_end,
15086 GC_static_roots[i].r_tmp ? " (temporary)" : "");
15087 }
15088 GC_printf("GC_root_size= %lu\n", (unsigned long)GC_root_size);
15089 if ((size = GC_compute_root_size()) != GC_root_size)
15090 GC_err_printf("GC_root_size incorrect!! Should be: %lu\n",
15091 (unsigned long)size);
15092 }
15093#endif
15094#ifndef THREADS
15095 GC_INNER GC_bool GC_is_static_root(void *p)
15096 {
15097 static int last_root_set = MAX_ROOT_SETS;
15098 int i;
15099 if (last_root_set < n_root_sets
15100 && (word)p >= (word)GC_static_roots[last_root_set].r_start
15101 && (word)p < (word)GC_static_roots[last_root_set].r_end)
15102 return(TRUE);
15103 for (i = 0; i < n_root_sets; i++) {
15104 if ((word)p >= (word)GC_static_roots[i].r_start
15105 && (word)p < (word)GC_static_roots[i].r_end) {
15106 last_root_set = i;
15107 return(TRUE);
15108 }
15109 }
15110 return(FALSE);
15111 }
15112#endif
15113#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
15114 GC_INLINE int rt_hash(ptr_t addr)
15115 {
15116 word result = (word) addr;
15117#if CPP_WORDSZ > 8*LOG_RT_SIZE
15118 result ^= result >> 8*LOG_RT_SIZE;
15119#endif
15120#if CPP_WORDSZ > 4*LOG_RT_SIZE
15121 result ^= result >> 4*LOG_RT_SIZE;
15122#endif
15123 result ^= result >> 2*LOG_RT_SIZE;
15124 result ^= result >> LOG_RT_SIZE;
15125 result &= (RT_SIZE-1);
15126 return(result);
15127 }
15128 GC_INNER void * GC_roots_present(ptr_t b)
15129 {
15130 int h = rt_hash(b);
15131 struct roots *p = GC_root_index[h];
15132 while (p != 0) {
15133 if (p -> r_start == (ptr_t)b) return(p);
15134 p = p -> r_next;
15135 }
15136 return NULL;
15137 }
15138 GC_INLINE void add_roots_to_index(struct roots *p)
15139 {
15140 int h = rt_hash(p -> r_start);
15141 p -> r_next = GC_root_index[h];
15142 GC_root_index[h] = p;
15143 }
15144#endif
15145GC_INNER word GC_root_size = 0;
15146GC_API void GC_CALL GC_add_roots(void *b, void *e)
15147{
15148 DCL_LOCK_STATE;
15149 if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
15150 LOCK();
15151 GC_add_roots_inner((ptr_t)b, (ptr_t)e, FALSE);
15152 UNLOCK();
15153}
15154void GC_add_roots_inner(ptr_t b, ptr_t e, GC_bool tmp)
15155{
15156 GC_ASSERT((word)b <= (word)e);
15157 b = (ptr_t)(((word)b + (sizeof(word) - 1)) & ~(word)(sizeof(word) - 1));
15158 e = (ptr_t)((word)e & ~(word)(sizeof(word) - 1));
15159 if ((word)b >= (word)e) return;
15160#if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
15161 {
15162 int i;
15163 struct roots * old = NULL;
15164 for (i = 0; i < n_root_sets; i++) {
15165 old = GC_static_roots + i;
15166 if ((word)b <= (word)old->r_end
15167 && (word)e >= (word)old->r_start) {
15168 if ((word)b < (word)old->r_start) {
15169 GC_root_size += old->r_start - b;
15170 old -> r_start = b;
15171 }
15172 if ((word)e > (word)old->r_end) {
15173 GC_root_size += e - old->r_end;
15174 old -> r_end = e;
15175 }
15176 old -> r_tmp &= tmp;
15177 break;
15178 }
15179 }
15180 if (i < n_root_sets) {
15181 struct roots *other;
15182 for (i++; i < n_root_sets; i++) {
15183 other = GC_static_roots + i;
15184 b = other -> r_start;
15185 e = other -> r_end;
15186 if ((word)b <= (word)old->r_end
15187 && (word)e >= (word)old->r_start) {
15188 if ((word)b < (word)old->r_start) {
15189 GC_root_size += old->r_start - b;
15190 old -> r_start = b;
15191 }
15192 if ((word)e > (word)old->r_end) {
15193 GC_root_size += e - old->r_end;
15194 old -> r_end = e;
15195 }
15196 old -> r_tmp &= other -> r_tmp;
15197 GC_root_size -= (other -> r_end - other -> r_start);
15198 other -> r_start = GC_static_roots[n_root_sets-1].r_start;
15199 other -> r_end = GC_static_roots[n_root_sets-1].r_end;
15200 n_root_sets--;
15201 }
15202 }
15203 return;
15204 }
15205 }
15206#else
15207 {
15208 struct roots * old = (struct roots *)GC_roots_present(b);
15209 if (old != 0) {
15210 if ((word)e <= (word)old->r_end) {
15211 old -> r_tmp &= tmp;
15212 return;
15213 }
15214 if (old -> r_tmp == tmp || !tmp) {
15215 GC_root_size += e - old -> r_end;
15216 old -> r_end = e;
15217 old -> r_tmp = tmp;
15218 return;
15219 }
15220 b = old -> r_end;
15221 }
15222 }
15223#endif
15224 if (n_root_sets == MAX_ROOT_SETS) {
15225 ABORT("Too many root sets");
15226 }
15227#ifdef DEBUG_ADD_DEL_ROOTS
15228 GC_log_printf("Adding data root section %d: %p .. %p%s\n",
15229 n_root_sets, (void *)b, (void *)e,
15230 tmp ? " (temporary)" : "");
15231#endif
15232 GC_static_roots[n_root_sets].r_start = (ptr_t)b;
15233 GC_static_roots[n_root_sets].r_end = (ptr_t)e;
15234 GC_static_roots[n_root_sets].r_tmp = tmp;
15235#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
15236 GC_static_roots[n_root_sets].r_next = 0;
15237 add_roots_to_index(GC_static_roots + n_root_sets);
15238#endif
15239 GC_root_size += e - b;
15240 n_root_sets++;
15241}
15242GC_API void GC_CALL GC_clear_roots(void)
15243{
15244 DCL_LOCK_STATE;
15245 if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
15246 LOCK();
15247#ifdef THREADS
15248 GC_roots_were_cleared = TRUE;
15249#endif
15250 n_root_sets = 0;
15251 GC_root_size = 0;
15252#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
15253 BZERO(GC_root_index, RT_SIZE * sizeof(void *));
15254#endif
15255#ifdef DEBUG_ADD_DEL_ROOTS
15256 GC_log_printf("Clear all data root sections\n");
15257#endif
15258 UNLOCK();
15259}
15260STATIC void GC_remove_root_at_pos(int i)
15261{
15262#ifdef DEBUG_ADD_DEL_ROOTS
15263 GC_log_printf("Remove data root section at %d: %p .. %p%s\n",
15264 i, (void *)GC_static_roots[i].r_start,
15265 (void *)GC_static_roots[i].r_end,
15266 GC_static_roots[i].r_tmp ? " (temporary)" : "");
15267#endif
15268 GC_root_size -= (GC_static_roots[i].r_end - GC_static_roots[i].r_start);
15269 GC_static_roots[i].r_start = GC_static_roots[n_root_sets-1].r_start;
15270 GC_static_roots[i].r_end = GC_static_roots[n_root_sets-1].r_end;
15271 GC_static_roots[i].r_tmp = GC_static_roots[n_root_sets-1].r_tmp;
15272 n_root_sets--;
15273}
15274#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
15275 STATIC void GC_rebuild_root_index(void)
15276 {
15277 int i;
15278 BZERO(GC_root_index, RT_SIZE * sizeof(void *));
15279 for (i = 0; i < n_root_sets; i++)
15280 add_roots_to_index(GC_static_roots + i);
15281 }
15282#endif
15283#if defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE) \
15284 || defined(PCR) || defined(CYGWIN32)
15285STATIC void GC_remove_tmp_roots(void)
15286{
15287 int i;
15288#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
15289 int old_n_roots = n_root_sets;
15290#endif
15291 for (i = 0; i < n_root_sets; ) {
15292 if (GC_static_roots[i].r_tmp) {
15293 GC_remove_root_at_pos(i);
15294 } else {
15295 i++;
15296 }
15297 }
15298#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
15299 if (n_root_sets < old_n_roots)
15300 GC_rebuild_root_index();
15301#endif
15302}
15303#endif
15304#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
15305 STATIC void GC_remove_roots_inner(ptr_t b, ptr_t e);
15306 GC_API void GC_CALL GC_remove_roots(void *b, void *e)
15307 {
15308 DCL_LOCK_STATE;
15309 if ((((word)b + (sizeof(word) - 1)) & ~(word)(sizeof(word) - 1)) >=
15310 ((word)e & ~(word)(sizeof(word) - 1)))
15311 return;
15312 LOCK();
15313 GC_remove_roots_inner((ptr_t)b, (ptr_t)e);
15314 UNLOCK();
15315 }
15316 STATIC void GC_remove_roots_inner(ptr_t b, ptr_t e)
15317 {
15318 int i;
15319 GC_bool rebuild = FALSE;
15320 for (i = 0; i < n_root_sets; ) {
15321 if ((word)GC_static_roots[i].r_start >= (word)b
15322 && (word)GC_static_roots[i].r_end <= (word)e) {
15323 GC_remove_root_at_pos(i);
15324 rebuild = TRUE;
15325 } else {
15326 i++;
15327 }
15328 }
15329 if (rebuild)
15330 GC_rebuild_root_index();
15331 }
15332#endif
15333#ifdef USE_PROC_FOR_LIBRARIES
15334 GC_INLINE void swap_static_roots(int i, int j)
15335 {
15336 ptr_t r_start = GC_static_roots[i].r_start;
15337 ptr_t r_end = GC_static_roots[i].r_end;
15338 GC_bool r_tmp = GC_static_roots[i].r_tmp;
15339 GC_static_roots[i].r_start = GC_static_roots[j].r_start;
15340 GC_static_roots[i].r_end = GC_static_roots[j].r_end;
15341 GC_static_roots[i].r_tmp = GC_static_roots[j].r_tmp;
15342 GC_static_roots[j].r_start = r_start;
15343 GC_static_roots[j].r_end = r_end;
15344 GC_static_roots[j].r_tmp = r_tmp;
15345 }
15346 GC_INNER void GC_remove_roots_subregion(ptr_t b, ptr_t e)
15347 {
15348 int i;
15349 GC_bool rebuild = FALSE;
15350 GC_ASSERT(I_HOLD_LOCK());
15351 GC_ASSERT((word)b % sizeof(word) == 0 && (word)e % sizeof(word) == 0);
15352 for (i = 0; i < n_root_sets; i++) {
15353 ptr_t r_start, r_end;
15354 if (GC_static_roots[i].r_tmp) {
15355#ifdef GC_ASSERTIONS
15356 int j;
15357 for (j = i + 1; j < n_root_sets; j++) {
15358 GC_ASSERT(GC_static_roots[j].r_tmp);
15359 }
15360#endif
15361 break;
15362 }
15363 r_start = GC_static_roots[i].r_start;
15364 r_end = GC_static_roots[i].r_end;
15365 if (!EXPECT((word)e <= (word)r_start || (word)r_end <= (word)b, TRUE)) {
15366#ifdef DEBUG_ADD_DEL_ROOTS
15367 GC_log_printf("Removing %p .. %p from root section %d (%p .. %p)\n",
15368 (void *)b, (void *)e,
15369 i, (void *)r_start, (void *)r_end);
15370#endif
15371 if ((word)r_start < (word)b) {
15372 GC_root_size -= r_end - b;
15373 GC_static_roots[i].r_end = b;
15374 if ((word)e < (word)r_end) {
15375 int j;
15376 if (rebuild) {
15377 GC_rebuild_root_index();
15378 rebuild = FALSE;
15379 }
15380 GC_add_roots_inner(e, r_end, FALSE);
15381 for (j = i + 1; j < n_root_sets; j++)
15382 if (GC_static_roots[j].r_tmp)
15383 break;
15384 if (j < n_root_sets-1 && !GC_static_roots[n_root_sets-1].r_tmp) {
15385 swap_static_roots(j, n_root_sets - 1);
15386 rebuild = TRUE;
15387 }
15388 }
15389 } else {
15390 if ((word)e < (word)r_end) {
15391 GC_root_size -= e - r_start;
15392 GC_static_roots[i].r_start = e;
15393 } else {
15394 GC_remove_root_at_pos(i);
15395 if (i < n_root_sets - 1 && GC_static_roots[i].r_tmp
15396 && !GC_static_roots[i + 1].r_tmp) {
15397 int j;
15398 for (j = i + 2; j < n_root_sets; j++)
15399 if (GC_static_roots[j].r_tmp)
15400 break;
15401 swap_static_roots(i, j - 1);
15402 }
15403 i--;
15404 }
15405 rebuild = TRUE;
15406 }
15407 }
15408 }
15409 if (rebuild)
15410 GC_rebuild_root_index();
15411 }
15412#endif
15413#if !defined(NO_DEBUGGING)
15414 GC_API int GC_CALL GC_is_tmp_root(void *p)
15415 {
15416 static int last_root_set = MAX_ROOT_SETS;
15417 int i;
15418 if (last_root_set < n_root_sets
15419 && (word)p >= (word)GC_static_roots[last_root_set].r_start
15420 && (word)p < (word)GC_static_roots[last_root_set].r_end)
15421 return GC_static_roots[last_root_set].r_tmp;
15422 for (i = 0; i < n_root_sets; i++) {
15423 if ((word)p >= (word)GC_static_roots[i].r_start
15424 && (word)p < (word)GC_static_roots[i].r_end) {
15425 last_root_set = i;
15426 return GC_static_roots[i].r_tmp;
15427 }
15428 }
15429 return(FALSE);
15430 }
15431#endif
15432GC_INNER ptr_t GC_approx_sp(void)
15433{
15434 volatile word sp;
15435#if defined(S390) && !defined(CPPCHECK) && (__clang_major__ < 8)
15436 sp = (word)&sp;
15437#elif defined(CPPCHECK) || (__GNUC__ >= 4 \
15438 && !defined(STACK_NOT_SCANNED))
15439 sp = (word)__builtin_frame_address(0);
15440#else
15441 sp = (word)&sp;
15442#endif
15443 return((ptr_t)sp);
15444}
15445GC_API void GC_CALL GC_clear_exclusion_table(void)
15446{
15447 GC_excl_table_entries = 0;
15448}
15449STATIC struct exclusion * GC_next_exclusion(ptr_t start_addr)
15450{
15451 size_t low = 0;
15452 size_t high;
15453 GC_ASSERT(GC_excl_table_entries > 0);
15454 high = GC_excl_table_entries - 1;
15455 while (high > low) {
15456 size_t mid = (low + high) >> 1;
15457 if ((word) GC_excl_table[mid].e_end <= (word) start_addr) {
15458 low = mid + 1;
15459 } else {
15460 high = mid;
15461 }
15462 }
15463 if ((word) GC_excl_table[low].e_end <= (word) start_addr) return 0;
15464 return GC_excl_table + low;
15465}
15466GC_INNER void GC_exclude_static_roots_inner(void *start, void *finish)
15467{
15468 struct exclusion * next;
15469 size_t next_index;
15470 GC_ASSERT((word)start % sizeof(word) == 0);
15471 GC_ASSERT((word)start < (word)finish);
15472 if (0 == GC_excl_table_entries) {
15473 next = 0;
15474 } else {
15475 next = GC_next_exclusion((ptr_t)start);
15476 }
15477 if (0 != next) {
15478 size_t i;
15479 if ((word)(next -> e_start) < (word) finish) {
15480 ABORT("Exclusion ranges overlap");
15481 }
15482 if ((word)(next -> e_start) == (word) finish) {
15483 next -> e_start = (ptr_t)start;
15484 return;
15485 }
15486 next_index = next - GC_excl_table;
15487 for (i = GC_excl_table_entries; i > next_index; --i) {
15488 GC_excl_table[i] = GC_excl_table[i-1];
15489 }
15490 } else {
15491 next_index = GC_excl_table_entries;
15492 }
15493 if (GC_excl_table_entries == MAX_EXCLUSIONS) ABORT("Too many exclusions");
15494 GC_excl_table[next_index].e_start = (ptr_t)start;
15495 GC_excl_table[next_index].e_end = (ptr_t)finish;
15496 ++GC_excl_table_entries;
15497}
15498GC_API void GC_CALL GC_exclude_static_roots(void *b, void *e)
15499{
15500 DCL_LOCK_STATE;
15501 if (b == e) return;
15502 b = (void *)((word)b & ~(word)(sizeof(word) - 1));
15503 e = (void *)(((word)e + (sizeof(word) - 1)) & ~(word)(sizeof(word) - 1));
15504 if (NULL == e)
15505 e = (void *)(~(word)(sizeof(word) - 1));
15506 LOCK();
15507 GC_exclude_static_roots_inner(b, e);
15508 UNLOCK();
15509}
15510#if defined(WRAP_MARK_SOME) && defined(PARALLEL_MARK)
15511#define GC_PUSH_CONDITIONAL(b, t, all) \
15512 (GC_parallel \
15513 ? GC_push_conditional_eager(b, t, all) \
15514 : GC_push_conditional_static(b, t, all))
15515#else
15516#define GC_PUSH_CONDITIONAL(b, t, all) GC_push_conditional_static(b, t, all)
15517#endif
15518STATIC void GC_push_conditional_with_exclusions(ptr_t bottom, ptr_t top,
15519 GC_bool all)
15520{
15521 while ((word)bottom < (word)top) {
15522 struct exclusion *next = GC_next_exclusion(bottom);
15523 ptr_t excl_start;
15524 if (0 == next
15525 || (word)(excl_start = next -> e_start) >= (word)top) {
15526 GC_PUSH_CONDITIONAL(bottom, top, all);
15527 break;
15528 }
15529 if ((word)excl_start > (word)bottom)
15530 GC_PUSH_CONDITIONAL(bottom, excl_start, all);
15531 bottom = next -> e_end;
15532 }
15533}
15534#ifdef IA64
15535 GC_INNER void GC_push_all_register_sections(ptr_t bs_lo, ptr_t bs_hi,
15536 int eager, struct GC_traced_stack_sect_s *traced_stack_sect)
15537 {
15538 while (traced_stack_sect != NULL) {
15539 ptr_t frame_bs_lo = traced_stack_sect -> backing_store_end;
15540 GC_ASSERT((word)frame_bs_lo <= (word)bs_hi);
15541 if (eager) {
15542 GC_push_all_eager(frame_bs_lo, bs_hi);
15543 } else {
15544 GC_push_all_stack(frame_bs_lo, bs_hi);
15545 }
15546 bs_hi = traced_stack_sect -> saved_backing_store_ptr;
15547 traced_stack_sect = traced_stack_sect -> prev;
15548 }
15549 GC_ASSERT((word)bs_lo <= (word)bs_hi);
15550 if (eager) {
15551 GC_push_all_eager(bs_lo, bs_hi);
15552 } else {
15553 GC_push_all_stack(bs_lo, bs_hi);
15554 }
15555 }
15556#endif
15557#ifdef THREADS
15558GC_INNER void GC_push_all_stack_sections(ptr_t lo, ptr_t hi,
15559 struct GC_traced_stack_sect_s *traced_stack_sect)
15560{
15561 while (traced_stack_sect != NULL) {
15562 GC_ASSERT((word)lo HOTTER_THAN (word)traced_stack_sect);
15563#ifdef STACK_GROWS_UP
15564 GC_push_all_stack((ptr_t)traced_stack_sect, lo);
15565#else
15566 GC_push_all_stack(lo, (ptr_t)traced_stack_sect);
15567#endif
15568 lo = traced_stack_sect -> saved_stack_ptr;
15569 GC_ASSERT(lo != NULL);
15570 traced_stack_sect = traced_stack_sect -> prev;
15571 }
15572 GC_ASSERT(!((word)hi HOTTER_THAN (word)lo));
15573#ifdef STACK_GROWS_UP
15574 GC_push_all_stack(hi, lo);
15575#else
15576 GC_push_all_stack(lo, hi);
15577#endif
15578}
15579#else
15580STATIC void GC_push_all_stack_partially_eager(ptr_t bottom, ptr_t top,
15581 ptr_t cold_gc_frame)
15582{
15583#ifndef NEED_FIXUP_POINTER
15584 if (GC_all_interior_pointers) {
15585 if (0 == cold_gc_frame) {
15586 GC_push_all_stack(bottom, top);
15587 return;
15588 }
15589 GC_ASSERT((word)bottom <= (word)cold_gc_frame
15590 && (word)cold_gc_frame <= (word)top);
15591#ifdef STACK_GROWS_DOWN
15592 GC_push_all(cold_gc_frame - sizeof(ptr_t), top);
15593 GC_push_all_eager(bottom, cold_gc_frame);
15594#else
15595 GC_push_all(bottom, cold_gc_frame + sizeof(ptr_t));
15596 GC_push_all_eager(cold_gc_frame, top);
15597#endif
15598 } else
15599#endif
15600 {
15601 GC_push_all_eager(bottom, top);
15602 }
15603#ifdef TRACE_BUF
15604 GC_add_trace_entry("GC_push_all_stack", (word)bottom, (word)top);
15605#endif
15606}
15607STATIC void GC_push_all_stack_part_eager_sections(ptr_t lo, ptr_t hi,
15608 ptr_t cold_gc_frame, struct GC_traced_stack_sect_s *traced_stack_sect)
15609{
15610 GC_ASSERT(traced_stack_sect == NULL || cold_gc_frame == NULL ||
15611 (word)cold_gc_frame HOTTER_THAN (word)traced_stack_sect);
15612 while (traced_stack_sect != NULL) {
15613 GC_ASSERT((word)lo HOTTER_THAN (word)traced_stack_sect);
15614#ifdef STACK_GROWS_UP
15615 GC_push_all_stack_partially_eager((ptr_t)traced_stack_sect, lo,
15616 cold_gc_frame);
15617#else
15618 GC_push_all_stack_partially_eager(lo, (ptr_t)traced_stack_sect,
15619 cold_gc_frame);
15620#endif
15621 lo = traced_stack_sect -> saved_stack_ptr;
15622 GC_ASSERT(lo != NULL);
15623 traced_stack_sect = traced_stack_sect -> prev;
15624 cold_gc_frame = NULL;
15625 }
15626 GC_ASSERT(!((word)hi HOTTER_THAN (word)lo));
15627#ifdef STACK_GROWS_UP
15628 GC_push_all_stack_partially_eager(hi, lo, cold_gc_frame);
15629#else
15630 GC_push_all_stack_partially_eager(lo, hi, cold_gc_frame);
15631#endif
15632}
15633#endif
15634STATIC void GC_push_current_stack(ptr_t cold_gc_frame,
15635 void * context GC_ATTR_UNUSED)
15636{
15637#if defined(THREADS)
15638#ifdef STACK_GROWS_DOWN
15639 GC_push_all_eager(GC_approx_sp(), cold_gc_frame);
15640#else
15641 GC_push_all_eager(cold_gc_frame, GC_approx_sp());
15642#endif
15643#else
15644 GC_push_all_stack_part_eager_sections(GC_approx_sp(), GC_stackbottom,
15645 cold_gc_frame, GC_traced_stack_sect);
15646#ifdef IA64
15647 {
15648 ptr_t bsp = GC_save_regs_ret_val;
15649 ptr_t cold_gc_bs_pointer = bsp - 2048;
15650 if (GC_all_interior_pointers
15651 && (word)cold_gc_bs_pointer > (word)BACKING_STORE_BASE) {
15652 if (GC_traced_stack_sect != NULL
15653 && (word)cold_gc_bs_pointer
15654 < (word)GC_traced_stack_sect->backing_store_end)
15655 cold_gc_bs_pointer =
15656 GC_traced_stack_sect->backing_store_end;
15657 GC_push_all_register_sections(BACKING_STORE_BASE,
15658 cold_gc_bs_pointer, FALSE, GC_traced_stack_sect);
15659 GC_push_all_eager(cold_gc_bs_pointer, bsp);
15660 } else {
15661 GC_push_all_register_sections(BACKING_STORE_BASE, bsp,
15662 TRUE , GC_traced_stack_sect);
15663 }
15664 }
15665#endif
15666#endif
15667}
15668GC_INNER void (*GC_push_typed_structures)(void) = 0;
15669GC_INNER void GC_cond_register_dynamic_libraries(void)
15670{
15671#if (defined(DYNAMIC_LOADING) && !defined(MSWIN_XBOX1)) \
15672 || defined(CYGWIN32) || defined(MSWIN32) || defined(MSWINCE) \
15673 || defined(PCR)
15674 GC_remove_tmp_roots();
15675 if (!GC_no_dls) GC_register_dynamic_libraries();
15676#else
15677 GC_no_dls = TRUE;
15678#endif
15679}
15680STATIC void GC_push_regs_and_stack(ptr_t cold_gc_frame)
15681{
15682#ifdef THREADS
15683 if (NULL == cold_gc_frame)
15684 return;
15685#endif
15686 GC_with_callee_saves_pushed(GC_push_current_stack, cold_gc_frame);
15687}
15688GC_INNER void GC_push_roots(GC_bool all, ptr_t cold_gc_frame GC_ATTR_UNUSED)
15689{
15690 int i;
15691 unsigned kind;
15692#if !defined(REGISTER_LIBRARIES_EARLY)
15693 GC_cond_register_dynamic_libraries();
15694#endif
15695 for (i = 0; i < n_root_sets; i++) {
15696 GC_push_conditional_with_exclusions(
15697 GC_static_roots[i].r_start,
15698 GC_static_roots[i].r_end, all);
15699 }
15700 for (kind = 0; kind < GC_n_kinds; kind++) {
15701 void *base = GC_base(GC_obj_kinds[kind].ok_freelist);
15702 if (base != NULL) {
15703 GC_set_mark_bit(base);
15704 }
15705 }
15706#ifndef GC_NO_FINALIZATION
15707 GC_push_finalizer_structures();
15708#endif
15709#ifdef THREADS
15710 if (GC_no_dls || GC_roots_were_cleared)
15711 GC_push_thread_structures();
15712#endif
15713 if (GC_push_typed_structures)
15714 GC_push_typed_structures();
15715#if defined(THREAD_LOCAL_ALLOC)
15716 if (GC_world_stopped)
15717 GC_mark_thread_local_free_lists();
15718#endif
15719#ifndef STACK_NOT_SCANNED
15720 GC_push_regs_and_stack(cold_gc_frame);
15721#endif
15722 if (GC_push_other_roots != 0) {
15723 (*GC_push_other_roots)();
15724 }
15725}
15726#ifdef ENABLE_DISCLAIM
15727#endif
15728#include <stdio.h>
15729GC_INNER signed_word GC_bytes_found = 0;
15730#if defined(PARALLEL_MARK)
15731 GC_INNER signed_word GC_fl_builder_count = 0;
15732#endif
15733#ifndef MAX_LEAKED
15734#define MAX_LEAKED 40
15735#endif
15736STATIC ptr_t GC_leaked[MAX_LEAKED] = { NULL };
15737STATIC unsigned GC_n_leaked = 0;
15738GC_INNER GC_bool GC_have_errors = FALSE;
15739#if !defined(EAGER_SWEEP) && defined(ENABLE_DISCLAIM)
15740 STATIC void GC_reclaim_unconditionally_marked(void);
15741#endif
15742GC_INLINE void GC_add_leaked(ptr_t leaked)
15743{
15744#ifndef SHORT_DBG_HDRS
15745 if (GC_findleak_delay_free && !GC_check_leaked(leaked))
15746 return;
15747#endif
15748 GC_have_errors = TRUE;
15749 if (GC_n_leaked < MAX_LEAKED) {
15750 GC_leaked[GC_n_leaked++] = leaked;
15751 GC_set_mark_bit(leaked);
15752 }
15753}
15754GC_INNER void GC_print_all_errors(void)
15755{
15756 static GC_bool printing_errors = FALSE;
15757 GC_bool have_errors;
15758 unsigned i, n_leaked;
15759 ptr_t leaked[MAX_LEAKED];
15760 DCL_LOCK_STATE;
15761 LOCK();
15762 if (printing_errors) {
15763 UNLOCK();
15764 return;
15765 }
15766 have_errors = GC_have_errors;
15767 printing_errors = TRUE;
15768 n_leaked = GC_n_leaked;
15769 if (n_leaked > 0) {
15770 GC_ASSERT(n_leaked <= MAX_LEAKED);
15771 BCOPY(GC_leaked, leaked, n_leaked * sizeof(ptr_t));
15772 GC_n_leaked = 0;
15773 BZERO(GC_leaked, n_leaked * sizeof(ptr_t));
15774 }
15775 UNLOCK();
15776 if (GC_debugging_started) {
15777 GC_print_all_smashed();
15778 } else {
15779 have_errors = FALSE;
15780 }
15781 if (n_leaked > 0) {
15782 GC_err_printf("Found %u leaked objects:\n", n_leaked);
15783 have_errors = TRUE;
15784 }
15785 for (i = 0; i < n_leaked; i++) {
15786 ptr_t p = leaked[i];
15787#ifndef SKIP_LEAKED_OBJECTS_PRINTING
15788 GC_print_heap_obj(p);
15789#endif
15790 GC_free(p);
15791 }
15792 if (have_errors
15793#ifndef GC_ABORT_ON_LEAK
15794 && GETENV("GC_ABORT_ON_LEAK") != NULL
15795#endif
15796 ) {
15797 ABORT("Leaked or smashed objects encountered");
15798 }
15799 LOCK();
15800 printing_errors = FALSE;
15801 UNLOCK();
15802}
15803GC_INNER GC_bool GC_block_empty(hdr *hhdr)
15804{
15805 return (hhdr -> hb_n_marks == 0);
15806}
15807STATIC GC_bool GC_block_nearly_full(hdr *hhdr, word sz)
15808{
15809 return hhdr -> hb_n_marks > HBLK_OBJS(sz) * 7 / 8;
15810}
15811GC_INLINE word *GC_clear_block(word *p, word sz, signed_word *count)
15812{
15813 word *q = (word *)((ptr_t)p + sz);
15814#ifdef USE_MARK_BYTES
15815 GC_ASSERT((sz & 1) == 0);
15816 GC_ASSERT(((word)p & (2 * sizeof(word) - 1)) == 0);
15817 p[1] = 0;
15818 p += 2;
15819 while ((word)p < (word)q) {
15820 CLEAR_DOUBLE(p);
15821 p += 2;
15822 }
15823#else
15824 p++;
15825 while ((word)p < (word)q) {
15826 *p++ = 0;
15827 }
15828#endif
15829 *count += sz;
15830 return p;
15831}
15832STATIC ptr_t GC_reclaim_clear(struct hblk *hbp, hdr *hhdr, word sz,
15833 ptr_t list, signed_word *count)
15834{
15835 word bit_no = 0;
15836 ptr_t p, plim;
15837 GC_ASSERT(hhdr == GC_find_header((ptr_t)hbp));
15838#ifndef THREADS
15839 GC_ASSERT(sz == hhdr -> hb_sz);
15840#else
15841#endif
15842 GC_ASSERT((sz & (BYTES_PER_WORD-1)) == 0);
15843 p = hbp->hb_body;
15844 plim = p + HBLKSIZE - sz;
15845 while ((word)p <= (word)plim) {
15846 if (mark_bit_from_hdr(hhdr, bit_no)) {
15847 p += sz;
15848 } else {
15849 obj_link(p) = list;
15850 list = p;
15851 p = (ptr_t)GC_clear_block((word *)p, sz, count);
15852 }
15853 bit_no += MARK_BIT_OFFSET(sz);
15854 }
15855 return list;
15856}
15857STATIC ptr_t GC_reclaim_uninit(struct hblk *hbp, hdr *hhdr, word sz,
15858 ptr_t list, signed_word *count)
15859{
15860 word bit_no = 0;
15861 word *p, *plim;
15862 signed_word n_bytes_found = 0;
15863#ifndef THREADS
15864 GC_ASSERT(sz == hhdr -> hb_sz);
15865#endif
15866 p = (word *)(hbp->hb_body);
15867 plim = (word *)((ptr_t)hbp + HBLKSIZE - sz);
15868 while ((word)p <= (word)plim) {
15869 if (!mark_bit_from_hdr(hhdr, bit_no)) {
15870 n_bytes_found += sz;
15871 obj_link(p) = list;
15872 list = ((ptr_t)p);
15873 }
15874 p = (word *)((ptr_t)p + sz);
15875 bit_no += MARK_BIT_OFFSET(sz);
15876 }
15877 *count += n_bytes_found;
15878 return(list);
15879}
15880#ifdef ENABLE_DISCLAIM
15881 STATIC ptr_t GC_disclaim_and_reclaim(struct hblk *hbp, hdr *hhdr, word sz,
15882 ptr_t list, signed_word *count)
15883 {
15884 word bit_no = 0;
15885 ptr_t p, plim;
15886 struct obj_kind *ok = &GC_obj_kinds[hhdr->hb_obj_kind];
15887 int (GC_CALLBACK *disclaim)(void *) = ok->ok_disclaim_proc;
15888#ifndef THREADS
15889 GC_ASSERT(sz == hhdr -> hb_sz);
15890#endif
15891 p = hbp->hb_body;
15892 plim = p + HBLKSIZE - sz;
15893 for (; (word)p <= (word)plim; bit_no += MARK_BIT_OFFSET(sz)) {
15894 if (mark_bit_from_hdr(hhdr, bit_no)) {
15895 p += sz;
15896 } else if ((*disclaim)(p)) {
15897 set_mark_bit_from_hdr(hhdr, bit_no);
15898 hhdr -> hb_n_marks++;
15899 p += sz;
15900 } else {
15901 obj_link(p) = list;
15902 list = p;
15903 p = (ptr_t)GC_clear_block((word *)p, sz, count);
15904 }
15905 }
15906 return list;
15907 }
15908#endif
15909STATIC void GC_reclaim_check(struct hblk *hbp, hdr *hhdr, word sz)
15910{
15911 word bit_no;
15912 ptr_t p, plim;
15913#ifndef THREADS
15914 GC_ASSERT(sz == hhdr -> hb_sz);
15915#endif
15916 p = hbp->hb_body;
15917 plim = p + HBLKSIZE - sz;
15918 for (bit_no = 0; (word)p <= (word)plim;
15919 p += sz, bit_no += MARK_BIT_OFFSET(sz)) {
15920 if (!mark_bit_from_hdr(hhdr, bit_no)) {
15921 GC_add_leaked(p);
15922 }
15923 }
15924}
15925#ifdef AO_HAVE_load
15926#define IS_PTRFREE_SAFE(hhdr) \
15927 (AO_load((volatile AO_t *)&(hhdr)->hb_descr) == 0)
15928#else
15929#define IS_PTRFREE_SAFE(hhdr) ((hhdr)->hb_descr == 0)
15930#endif
15931GC_INNER ptr_t GC_reclaim_generic(struct hblk * hbp, hdr *hhdr, size_t sz,
15932 GC_bool init, ptr_t list,
15933 signed_word *count)
15934{
15935 ptr_t result;
15936 GC_ASSERT(GC_find_header((ptr_t)hbp) == hhdr);
15937#ifndef GC_DISABLE_INCREMENTAL
15938 GC_remove_protection(hbp, 1, IS_PTRFREE_SAFE(hhdr));
15939#endif
15940#ifdef ENABLE_DISCLAIM
15941 if ((hhdr -> hb_flags & HAS_DISCLAIM) != 0) {
15942 result = GC_disclaim_and_reclaim(hbp, hhdr, sz, list, count);
15943 } else
15944#endif
15945 if (init || GC_debugging_started) {
15946 result = GC_reclaim_clear(hbp, hhdr, sz, list, count);
15947 } else {
15948 GC_ASSERT(IS_PTRFREE_SAFE(hhdr));
15949 result = GC_reclaim_uninit(hbp, hhdr, sz, list, count);
15950 }
15951 if (IS_UNCOLLECTABLE(hhdr -> hb_obj_kind)) GC_set_hdr_marks(hhdr);
15952 return result;
15953}
15954STATIC void GC_reclaim_small_nonempty_block(struct hblk *hbp, word sz,
15955 GC_bool report_if_found)
15956{
15957 hdr *hhdr = HDR(hbp);
15958 struct obj_kind * ok = &GC_obj_kinds[hhdr -> hb_obj_kind];
15959 void **flh = &(ok -> ok_freelist[BYTES_TO_GRANULES(sz)]);
15960 hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no;
15961 if (report_if_found) {
15962 GC_reclaim_check(hbp, hhdr, sz);
15963 } else {
15964 *flh = GC_reclaim_generic(hbp, hhdr, sz, ok -> ok_init,
15965 (ptr_t)(*flh), &GC_bytes_found);
15966 }
15967}
15968#ifdef ENABLE_DISCLAIM
15969 STATIC void GC_disclaim_and_reclaim_or_free_small_block(struct hblk *hbp)
15970 {
15971 hdr *hhdr = HDR(hbp);
15972 word sz = hhdr -> hb_sz;
15973 struct obj_kind * ok = &GC_obj_kinds[hhdr -> hb_obj_kind];
15974 void **flh = &(ok -> ok_freelist[BYTES_TO_GRANULES(sz)]);
15975 void *flh_next;
15976 hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no;
15977 flh_next = GC_reclaim_generic(hbp, hhdr, sz, ok -> ok_init,
15978 (ptr_t)(*flh), &GC_bytes_found);
15979 if (hhdr -> hb_n_marks)
15980 *flh = flh_next;
15981 else {
15982 GC_bytes_found += HBLKSIZE;
15983 GC_freehblk(hbp);
15984 }
15985 }
15986#endif
15987STATIC void GC_reclaim_block(struct hblk *hbp, word report_if_found)
15988{
15989 hdr * hhdr = HDR(hbp);
15990 word sz;
15991 struct obj_kind * ok = &GC_obj_kinds[hhdr -> hb_obj_kind];
15992#ifdef AO_HAVE_load
15993 sz = (word)AO_load((volatile AO_t *)&hhdr->hb_sz);
15994#else
15995 sz = hhdr -> hb_sz;
15996#endif
15997 if( sz > MAXOBJBYTES ) {
15998 if( !mark_bit_from_hdr(hhdr, 0) ) {
15999 if (report_if_found) {
16000 GC_add_leaked((ptr_t)hbp);
16001 } else {
16002 word blocks;
16003#ifdef ENABLE_DISCLAIM
16004 if (EXPECT(hhdr->hb_flags & HAS_DISCLAIM, 0)) {
16005 if ((*ok->ok_disclaim_proc)(hbp)) {
16006 set_mark_bit_from_hdr(hhdr, 0);
16007 goto in_use;
16008 }
16009 }
16010#endif
16011 blocks = OBJ_SZ_TO_BLOCKS(sz);
16012#if defined(CPPCHECK)
16013 GC_noop1((word)&blocks);
16014#endif
16015 if (blocks > 1) {
16016 GC_large_allocd_bytes -= blocks * HBLKSIZE;
16017 }
16018 GC_bytes_found += sz;
16019 GC_freehblk(hbp);
16020 }
16021 } else {
16022#ifdef ENABLE_DISCLAIM
16023 in_use:
16024#endif
16025 if (IS_PTRFREE_SAFE(hhdr)) {
16026 GC_atomic_in_use += sz;
16027 } else {
16028 GC_composite_in_use += sz;
16029 }
16030 }
16031 } else {
16032 GC_bool empty = GC_block_empty(hhdr);
16033#ifdef PARALLEL_MARK
16034 GC_ASSERT(hhdr -> hb_n_marks <= 2 * (HBLKSIZE/sz + 1) + 16);
16035#else
16036 GC_ASSERT(sz * hhdr -> hb_n_marks <= HBLKSIZE);
16037#endif
16038 if (report_if_found) {
16039 GC_reclaim_small_nonempty_block(hbp, sz,
16040 TRUE );
16041 } else if (empty) {
16042#ifdef ENABLE_DISCLAIM
16043 if ((hhdr -> hb_flags & HAS_DISCLAIM) != 0) {
16044 GC_disclaim_and_reclaim_or_free_small_block(hbp);
16045 } else
16046#endif
16047 {
16048 GC_bytes_found += HBLKSIZE;
16049 GC_freehblk(hbp);
16050 }
16051 } else if (GC_find_leak || !GC_block_nearly_full(hhdr, sz)) {
16052 struct hblk **rlh = ok -> ok_reclaim_list;
16053 if (rlh != NULL) {
16054 rlh += BYTES_TO_GRANULES(sz);
16055 hhdr -> hb_next = *rlh;
16056 *rlh = hbp;
16057 }
16058 }
16059 if (IS_PTRFREE_SAFE(hhdr)) {
16060 GC_atomic_in_use += sz * hhdr -> hb_n_marks;
16061 } else {
16062 GC_composite_in_use += sz * hhdr -> hb_n_marks;
16063 }
16064 }
16065}
16066#if !defined(NO_DEBUGGING)
16067struct Print_stats
16068{
16069 size_t number_of_blocks;
16070 size_t total_bytes;
16071};
16072#ifdef USE_MARK_BYTES
16073unsigned GC_n_set_marks(hdr *hhdr)
16074{
16075 unsigned result = 0;
16076 word i;
16077 word sz = hhdr -> hb_sz;
16078 word offset = MARK_BIT_OFFSET(sz);
16079 word limit = FINAL_MARK_BIT(sz);
16080 for (i = 0; i < limit; i += offset) {
16081 result += hhdr -> hb_marks[i];
16082 }
16083 GC_ASSERT(hhdr -> hb_marks[limit]);
16084 return(result);
16085}
16086#else
16087static unsigned set_bits(word n)
16088{
16089 word m = n;
16090 unsigned result = 0;
16091 while (m > 0) {
16092 if (m & 1) result++;
16093 m >>= 1;
16094 }
16095 return(result);
16096}
16097unsigned GC_n_set_marks(hdr *hhdr)
16098{
16099 unsigned result = 0;
16100 word i;
16101 word n_mark_words;
16102#ifdef MARK_BIT_PER_OBJ
16103 word n_objs = HBLK_OBJS(hhdr -> hb_sz);
16104 if (0 == n_objs) n_objs = 1;
16105 n_mark_words = divWORDSZ(n_objs + WORDSZ - 1);
16106#else
16107 n_mark_words = MARK_BITS_SZ;
16108#endif
16109 for (i = 0; i < n_mark_words - 1; i++) {
16110 result += set_bits(hhdr -> hb_marks[i]);
16111 }
16112#ifdef MARK_BIT_PER_OBJ
16113 result += set_bits((hhdr -> hb_marks[n_mark_words - 1])
16114 << (n_mark_words * WORDSZ - n_objs));
16115#else
16116 result += set_bits(hhdr -> hb_marks[n_mark_words - 1]);
16117#endif
16118 return result;
16119}
16120#endif
16121STATIC void GC_print_block_descr(struct hblk *h,
16122 word raw_ps)
16123{
16124 hdr * hhdr = HDR(h);
16125 size_t bytes = hhdr -> hb_sz;
16126 struct Print_stats *ps;
16127 unsigned n_marks = GC_n_set_marks(hhdr);
16128 unsigned n_objs = (unsigned)HBLK_OBJS(bytes);
16129 if (0 == n_objs) n_objs = 1;
16130 if (hhdr -> hb_n_marks != n_marks) {
16131 GC_printf("%u,%u,%u!=%u,%u\n", hhdr->hb_obj_kind, (unsigned)bytes,
16132 (unsigned)hhdr->hb_n_marks, n_marks, n_objs);
16133 } else {
16134 GC_printf("%u,%u,%u,%u\n", hhdr->hb_obj_kind, (unsigned)bytes,
16135 n_marks, n_objs);
16136 }
16137 ps = (struct Print_stats *)raw_ps;
16138 ps->total_bytes += (bytes + (HBLKSIZE-1)) & ~(HBLKSIZE-1);
16139 ps->number_of_blocks++;
16140}
16141void GC_print_block_list(void)
16142{
16143 struct Print_stats pstats;
16144 GC_printf("kind(0=ptrfree,1=normal,2=unc.),"
16145 "size_in_bytes,#_marks_set,#objs\n");
16146 pstats.number_of_blocks = 0;
16147 pstats.total_bytes = 0;
16148 GC_apply_to_all_blocks(GC_print_block_descr, (word)&pstats);
16149 GC_printf("blocks= %lu, bytes= %lu\n",
16150 (unsigned long)pstats.number_of_blocks,
16151 (unsigned long)pstats.total_bytes);
16152}
16153GC_API void GC_CALL GC_print_free_list(int kind, size_t sz_in_granules)
16154{
16155 void *flh_next;
16156 int n;
16157 GC_ASSERT(kind < MAXOBJKINDS);
16158 GC_ASSERT(sz_in_granules <= MAXOBJGRANULES);
16159 flh_next = GC_obj_kinds[kind].ok_freelist[sz_in_granules];
16160 for (n = 0; flh_next; n++) {
16161 GC_printf("Free object in heap block %p [%d]: %p\n",
16162 (void *)HBLKPTR(flh_next), n, flh_next);
16163 flh_next = obj_link(flh_next);
16164 }
16165}
16166#endif
16167STATIC void GC_clear_fl_links(void **flp)
16168{
16169 void *next = *flp;
16170 while (0 != next) {
16171 *flp = 0;
16172 flp = &(obj_link(next));
16173 next = *flp;
16174 }
16175}
16176GC_INNER void GC_start_reclaim(GC_bool report_if_found)
16177{
16178 unsigned kind;
16179#if defined(PARALLEL_MARK)
16180 GC_ASSERT(0 == GC_fl_builder_count);
16181#endif
16182 GC_composite_in_use = 0;
16183 GC_atomic_in_use = 0;
16184 for (kind = 0; kind < GC_n_kinds; kind++) {
16185 struct hblk ** rlist = GC_obj_kinds[kind].ok_reclaim_list;
16186 GC_bool should_clobber = (GC_obj_kinds[kind].ok_descriptor != 0);
16187 if (rlist == 0) continue;
16188 if (!report_if_found) {
16189 void **fop;
16190 void **lim = &(GC_obj_kinds[kind].ok_freelist[MAXOBJGRANULES+1]);
16191 for (fop = GC_obj_kinds[kind].ok_freelist;
16192 (word)fop < (word)lim; (*(word **)&fop)++) {
16193 if (*fop != 0) {
16194 if (should_clobber) {
16195 GC_clear_fl_links(fop);
16196 } else {
16197 *fop = 0;
16198 }
16199 }
16200 }
16201 }
16202 BZERO(rlist, (MAXOBJGRANULES + 1) * sizeof(void *));
16203 }
16204 GC_apply_to_all_blocks(GC_reclaim_block, (word)report_if_found);
16205#ifdef EAGER_SWEEP
16206 GC_reclaim_all((GC_stop_func)0, FALSE);
16207#elif defined(ENABLE_DISCLAIM)
16208 GC_reclaim_unconditionally_marked();
16209#endif
16210#if defined(PARALLEL_MARK)
16211 GC_ASSERT(0 == GC_fl_builder_count);
16212#endif
16213}
16214GC_INNER void GC_continue_reclaim(word sz , int kind)
16215{
16216 hdr * hhdr;
16217 struct hblk * hbp;
16218 struct obj_kind * ok = &(GC_obj_kinds[kind]);
16219 struct hblk ** rlh = ok -> ok_reclaim_list;
16220 void **flh = &(ok -> ok_freelist[sz]);
16221 if (NULL == rlh)
16222 return;
16223 for (rlh += sz; (hbp = *rlh) != NULL; ) {
16224 hhdr = HDR(hbp);
16225 *rlh = hhdr -> hb_next;
16226 GC_reclaim_small_nonempty_block(hbp, hhdr -> hb_sz, FALSE);
16227 if (*flh != 0)
16228 break;
16229 }
16230}
16231GC_INNER GC_bool GC_reclaim_all(GC_stop_func stop_func, GC_bool ignore_old)
16232{
16233 word sz;
16234 unsigned kind;
16235 hdr * hhdr;
16236 struct hblk * hbp;
16237 struct obj_kind * ok;
16238 struct hblk ** rlp;
16239 struct hblk ** rlh;
16240#ifndef NO_CLOCK
16241 CLOCK_TYPE start_time = CLOCK_TYPE_INITIALIZER;
16242 if (GC_print_stats == VERBOSE)
16243 GET_TIME(start_time);
16244#endif
16245 for (kind = 0; kind < GC_n_kinds; kind++) {
16246 ok = &(GC_obj_kinds[kind]);
16247 rlp = ok -> ok_reclaim_list;
16248 if (rlp == 0) continue;
16249 for (sz = 1; sz <= MAXOBJGRANULES; sz++) {
16250 for (rlh = rlp + sz; (hbp = *rlh) != NULL; ) {
16251 if (stop_func != (GC_stop_func)0 && (*stop_func)()) {
16252 return(FALSE);
16253 }
16254 hhdr = HDR(hbp);
16255 *rlh = hhdr -> hb_next;
16256 if (!ignore_old
16257 || (word)hhdr->hb_last_reclaimed == GC_gc_no - 1) {
16258 GC_reclaim_small_nonempty_block(hbp, hhdr->hb_sz, FALSE);
16259 }
16260 }
16261 }
16262 }
16263#ifndef NO_CLOCK
16264 if (GC_print_stats == VERBOSE) {
16265 CLOCK_TYPE done_time;
16266 GET_TIME(done_time);
16267 GC_verbose_log_printf(
16268 "Disposing of reclaim lists took %lu ms %lu ns\n",
16269 MS_TIME_DIFF(done_time, start_time),
16270 NS_FRAC_TIME_DIFF(done_time, start_time));
16271 }
16272#endif
16273 return(TRUE);
16274}
16275#if !defined(EAGER_SWEEP) && defined(ENABLE_DISCLAIM)
16276 STATIC void GC_reclaim_unconditionally_marked(void)
16277 {
16278 word sz;
16279 unsigned kind;
16280 hdr * hhdr;
16281 struct hblk * hbp;
16282 struct obj_kind * ok;
16283 struct hblk ** rlp;
16284 struct hblk ** rlh;
16285 for (kind = 0; kind < GC_n_kinds; kind++) {
16286 ok = &(GC_obj_kinds[kind]);
16287 if (!ok->ok_mark_unconditionally)
16288 continue;
16289 rlp = ok->ok_reclaim_list;
16290 if (rlp == 0)
16291 continue;
16292 for (sz = 1; sz <= MAXOBJGRANULES; sz++) {
16293 rlh = rlp + sz;
16294 while ((hbp = *rlh) != 0) {
16295 hhdr = HDR(hbp);
16296 *rlh = hhdr->hb_next;
16297 GC_reclaim_small_nonempty_block(hbp, hhdr->hb_sz, FALSE);
16298 }
16299 }
16300 }
16301 }
16302#endif
16303struct enumerate_reachable_s {
16304 GC_reachable_object_proc proc;
16305 void *client_data;
16306};
16307STATIC void GC_do_enumerate_reachable_objects(struct hblk *hbp, word ped)
16308{
16309 struct hblkhdr *hhdr = HDR(hbp);
16310 size_t sz = (size_t)hhdr->hb_sz;
16311 size_t bit_no;
16312 char *p, *plim;
16313 if (GC_block_empty(hhdr)) {
16314 return;
16315 }
16316 p = hbp->hb_body;
16317 if (sz > MAXOBJBYTES) {
16318 plim = p;
16319 } else {
16320 plim = hbp->hb_body + HBLKSIZE - sz;
16321 }
16322 for (bit_no = 0; p <= plim; bit_no += MARK_BIT_OFFSET(sz), p += sz) {
16323 if (mark_bit_from_hdr(hhdr, bit_no)) {
16324 ((struct enumerate_reachable_s *)ped)->proc(p, sz,
16325 ((struct enumerate_reachable_s *)ped)->client_data);
16326 }
16327 }
16328}
16329GC_API void GC_CALL GC_enumerate_reachable_objects_inner(
16330 GC_reachable_object_proc proc,
16331 void *client_data)
16332{
16333 struct enumerate_reachable_s ed;
16334 GC_ASSERT(I_HOLD_LOCK());
16335 ed.proc = proc;
16336 ed.client_data = client_data;
16337 GC_apply_to_all_blocks(GC_do_enumerate_reachable_objects, (word)&ed);
16338}
16339#ifndef GC_TYPED_H
16340#define GC_TYPED_H
16341#ifndef GC_H
16342#endif
16343#ifdef __cplusplus
16344 extern "C" {
16345#endif
16346typedef GC_word * GC_bitmap;
16347#define GC_WORDSZ (8 * sizeof(GC_word))
16348#define GC_get_bit(bm, index) \
16349 (((bm)[(index) / GC_WORDSZ] >> ((index) % GC_WORDSZ)) & 1)
16350#define GC_set_bit(bm, index) \
16351 ((bm)[(index) / GC_WORDSZ] |= (GC_word)1 << ((index) % GC_WORDSZ))
16352#define GC_WORD_OFFSET(t, f) (offsetof(t,f) / sizeof(GC_word))
16353#define GC_WORD_LEN(t) (sizeof(t) / sizeof(GC_word))
16354#define GC_BITMAP_SIZE(t) ((GC_WORD_LEN(t) + GC_WORDSZ - 1) / GC_WORDSZ)
16355typedef GC_word GC_descr;
16356GC_API GC_descr GC_CALL GC_make_descriptor(const GC_word * ,
16357 size_t );
16358GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
16359 GC_malloc_explicitly_typed(size_t ,
16360 GC_descr );
16361GC_API GC_ATTR_MALLOC GC_ATTR_ALLOC_SIZE(1) void * GC_CALL
16362 GC_malloc_explicitly_typed_ignore_off_page(size_t ,
16363 GC_descr );
16364GC_API GC_ATTR_MALLOC GC_ATTR_CALLOC_SIZE(1, 2) void * GC_CALL
16365 GC_calloc_explicitly_typed(size_t ,
16366 size_t ,
16367 GC_descr );
16368#ifdef GC_DEBUG
16369#define GC_MALLOC_EXPLICITLY_TYPED(bytes, d) ((void)(d), GC_MALLOC(bytes))
16370#define GC_CALLOC_EXPLICITLY_TYPED(n, bytes, d) \
16371 ((void)(d), GC_MALLOC((n) * (bytes)))
16372#else
16373#define GC_MALLOC_EXPLICITLY_TYPED(bytes, d) \
16374 GC_malloc_explicitly_typed(bytes, d)
16375#define GC_CALLOC_EXPLICITLY_TYPED(n, bytes, d) \
16376 GC_calloc_explicitly_typed(n, bytes, d)
16377#endif
16378#ifdef __cplusplus
16379 }
16380#endif
16381#endif
16382#define TYPD_EXTRA_BYTES (sizeof(word) - EXTRA_BYTES)
16383STATIC int GC_explicit_kind = 0;
16384STATIC int GC_array_kind = 0;
16385struct LeafDescriptor {
16386 word ld_tag;
16387#define LEAF_TAG 1
16388 size_t ld_size;
16389 size_t ld_nelements;
16390 GC_descr ld_descriptor;
16391};
16392struct ComplexArrayDescriptor {
16393 word ad_tag;
16394#define ARRAY_TAG 2
16395 size_t ad_nelements;
16396 union ComplexDescriptor * ad_element_descr;
16397};
16398struct SequenceDescriptor {
16399 word sd_tag;
16400#define SEQUENCE_TAG 3
16401 union ComplexDescriptor * sd_first;
16402 union ComplexDescriptor * sd_second;
16403};
16404typedef union ComplexDescriptor {
16405 struct LeafDescriptor ld;
16406 struct ComplexArrayDescriptor ad;
16407 struct SequenceDescriptor sd;
16408} complex_descriptor;
16409#define TAG ad.ad_tag
16410#define ED_INITIAL_SIZE 100
16411STATIC int GC_typed_mark_proc_index = 0;
16412STATIC int GC_array_mark_proc_index = 0;
16413STATIC void GC_push_typed_structures_proc(void)
16414{
16415 GC_PUSH_ALL_SYM(GC_ext_descriptors);
16416}
16417STATIC signed_word GC_add_ext_descriptor(const word * bm, word nbits)
16418{
16419 size_t nwords = divWORDSZ(nbits + WORDSZ-1);
16420 signed_word result;
16421 size_t i;
16422 word last_part;
16423 size_t extra_bits;
16424 DCL_LOCK_STATE;
16425 LOCK();
16426 while (GC_avail_descr + nwords >= GC_ed_size) {
16427 typed_ext_descr_t *newExtD;
16428 size_t new_size;
16429 word ed_size = GC_ed_size;
16430 if (ed_size == 0) {
16431 GC_ASSERT((word)(&GC_ext_descriptors) % sizeof(word) == 0);
16432 GC_push_typed_structures = GC_push_typed_structures_proc;
16433 UNLOCK();
16434 new_size = ED_INITIAL_SIZE;
16435 } else {
16436 UNLOCK();
16437 new_size = 2 * ed_size;
16438 if (new_size > MAX_ENV) return(-1);
16439 }
16440 newExtD = (typed_ext_descr_t*)GC_malloc_atomic(new_size
16441 * sizeof(typed_ext_descr_t));
16442 if (NULL == newExtD)
16443 return -1;
16444 LOCK();
16445 if (ed_size == GC_ed_size) {
16446 if (GC_avail_descr != 0) {
16447 BCOPY(GC_ext_descriptors, newExtD,
16448 GC_avail_descr * sizeof(typed_ext_descr_t));
16449 }
16450 GC_ed_size = new_size;
16451 GC_ext_descriptors = newExtD;
16452 }
16453 }
16454 result = GC_avail_descr;
16455 for (i = 0; i < nwords-1; i++) {
16456 GC_ext_descriptors[result + i].ed_bitmap = bm[i];
16457 GC_ext_descriptors[result + i].ed_continued = TRUE;
16458 }
16459 last_part = bm[i];
16460 extra_bits = nwords * WORDSZ - nbits;
16461 last_part <<= extra_bits;
16462 last_part >>= extra_bits;
16463 GC_ext_descriptors[result + i].ed_bitmap = last_part;
16464 GC_ext_descriptors[result + i].ed_continued = FALSE;
16465 GC_avail_descr += nwords;
16466 UNLOCK();
16467 return(result);
16468}
16469STATIC GC_descr GC_bm_table[WORDSZ/2];
16470STATIC GC_descr GC_double_descr(GC_descr descriptor, word nwords)
16471{
16472 if ((descriptor & GC_DS_TAGS) == GC_DS_LENGTH) {
16473 descriptor = GC_bm_table[BYTES_TO_WORDS((word)descriptor)];
16474 }
16475 descriptor |= (descriptor & ~GC_DS_TAGS) >> nwords;
16476 return(descriptor);
16477}
16478STATIC complex_descriptor *
16479GC_make_sequence_descriptor(complex_descriptor *first,
16480 complex_descriptor *second);
16481#define COMPLEX 2
16482#define LEAF 1
16483#define SIMPLE 0
16484#define NO_MEM (-1)
16485STATIC int GC_make_array_descriptor(size_t nelements, size_t size,
16486 GC_descr descriptor, GC_descr *simple_d,
16487 complex_descriptor **complex_d,
16488 struct LeafDescriptor * leaf)
16489{
16490#define OPT_THRESHOLD 50
16491 if ((descriptor & GC_DS_TAGS) == GC_DS_LENGTH) {
16492 if (descriptor == (GC_descr)size) {
16493 *simple_d = nelements * descriptor;
16494 return(SIMPLE);
16495 } else if ((word)descriptor == 0) {
16496 *simple_d = (GC_descr)0;
16497 return(SIMPLE);
16498 }
16499 }
16500 if (nelements <= OPT_THRESHOLD) {
16501 if (nelements <= 1) {
16502 if (nelements == 1) {
16503 *simple_d = descriptor;
16504 return(SIMPLE);
16505 } else {
16506 *simple_d = (GC_descr)0;
16507 return(SIMPLE);
16508 }
16509 }
16510 } else if (size <= BITMAP_BITS/2
16511 && (descriptor & GC_DS_TAGS) != GC_DS_PROC
16512 && (size & (sizeof(word)-1)) == 0) {
16513 int result =
16514 GC_make_array_descriptor(nelements/2, 2*size,
16515 GC_double_descr(descriptor,
16516 BYTES_TO_WORDS(size)),
16517 simple_d, complex_d, leaf);
16518 if ((nelements & 1) == 0) {
16519 return(result);
16520 } else {
16521 struct LeafDescriptor * one_element =
16522 (struct LeafDescriptor *)
16523 GC_malloc_atomic(sizeof(struct LeafDescriptor));
16524 if (result == NO_MEM || one_element == 0) return(NO_MEM);
16525 one_element -> ld_tag = LEAF_TAG;
16526 one_element -> ld_size = size;
16527 one_element -> ld_nelements = 1;
16528 one_element -> ld_descriptor = descriptor;
16529 switch(result) {
16530 case SIMPLE:
16531 {
16532 struct LeafDescriptor * beginning =
16533 (struct LeafDescriptor *)
16534 GC_malloc_atomic(sizeof(struct LeafDescriptor));
16535 if (beginning == 0) return(NO_MEM);
16536 beginning -> ld_tag = LEAF_TAG;
16537 beginning -> ld_size = size;
16538 beginning -> ld_nelements = 1;
16539 beginning -> ld_descriptor = *simple_d;
16540 *complex_d = GC_make_sequence_descriptor(
16541 (complex_descriptor *)beginning,
16542 (complex_descriptor *)one_element);
16543 break;
16544 }
16545 case LEAF:
16546 {
16547 struct LeafDescriptor * beginning =
16548 (struct LeafDescriptor *)
16549 GC_malloc_atomic(sizeof(struct LeafDescriptor));
16550 if (beginning == 0) return(NO_MEM);
16551 beginning -> ld_tag = LEAF_TAG;
16552 beginning -> ld_size = leaf -> ld_size;
16553 beginning -> ld_nelements = leaf -> ld_nelements;
16554 beginning -> ld_descriptor = leaf -> ld_descriptor;
16555 *complex_d = GC_make_sequence_descriptor(
16556 (complex_descriptor *)beginning,
16557 (complex_descriptor *)one_element);
16558 break;
16559 }
16560 case COMPLEX:
16561 *complex_d = GC_make_sequence_descriptor(
16562 *complex_d,
16563 (complex_descriptor *)one_element);
16564 break;
16565 }
16566 return(COMPLEX);
16567 }
16568 }
16569 leaf -> ld_size = size;
16570 leaf -> ld_nelements = nelements;
16571 leaf -> ld_descriptor = descriptor;
16572 return(LEAF);
16573}
16574STATIC complex_descriptor *
16575GC_make_sequence_descriptor(complex_descriptor *first,
16576 complex_descriptor *second)
16577{
16578 struct SequenceDescriptor * result =
16579 (struct SequenceDescriptor *)
16580 GC_malloc(sizeof(struct SequenceDescriptor));
16581 if (result != 0) {
16582 result -> sd_tag = SEQUENCE_TAG;
16583 result -> sd_first = first;
16584 result -> sd_second = second;
16585 GC_dirty(result);
16586 REACHABLE_AFTER_DIRTY(first);
16587 REACHABLE_AFTER_DIRTY(second);
16588 }
16589 return((complex_descriptor *)result);
16590}
16591STATIC mse * GC_typed_mark_proc(word * addr, mse * mark_stack_ptr,
16592 mse * mark_stack_limit, word env);
16593STATIC mse * GC_array_mark_proc(word * addr, mse * mark_stack_ptr,
16594 mse * mark_stack_limit, word env);
16595STATIC void GC_init_explicit_typing(void)
16596{
16597 unsigned i;
16598 GC_STATIC_ASSERT(sizeof(struct LeafDescriptor) % sizeof(word) == 0);
16599 GC_explicit_kind = GC_new_kind_inner(GC_new_free_list_inner(),
16600 (WORDS_TO_BYTES((word)-1) | GC_DS_PER_OBJECT),
16601 TRUE, TRUE);
16602 GC_typed_mark_proc_index = GC_new_proc_inner(GC_typed_mark_proc);
16603 GC_array_mark_proc_index = GC_new_proc_inner(GC_array_mark_proc);
16604 GC_array_kind = GC_new_kind_inner(GC_new_free_list_inner(),
16605 GC_MAKE_PROC(GC_array_mark_proc_index, 0),
16606 FALSE, TRUE);
16607 GC_bm_table[0] = GC_DS_BITMAP;
16608 for (i = 1; i < WORDSZ/2; i++) {
16609 GC_bm_table[i] = (((word)-1) << (WORDSZ - i)) | GC_DS_BITMAP;
16610 }
16611}
16612STATIC mse * GC_typed_mark_proc(word * addr, mse * mark_stack_ptr,
16613 mse * mark_stack_limit, word env)
16614{
16615 word bm = GC_ext_descriptors[env].ed_bitmap;
16616 word * current_p = addr;
16617 word current;
16618 ptr_t greatest_ha = (ptr_t)GC_greatest_plausible_heap_addr;
16619 ptr_t least_ha = (ptr_t)GC_least_plausible_heap_addr;
16620 DECLARE_HDR_CACHE;
16621 INIT_HDR_CACHE;
16622 for (; bm != 0; bm >>= 1, current_p++) {
16623 if (bm & 1) {
16624 current = *current_p;
16625 FIXUP_POINTER(current);
16626 if (current >= (word)least_ha && current <= (word)greatest_ha) {
16627 PUSH_CONTENTS((ptr_t)current, mark_stack_ptr,
16628 mark_stack_limit, (ptr_t)current_p);
16629 }
16630 }
16631 }
16632 if (GC_ext_descriptors[env].ed_continued) {
16633 mark_stack_ptr++;
16634 if ((word)mark_stack_ptr >= (word)mark_stack_limit) {
16635 mark_stack_ptr = GC_signal_mark_stack_overflow(mark_stack_ptr);
16636 }
16637 mark_stack_ptr -> mse_start = (ptr_t)(addr + WORDSZ);
16638 mark_stack_ptr -> mse_descr.w =
16639 GC_MAKE_PROC(GC_typed_mark_proc_index, env + 1);
16640 }
16641 return(mark_stack_ptr);
16642}
16643STATIC word GC_descr_obj_size(complex_descriptor *d)
16644{
16645 switch(d -> TAG) {
16646 case LEAF_TAG:
16647 return(d -> ld.ld_nelements * d -> ld.ld_size);
16648 case ARRAY_TAG:
16649 return(d -> ad.ad_nelements
16650 * GC_descr_obj_size(d -> ad.ad_element_descr));
16651 case SEQUENCE_TAG:
16652 return(GC_descr_obj_size(d -> sd.sd_first)
16653 + GC_descr_obj_size(d -> sd.sd_second));
16654 default:
16655 ABORT_RET("Bad complex descriptor");
16656 return 0;
16657 }
16658}
16659STATIC mse * GC_push_complex_descriptor(word *addr, complex_descriptor *d,
16660 mse *msp, mse *msl)
16661{
16662 ptr_t current = (ptr_t)addr;
16663 word nelements;
16664 word sz;
16665 word i;
16666 switch(d -> TAG) {
16667 case LEAF_TAG:
16668 {
16669 GC_descr descr = d -> ld.ld_descriptor;
16670 nelements = d -> ld.ld_nelements;
16671 if (msl - msp <= (ptrdiff_t)nelements) return(0);
16672 sz = d -> ld.ld_size;
16673 for (i = 0; i < nelements; i++) {
16674 msp++;
16675 msp -> mse_start = current;
16676 msp -> mse_descr.w = descr;
16677 current += sz;
16678 }
16679 return(msp);
16680 }
16681 case ARRAY_TAG:
16682 {
16683 complex_descriptor *descr = d -> ad.ad_element_descr;
16684 nelements = d -> ad.ad_nelements;
16685 sz = GC_descr_obj_size(descr);
16686 for (i = 0; i < nelements; i++) {
16687 msp = GC_push_complex_descriptor((word *)current, descr,
16688 msp, msl);
16689 if (msp == 0) return(0);
16690 current += sz;
16691 }
16692 return(msp);
16693 }
16694 case SEQUENCE_TAG:
16695 {
16696 sz = GC_descr_obj_size(d -> sd.sd_first);
16697 msp = GC_push_complex_descriptor((word *)current, d -> sd.sd_first,
16698 msp, msl);
16699 if (msp == 0) return(0);
16700 current += sz;
16701 msp = GC_push_complex_descriptor((word *)current, d -> sd.sd_second,
16702 msp, msl);
16703 return(msp);
16704 }
16705 default:
16706 ABORT_RET("Bad complex descriptor");
16707 return 0;
16708 }
16709}
16710STATIC mse * GC_array_mark_proc(word * addr, mse * mark_stack_ptr,
16711 mse * mark_stack_limit,
16712 word env GC_ATTR_UNUSED)
16713{
16714 hdr * hhdr = HDR(addr);
16715 word sz = hhdr -> hb_sz;
16716 word nwords = BYTES_TO_WORDS(sz);
16717 complex_descriptor * descr = (complex_descriptor *)(addr[nwords-1]);
16718 mse * orig_mark_stack_ptr = mark_stack_ptr;
16719 mse * new_mark_stack_ptr;
16720 if (descr == 0) {
16721 return(orig_mark_stack_ptr);
16722 }
16723 new_mark_stack_ptr = GC_push_complex_descriptor(addr, descr,
16724 mark_stack_ptr,
16725 mark_stack_limit-1);
16726 if (new_mark_stack_ptr == 0) {
16727 if (NULL == mark_stack_ptr) ABORT("Bad mark_stack_ptr");
16728#ifdef PARALLEL_MARK
16729 if (GC_mark_stack + GC_mark_stack_size == mark_stack_limit)
16730#endif
16731 {
16732 GC_mark_stack_too_small = TRUE;
16733 }
16734 new_mark_stack_ptr = orig_mark_stack_ptr + 1;
16735 new_mark_stack_ptr -> mse_start = (ptr_t)addr;
16736 new_mark_stack_ptr -> mse_descr.w = sz | GC_DS_LENGTH;
16737 } else {
16738 new_mark_stack_ptr++;
16739 new_mark_stack_ptr -> mse_start = (ptr_t)(addr + nwords - 1);
16740 new_mark_stack_ptr -> mse_descr.w = sizeof(word) | GC_DS_LENGTH;
16741 }
16742 return new_mark_stack_ptr;
16743}
16744GC_API GC_descr GC_CALL GC_make_descriptor(const GC_word * bm, size_t len)
16745{
16746 signed_word last_set_bit = len - 1;
16747 GC_descr result;
16748 DCL_LOCK_STATE;
16749#if defined(AO_HAVE_load_acquire) && defined(AO_HAVE_store_release)
16750 if (!EXPECT(AO_load_acquire(&GC_explicit_typing_initialized), TRUE)) {
16751 LOCK();
16752 if (!GC_explicit_typing_initialized) {
16753 GC_init_explicit_typing();
16754 AO_store_release(&GC_explicit_typing_initialized, TRUE);
16755 }
16756 UNLOCK();
16757 }
16758#else
16759 LOCK();
16760 if (!EXPECT(GC_explicit_typing_initialized, TRUE)) {
16761 GC_init_explicit_typing();
16762 GC_explicit_typing_initialized = TRUE;
16763 }
16764 UNLOCK();
16765#endif
16766 while (last_set_bit >= 0 && !GC_get_bit(bm, last_set_bit))
16767 last_set_bit--;
16768 if (last_set_bit < 0) return(0 );
16769#if ALIGNMENT == CPP_WORDSZ/8
16770 {
16771 signed_word i;
16772 for (i = 0; i < last_set_bit; i++) {
16773 if (!GC_get_bit(bm, i)) {
16774 break;
16775 }
16776 }
16777 if (i == last_set_bit) {
16778 return (WORDS_TO_BYTES(last_set_bit+1) | GC_DS_LENGTH);
16779 }
16780 }
16781#endif
16782 if ((word)last_set_bit < BITMAP_BITS) {
16783 signed_word i;
16784 result = SIGNB;
16785 for (i = last_set_bit - 1; i >= 0; i--) {
16786 result >>= 1;
16787 if (GC_get_bit(bm, i)) result |= SIGNB;
16788 }
16789 result |= GC_DS_BITMAP;
16790 } else {
16791 signed_word index = GC_add_ext_descriptor(bm, (word)last_set_bit + 1);
16792 if (index == -1) return(WORDS_TO_BYTES(last_set_bit+1) | GC_DS_LENGTH);
16793 result = GC_MAKE_PROC(GC_typed_mark_proc_index, (word)index);
16794 }
16795 return result;
16796}
16797GC_API GC_ATTR_MALLOC void * GC_CALL GC_malloc_explicitly_typed(size_t lb,
16798 GC_descr d)
16799{
16800 word *op;
16801 size_t lg;
16802 GC_ASSERT(GC_explicit_typing_initialized);
16803 lb = SIZET_SAT_ADD(lb, TYPD_EXTRA_BYTES);
16804 op = (word *)GC_malloc_kind(lb, GC_explicit_kind);
16805 if (EXPECT(NULL == op, FALSE))
16806 return NULL;
16807 lg = BYTES_TO_GRANULES(GC_size(op));
16808 op[GRANULES_TO_WORDS(lg) - 1] = d;
16809 GC_dirty(op + GRANULES_TO_WORDS(lg) - 1);
16810 REACHABLE_AFTER_DIRTY(d);
16811 return op;
16812}
16813#define GENERAL_MALLOC_IOP(lb, k) \
16814 GC_clear_stack(GC_generic_malloc_ignore_off_page(lb, k))
16815GC_API GC_ATTR_MALLOC void * GC_CALL
16816 GC_malloc_explicitly_typed_ignore_off_page(size_t lb, GC_descr d)
16817{
16818 ptr_t op;
16819 size_t lg;
16820 DCL_LOCK_STATE;
16821 GC_ASSERT(GC_explicit_typing_initialized);
16822 lb = SIZET_SAT_ADD(lb, TYPD_EXTRA_BYTES);
16823 if (SMALL_OBJ(lb)) {
16824 void **opp;
16825 GC_DBG_COLLECT_AT_MALLOC(lb);
16826 LOCK();
16827 lg = GC_size_map[lb];
16828 opp = &GC_obj_kinds[GC_explicit_kind].ok_freelist[lg];
16829 op = (ptr_t)(*opp);
16830 if (EXPECT(0 == op, FALSE)) {
16831 UNLOCK();
16832 op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_explicit_kind);
16833 if (0 == op) return 0;
16834 lg = BYTES_TO_GRANULES(GC_size(op));
16835 } else {
16836 *opp = obj_link(op);
16837 obj_link(op) = 0;
16838 GC_bytes_allocd += GRANULES_TO_BYTES((word)lg);
16839 UNLOCK();
16840 }
16841 } else {
16842 op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_explicit_kind);
16843 if (NULL == op) return NULL;
16844 lg = BYTES_TO_GRANULES(GC_size(op));
16845 }
16846 ((word *)op)[GRANULES_TO_WORDS(lg) - 1] = d;
16847 GC_dirty(op + GRANULES_TO_WORDS(lg) - 1);
16848 REACHABLE_AFTER_DIRTY(d);
16849 return op;
16850}
16851GC_API GC_ATTR_MALLOC void * GC_CALL GC_calloc_explicitly_typed(size_t n,
16852 size_t lb, GC_descr d)
16853{
16854 word *op;
16855 size_t lg;
16856 GC_descr simple_descr;
16857 complex_descriptor *complex_descr;
16858 int descr_type;
16859 struct LeafDescriptor leaf;
16860 GC_ASSERT(GC_explicit_typing_initialized);
16861 descr_type = GC_make_array_descriptor((word)n, (word)lb, d, &simple_descr,
16862 &complex_descr, &leaf);
16863 if ((lb | n) > GC_SQRT_SIZE_MAX
16864 && lb > 0 && n > GC_SIZE_MAX / lb)
16865 return (*GC_get_oom_fn())(GC_SIZE_MAX);
16866 lb *= n;
16867 switch(descr_type) {
16868 case NO_MEM: return(0);
16869 case SIMPLE:
16870 return GC_malloc_explicitly_typed(lb, simple_descr);
16871 case LEAF:
16872 lb = SIZET_SAT_ADD(lb,
16873 sizeof(struct LeafDescriptor) + TYPD_EXTRA_BYTES);
16874 break;
16875 case COMPLEX:
16876 lb = SIZET_SAT_ADD(lb, TYPD_EXTRA_BYTES);
16877 break;
16878 }
16879 op = (word *)GC_malloc_kind(lb, GC_array_kind);
16880 if (EXPECT(NULL == op, FALSE))
16881 return NULL;
16882 lg = BYTES_TO_GRANULES(GC_size(op));
16883 if (descr_type == LEAF) {
16884 volatile struct LeafDescriptor * lp =
16885 (struct LeafDescriptor *)
16886 (op + GRANULES_TO_WORDS(lg)
16887 - (BYTES_TO_WORDS(sizeof(struct LeafDescriptor)) + 1));
16888 lp -> ld_tag = LEAF_TAG;
16889 lp -> ld_size = leaf.ld_size;
16890 lp -> ld_nelements = leaf.ld_nelements;
16891 lp -> ld_descriptor = leaf.ld_descriptor;
16892 ((volatile word *)op)[GRANULES_TO_WORDS(lg) - 1] = (word)lp;
16893 } else {
16894#ifndef GC_NO_FINALIZATION
16895 size_t lw = GRANULES_TO_WORDS(lg);
16896 op[lw - 1] = (word)complex_descr;
16897 GC_dirty(op + lw - 1);
16898 REACHABLE_AFTER_DIRTY(complex_descr);
16899 if (EXPECT(GC_general_register_disappearing_link(
16900 (void **)(op + lw - 1), op)
16901 == GC_NO_MEMORY, FALSE))
16902#endif
16903 {
16904 return (*GC_get_oom_fn())(lb);
16905 }
16906 }
16907 return op;
16908}
16909#include <stdio.h>
16910#include <limits.h>
16911#include <stdarg.h>
16912#ifndef MSWINCE
16913#include <signal.h>
16914#endif
16915#ifdef GC_SOLARIS_THREADS
16916#include <sys/syscall.h>
16917#endif
16918#if defined(UNIX_LIKE) || defined(CYGWIN32) || defined(SYMBIAN) \
16919 || (defined(CONSOLE_LOG) && defined(MSWIN32))
16920#include <fcntl.h>
16921#include <sys/types.h>
16922#include <sys/stat.h>
16923#endif
16924#if defined(CONSOLE_LOG) && defined(MSWIN32) && defined(_MSC_VER)
16925#include <io.h>
16926#endif
16927#ifdef NONSTOP
16928#include <floss.h>
16929#endif
16930#ifdef THREADS
16931#ifdef PCR
16932#include "il/PCR_IL.h"
16933 GC_INNER PCR_Th_ML GC_allocate_ml;
16934#elif defined(SN_TARGET_PSP2)
16935 GC_INNER WapiMutex GC_allocate_ml_PSP2 = { 0, NULL };
16936#elif defined(GC_DEFN_ALLOCATE_ML) || defined(SN_TARGET_PS3)
16937#include <pthread.h>
16938 GC_INNER pthread_mutex_t GC_allocate_ml;
16939#endif
16940#endif
16941#ifdef DYNAMIC_LOADING
16942#define GC_REGISTER_MAIN_STATIC_DATA() GC_register_main_static_data()
16943#elif defined(GC_DONT_REGISTER_MAIN_STATIC_DATA)
16944#define GC_REGISTER_MAIN_STATIC_DATA() FALSE
16945#else
16946#define GC_REGISTER_MAIN_STATIC_DATA() TRUE
16947#endif
16948#ifdef NEED_CANCEL_DISABLE_COUNT
16949 __thread unsigned char GC_cancel_disable_count = 0;
16950#endif
16951GC_FAR struct _GC_arrays GC_arrays ;
16952GC_INNER unsigned GC_n_mark_procs = GC_RESERVED_MARK_PROCS;
16953GC_INNER unsigned GC_n_kinds = GC_N_KINDS_INITIAL_VALUE;
16954GC_INNER GC_bool GC_debugging_started = FALSE;
16955ptr_t GC_stackbottom = 0;
16956#ifdef IA64
16957 ptr_t GC_register_stackbottom = 0;
16958#endif
16959int GC_dont_gc = FALSE;
16960int GC_dont_precollect = FALSE;
16961GC_bool GC_quiet = 0;
16962#if !defined(NO_CLOCK) || !defined(SMALL_CONFIG)
16963 int GC_print_stats = 0;
16964#endif
16965#ifdef GC_PRINT_BACK_HEIGHT
16966 GC_INNER GC_bool GC_print_back_height = TRUE;
16967#else
16968 GC_INNER GC_bool GC_print_back_height = FALSE;
16969#endif
16970#ifndef NO_DEBUGGING
16971#ifdef GC_DUMP_REGULARLY
16972 GC_INNER GC_bool GC_dump_regularly = TRUE;
16973#else
16974 GC_INNER GC_bool GC_dump_regularly = FALSE;
16975#endif
16976#ifndef NO_CLOCK
16977 STATIC CLOCK_TYPE GC_init_time;
16978#endif
16979#endif
16980#ifdef KEEP_BACK_PTRS
16981 GC_INNER long GC_backtraces = 0;
16982#endif
16983#ifdef FIND_LEAK
16984 int GC_find_leak = 1;
16985#else
16986 int GC_find_leak = 0;
16987#endif
16988#ifndef SHORT_DBG_HDRS
16989#ifdef GC_FINDLEAK_DELAY_FREE
16990 GC_INNER GC_bool GC_findleak_delay_free = TRUE;
16991#else
16992 GC_INNER GC_bool GC_findleak_delay_free = FALSE;
16993#endif
16994#endif
16995#ifdef ALL_INTERIOR_POINTERS
16996 int GC_all_interior_pointers = 1;
16997#else
16998 int GC_all_interior_pointers = 0;
16999#endif
17000#ifdef FINALIZE_ON_DEMAND
17001 int GC_finalize_on_demand = 1;
17002#else
17003 int GC_finalize_on_demand = 0;
17004#endif
17005#ifdef JAVA_FINALIZATION
17006 int GC_java_finalization = 1;
17007#else
17008 int GC_java_finalization = 0;
17009#endif
17010GC_finalizer_notifier_proc GC_finalizer_notifier =
17011 (GC_finalizer_notifier_proc)0;
17012#ifdef GC_FORCE_UNMAP_ON_GCOLLECT
17013 GC_INNER GC_bool GC_force_unmap_on_gcollect = TRUE;
17014#else
17015 GC_INNER GC_bool GC_force_unmap_on_gcollect = FALSE;
17016#endif
17017#ifndef GC_LARGE_ALLOC_WARN_INTERVAL
17018#define GC_LARGE_ALLOC_WARN_INTERVAL 5
17019#endif
17020GC_INNER long GC_large_alloc_warn_interval = GC_LARGE_ALLOC_WARN_INTERVAL;
17021STATIC void * GC_CALLBACK GC_default_oom_fn(
17022 size_t bytes_requested GC_ATTR_UNUSED)
17023{
17024 return(0);
17025}
17026GC_oom_func GC_oom_fn = GC_default_oom_fn;
17027#ifdef CAN_HANDLE_FORK
17028#ifdef HANDLE_FORK
17029 GC_INNER int GC_handle_fork = 1;
17030#else
17031 GC_INNER int GC_handle_fork = FALSE;
17032#endif
17033#elif !defined(HAVE_NO_FORK)
17034 GC_API void GC_CALL GC_atfork_prepare(void)
17035 {
17036#ifdef THREADS
17037 ABORT("fork() handling unsupported");
17038#endif
17039 }
17040 GC_API void GC_CALL GC_atfork_parent(void)
17041 {
17042 }
17043 GC_API void GC_CALL GC_atfork_child(void)
17044 {
17045 }
17046#endif
17047GC_API void GC_CALL GC_set_handle_fork(int value GC_ATTR_UNUSED)
17048{
17049#ifdef CAN_HANDLE_FORK
17050 if (!GC_is_initialized)
17051 GC_handle_fork = value >= -1 ? value : 1;
17052#elif defined(THREADS) || (defined(DARWIN) && defined(MPROTECT_VDB))
17053 if (!GC_is_initialized && value) {
17054#ifndef SMALL_CONFIG
17055 GC_init();
17056#ifndef THREADS
17057 if (GC_manual_vdb)
17058 return;
17059#endif
17060#endif
17061 ABORT("fork() handling unsupported");
17062 }
17063#else
17064#endif
17065}
17066STATIC void GC_init_size_map(void)
17067{
17068 size_t i;
17069 GC_size_map[0] = 1;
17070 for (i = 1; i <= GRANULES_TO_BYTES(TINY_FREELISTS-1) - EXTRA_BYTES; i++) {
17071 GC_size_map[i] = ROUNDED_UP_GRANULES(i);
17072#ifndef _MSC_VER
17073 GC_ASSERT(GC_size_map[i] < TINY_FREELISTS);
17074#endif
17075 }
17076}
17077#ifndef SMALL_CLEAR_SIZE
17078#define SMALL_CLEAR_SIZE 256
17079#endif
17080#if defined(ALWAYS_SMALL_CLEAR_STACK) || defined(STACK_NOT_SCANNED)
17081 GC_API void * GC_CALL GC_clear_stack(void *arg)
17082 {
17083#ifndef STACK_NOT_SCANNED
17084 word volatile dummy[SMALL_CLEAR_SIZE];
17085 BZERO(( void *)dummy, sizeof(dummy));
17086#endif
17087 return arg;
17088 }
17089#else
17090#ifdef THREADS
17091#define BIG_CLEAR_SIZE 2048
17092#else
17093 STATIC word GC_stack_last_cleared = 0;
17094 STATIC ptr_t GC_min_sp = NULL;
17095 STATIC ptr_t GC_high_water = NULL;
17096 STATIC word GC_bytes_allocd_at_reset = 0;
17097#define DEGRADE_RATE 50
17098#endif
17099#if defined(ASM_CLEAR_CODE)
17100 void *GC_clear_stack_inner(void *, ptr_t);
17101#else
17102 void *GC_clear_stack_inner(void *arg,
17103#if defined(__APPLE_CC__) && !GC_CLANG_PREREQ(6, 0)
17104 volatile
17105#endif
17106 ptr_t limit)
17107 {
17108#define CLEAR_SIZE 213
17109 volatile word dummy[CLEAR_SIZE];
17110 BZERO(( void *)dummy, sizeof(dummy));
17111 if ((word)GC_approx_sp() COOLER_THAN (word)limit) {
17112 (void)GC_clear_stack_inner(arg, limit);
17113 }
17114#if defined(CPPCHECK)
17115 GC_noop1(dummy[0]);
17116#else
17117 GC_noop1(COVERT_DATAFLOW(dummy));
17118#endif
17119 return(arg);
17120 }
17121#endif
17122#ifdef THREADS
17123 GC_ATTR_NO_SANITIZE_THREAD
17124 static unsigned next_random_no(void)
17125 {
17126 static unsigned random_no = 0;
17127 return ++random_no % 13;
17128 }
17129#endif
17130 GC_API void * GC_CALL GC_clear_stack(void *arg)
17131 {
17132 ptr_t sp = GC_approx_sp();
17133#ifdef THREADS
17134 word volatile dummy[SMALL_CLEAR_SIZE];
17135#endif
17136#define SLOP 400
17137#define GC_SLOP 4000
17138#define CLEAR_THRESHOLD 100000
17139#ifdef THREADS
17140 if (next_random_no() == 0) {
17141 ptr_t limit = sp;
17142 MAKE_HOTTER(limit, BIG_CLEAR_SIZE*sizeof(word));
17143 limit = (ptr_t)((word)limit & ~0xf);
17144 return GC_clear_stack_inner(arg, limit);
17145 }
17146 BZERO((void *)dummy, SMALL_CLEAR_SIZE*sizeof(word));
17147#else
17148 if (GC_gc_no > GC_stack_last_cleared) {
17149 if (GC_stack_last_cleared == 0)
17150 GC_high_water = (ptr_t)GC_stackbottom;
17151 GC_min_sp = GC_high_water;
17152 GC_stack_last_cleared = GC_gc_no;
17153 GC_bytes_allocd_at_reset = GC_bytes_allocd;
17154 }
17155 MAKE_COOLER(GC_high_water, WORDS_TO_BYTES(DEGRADE_RATE) + GC_SLOP);
17156 if ((word)sp HOTTER_THAN (word)GC_high_water) {
17157 GC_high_water = sp;
17158 }
17159 MAKE_HOTTER(GC_high_water, GC_SLOP);
17160 {
17161 ptr_t limit = GC_min_sp;
17162 MAKE_HOTTER(limit, SLOP);
17163 if ((word)sp COOLER_THAN (word)limit) {
17164 limit = (ptr_t)((word)limit & ~0xf);
17165 GC_min_sp = sp;
17166 return GC_clear_stack_inner(arg, limit);
17167 }
17168 }
17169 if (GC_bytes_allocd - GC_bytes_allocd_at_reset > CLEAR_THRESHOLD) {
17170 GC_min_sp = sp;
17171 MAKE_HOTTER(GC_min_sp, CLEAR_THRESHOLD/4);
17172 if ((word)GC_min_sp HOTTER_THAN (word)GC_high_water)
17173 GC_min_sp = GC_high_water;
17174 GC_bytes_allocd_at_reset = GC_bytes_allocd;
17175 }
17176#endif
17177 return arg;
17178 }
17179#endif
17180GC_API void * GC_CALL GC_base(void * p)
17181{
17182 ptr_t r;
17183 struct hblk *h;
17184 bottom_index *bi;
17185 hdr *candidate_hdr;
17186 r = (ptr_t)p;
17187 if (!EXPECT(GC_is_initialized, TRUE)) return 0;
17188 h = HBLKPTR(r);
17189 GET_BI(r, bi);
17190 candidate_hdr = HDR_FROM_BI(bi, r);
17191 if (candidate_hdr == 0) return(0);
17192 while (IS_FORWARDING_ADDR_OR_NIL(candidate_hdr)) {
17193 h = FORWARDED_ADDR(h,candidate_hdr);
17194 r = (ptr_t)h;
17195 candidate_hdr = HDR(h);
17196 }
17197 if (HBLK_IS_FREE(candidate_hdr)) return(0);
17198 r = (ptr_t)((word)r & ~(WORDS_TO_BYTES(1) - 1));
17199 {
17200 size_t offset = HBLKDISPL(r);
17201 word sz = candidate_hdr -> hb_sz;
17202 size_t obj_displ = offset % sz;
17203 ptr_t limit;
17204 r -= obj_displ;
17205 limit = r + sz;
17206 if ((word)limit > (word)(h + 1) && sz <= HBLKSIZE) {
17207 return(0);
17208 }
17209 if ((word)p >= (word)limit) return(0);
17210 }
17211 return((void *)r);
17212}
17213GC_API int GC_CALL GC_is_heap_ptr(const void *p)
17214{
17215 bottom_index *bi;
17216 GC_ASSERT(GC_is_initialized);
17217 GET_BI(p, bi);
17218 return HDR_FROM_BI(bi, p) != 0;
17219}
17220GC_API size_t GC_CALL GC_size(const void * p)
17221{
17222 hdr * hhdr = HDR(p);
17223 return (size_t)hhdr->hb_sz;
17224}
17225GC_API size_t GC_CALL GC_get_heap_size(void)
17226{
17227 return (size_t)(GC_heapsize - GC_unmapped_bytes);
17228}
17229GC_API size_t GC_CALL GC_get_obtained_from_os_bytes(void)
17230{
17231 return (size_t)GC_our_mem_bytes;
17232}
17233GC_API size_t GC_CALL GC_get_free_bytes(void)
17234{
17235 return (size_t)(GC_large_free_bytes - GC_unmapped_bytes);
17236}
17237GC_API size_t GC_CALL GC_get_unmapped_bytes(void)
17238{
17239 return (size_t)GC_unmapped_bytes;
17240}
17241GC_API size_t GC_CALL GC_get_bytes_since_gc(void)
17242{
17243 return (size_t)GC_bytes_allocd;
17244}
17245GC_API size_t GC_CALL GC_get_total_bytes(void)
17246{
17247 return (size_t)(GC_bytes_allocd + GC_bytes_allocd_before_gc);
17248}
17249#ifndef GC_GET_HEAP_USAGE_NOT_NEEDED
17250GC_API size_t GC_CALL GC_get_size_map_at(int i)
17251{
17252 if ((unsigned)i > MAXOBJBYTES)
17253 return GC_SIZE_MAX;
17254 return GRANULES_TO_BYTES(GC_size_map[i]);
17255}
17256GC_API void GC_CALL GC_get_heap_usage_safe(GC_word *pheap_size,
17257 GC_word *pfree_bytes, GC_word *punmapped_bytes,
17258 GC_word *pbytes_since_gc, GC_word *ptotal_bytes)
17259{
17260 DCL_LOCK_STATE;
17261 LOCK();
17262 if (pheap_size != NULL)
17263 *pheap_size = GC_heapsize - GC_unmapped_bytes;
17264 if (pfree_bytes != NULL)
17265 *pfree_bytes = GC_large_free_bytes - GC_unmapped_bytes;
17266 if (punmapped_bytes != NULL)
17267 *punmapped_bytes = GC_unmapped_bytes;
17268 if (pbytes_since_gc != NULL)
17269 *pbytes_since_gc = GC_bytes_allocd;
17270 if (ptotal_bytes != NULL)
17271 *ptotal_bytes = GC_bytes_allocd + GC_bytes_allocd_before_gc;
17272 UNLOCK();
17273}
17274 GC_INNER word GC_reclaimed_bytes_before_gc = 0;
17275 static void fill_prof_stats(struct GC_prof_stats_s *pstats)
17276 {
17277 pstats->heapsize_full = GC_heapsize;
17278 pstats->free_bytes_full = GC_large_free_bytes;
17279 pstats->unmapped_bytes = GC_unmapped_bytes;
17280 pstats->bytes_allocd_since_gc = GC_bytes_allocd;
17281 pstats->allocd_bytes_before_gc = GC_bytes_allocd_before_gc;
17282 pstats->non_gc_bytes = GC_non_gc_bytes;
17283 pstats->gc_no = GC_gc_no;
17284#ifdef PARALLEL_MARK
17285 pstats->markers_m1 = (word)((signed_word)GC_markers_m1);
17286#else
17287 pstats->markers_m1 = 0;
17288#endif
17289 pstats->bytes_reclaimed_since_gc = GC_bytes_found > 0 ?
17290 (word)GC_bytes_found : 0;
17291 pstats->reclaimed_bytes_before_gc = GC_reclaimed_bytes_before_gc;
17292 pstats->expl_freed_bytes_since_gc = GC_bytes_freed;
17293 pstats->obtained_from_os_bytes = GC_our_mem_bytes;
17294 }
17295#include <string.h>
17296 GC_API size_t GC_CALL GC_get_prof_stats(struct GC_prof_stats_s *pstats,
17297 size_t stats_sz)
17298 {
17299 struct GC_prof_stats_s stats;
17300 DCL_LOCK_STATE;
17301 LOCK();
17302 fill_prof_stats(stats_sz >= sizeof(stats) ? pstats : &stats);
17303 UNLOCK();
17304 if (stats_sz == sizeof(stats)) {
17305 return sizeof(stats);
17306 } else if (stats_sz > sizeof(stats)) {
17307 memset((char *)pstats + sizeof(stats), 0xff, stats_sz - sizeof(stats));
17308 return sizeof(stats);
17309 } else {
17310 if (EXPECT(stats_sz > 0, TRUE))
17311 BCOPY(&stats, pstats, stats_sz);
17312 return stats_sz;
17313 }
17314 }
17315#ifdef THREADS
17316 GC_API size_t GC_CALL GC_get_prof_stats_unsafe(
17317 struct GC_prof_stats_s *pstats,
17318 size_t stats_sz)
17319 {
17320 struct GC_prof_stats_s stats;
17321 if (stats_sz >= sizeof(stats)) {
17322 fill_prof_stats(pstats);
17323 if (stats_sz > sizeof(stats))
17324 memset((char *)pstats + sizeof(stats), 0xff,
17325 stats_sz - sizeof(stats));
17326 return sizeof(stats);
17327 } else {
17328 if (EXPECT(stats_sz > 0, TRUE)) {
17329 fill_prof_stats(&stats);
17330 BCOPY(&stats, pstats, stats_sz);
17331 }
17332 return stats_sz;
17333 }
17334 }
17335#endif
17336#endif
17337#if defined(GC_DARWIN_THREADS) || defined(GC_OPENBSD_UTHREADS) \
17338 || defined(GC_WIN32_THREADS) || (defined(NACL) && defined(THREADS))
17339 GC_API void GC_CALL GC_set_suspend_signal(int sig GC_ATTR_UNUSED)
17340 {
17341 }
17342 GC_API void GC_CALL GC_set_thr_restart_signal(int sig GC_ATTR_UNUSED)
17343 {
17344 }
17345 GC_API int GC_CALL GC_get_suspend_signal(void)
17346 {
17347 return -1;
17348 }
17349 GC_API int GC_CALL GC_get_thr_restart_signal(void)
17350 {
17351 return -1;
17352 }
17353#endif
17354#if !defined(_MAX_PATH) && (defined(MSWIN32) || defined(MSWINCE) \
17355 || defined(CYGWIN32))
17356#define _MAX_PATH MAX_PATH
17357#endif
17358#ifdef GC_READ_ENV_FILE
17359 STATIC char *GC_envfile_content = NULL;
17360 STATIC unsigned GC_envfile_length = 0;
17361#ifndef GC_ENVFILE_MAXLEN
17362#define GC_ENVFILE_MAXLEN 0x4000
17363#endif
17364#define GC_ENV_FILE_EXT ".gc.env"
17365 STATIC void GC_envfile_init(void)
17366 {
17367#if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
17368 HANDLE hFile;
17369 char *content;
17370 unsigned ofs;
17371 unsigned len;
17372 DWORD nBytesRead;
17373 TCHAR path[_MAX_PATH + 0x10];
17374 size_t bytes_to_get;
17375 len = (unsigned)GetModuleFileName(NULL , path,
17376 _MAX_PATH + 1);
17377 if (len > 4 && path[len - 4] == (TCHAR)'.') {
17378 len -= 4;
17379 }
17380 BCOPY(TEXT(GC_ENV_FILE_EXT), &path[len], sizeof(TEXT(GC_ENV_FILE_EXT)));
17381 hFile = CreateFile(path, GENERIC_READ,
17382 FILE_SHARE_READ | FILE_SHARE_WRITE,
17383 NULL , OPEN_EXISTING,
17384 FILE_ATTRIBUTE_NORMAL, NULL );
17385 if (hFile == INVALID_HANDLE_VALUE)
17386 return;
17387 len = (unsigned)GetFileSize(hFile, NULL);
17388 if (len <= 1 || len >= GC_ENVFILE_MAXLEN) {
17389 CloseHandle(hFile);
17390 return;
17391 }
17392 GC_ASSERT(GC_page_size != 0);
17393 bytes_to_get = ROUNDUP_PAGESIZE_IF_MMAP((size_t)len + 1);
17394 content = (char *)GET_MEM(bytes_to_get);
17395 if (content == NULL) {
17396 CloseHandle(hFile);
17397 return;
17398 }
17399 GC_add_to_our_memory(content, bytes_to_get);
17400 ofs = 0;
17401 nBytesRead = (DWORD)-1L;
17402 while (ReadFile(hFile, content + ofs, len - ofs + 1, &nBytesRead,
17403 NULL ) && nBytesRead != 0) {
17404 if ((ofs += nBytesRead) > len)
17405 break;
17406 }
17407 CloseHandle(hFile);
17408 if (ofs != len || nBytesRead != 0) {
17409 return;
17410 }
17411 content[ofs] = '\0';
17412 while (ofs-- > 0) {
17413 if (content[ofs] == '\r' || content[ofs] == '\n')
17414 content[ofs] = '\0';
17415 }
17416 GC_ASSERT(NULL == GC_envfile_content);
17417 GC_envfile_length = len + 1;
17418 GC_envfile_content = content;
17419#endif
17420 }
17421 GC_INNER char * GC_envfile_getenv(const char *name)
17422 {
17423 char *p;
17424 char *end_of_content;
17425 unsigned namelen;
17426#ifndef NO_GETENV
17427 p = getenv(name);
17428 if (p != NULL)
17429 return *p != '\0' ? p : NULL;
17430#endif
17431 p = GC_envfile_content;
17432 if (p == NULL)
17433 return NULL;
17434 namelen = strlen(name);
17435 if (namelen == 0)
17436 return NULL;
17437 for (end_of_content = p + GC_envfile_length;
17438 p != end_of_content; p += strlen(p) + 1) {
17439 if (strncmp(p, name, namelen) == 0 && *(p += namelen) == '=') {
17440 p++;
17441 return *p != '\0' ? p : NULL;
17442 }
17443 }
17444 return NULL;
17445 }
17446#endif
17447GC_INNER GC_bool GC_is_initialized = FALSE;
17448GC_API int GC_CALL GC_is_init_called(void)
17449{
17450 return GC_is_initialized;
17451}
17452#if defined(GC_WIN32_THREADS) \
17453 && ((defined(MSWIN32) && !defined(CONSOLE_LOG)) || defined(MSWINCE))
17454 GC_INNER CRITICAL_SECTION GC_write_cs;
17455#endif
17456#ifndef DONT_USE_ATEXIT
17457#if !defined(PCR) && !defined(SMALL_CONFIG)
17458 static GC_bool skip_gc_atexit = FALSE;
17459#else
17460#define skip_gc_atexit FALSE
17461#endif
17462 STATIC void GC_exit_check(void)
17463 {
17464 if (GC_find_leak && !skip_gc_atexit) {
17465#ifdef THREADS
17466 GC_in_thread_creation = TRUE;
17467 GC_gcollect();
17468 GC_in_thread_creation = FALSE;
17469#else
17470 GC_gcollect();
17471#endif
17472 }
17473 }
17474#endif
17475#if defined(UNIX_LIKE) && !defined(NO_DEBUGGING)
17476 static void looping_handler(int sig)
17477 {
17478 GC_err_printf("Caught signal %d: looping in handler\n", sig);
17479 for (;;) {
17480 }
17481 }
17482 static GC_bool installed_looping_handler = FALSE;
17483 static void maybe_install_looping_handler(void)
17484 {
17485 if (!installed_looping_handler && 0 != GETENV("GC_LOOP_ON_ABORT")) {
17486 GC_set_and_save_fault_handler(looping_handler);
17487 installed_looping_handler = TRUE;
17488 }
17489 }
17490#else
17491#define maybe_install_looping_handler()
17492#endif
17493#define GC_DEFAULT_STDOUT_FD 1
17494#define GC_DEFAULT_STDERR_FD 2
17495#if !defined(OS2) && !defined(MACOS) && !defined(GC_ANDROID_LOG) \
17496 && !defined(NN_PLATFORM_CTR) && !defined(NINTENDO_SWITCH) \
17497 && (!defined(MSWIN32) || defined(CONSOLE_LOG)) && !defined(MSWINCE)
17498 STATIC int GC_stdout = GC_DEFAULT_STDOUT_FD;
17499 STATIC int GC_stderr = GC_DEFAULT_STDERR_FD;
17500 STATIC int GC_log = GC_DEFAULT_STDERR_FD;
17501#ifndef MSWIN32
17502 GC_API void GC_CALL GC_set_log_fd(int fd)
17503 {
17504 GC_log = fd;
17505 }
17506#endif
17507#endif
17508#ifdef MSGBOX_ON_ERROR
17509 STATIC void GC_win32_MessageBoxA(const char *msg, const char *caption,
17510 unsigned flags)
17511 {
17512#ifndef DONT_USE_USER32_DLL
17513 (void)MessageBoxA(NULL, msg, caption, flags);
17514#else
17515 HINSTANCE hU32 = LoadLibrary(TEXT("user32.dll"));
17516 if (hU32) {
17517 FARPROC pfn = GetProcAddress(hU32, "MessageBoxA");
17518 if (pfn)
17519 (void)(*(int (WINAPI *)(HWND, LPCSTR, LPCSTR, UINT))(word)pfn)(
17520 NULL , msg, caption, flags);
17521 (void)FreeLibrary(hU32);
17522 }
17523#endif
17524 }
17525#endif
17526#if defined(THREADS) && defined(UNIX_LIKE) && !defined(NO_GETCONTEXT)
17527 static void callee_saves_pushed_dummy_fn(ptr_t data GC_ATTR_UNUSED,
17528 void * context GC_ATTR_UNUSED) {}
17529#endif
17530#ifndef SMALL_CONFIG
17531#ifdef MANUAL_VDB
17532 static GC_bool manual_vdb_allowed = TRUE;
17533#else
17534 static GC_bool manual_vdb_allowed = FALSE;
17535#endif
17536 GC_API void GC_CALL GC_set_manual_vdb_allowed(int value)
17537 {
17538 manual_vdb_allowed = (GC_bool)value;
17539 }
17540 GC_API int GC_CALL GC_get_manual_vdb_allowed(void)
17541 {
17542 return (int)manual_vdb_allowed;
17543 }
17544#endif
17545STATIC word GC_parse_mem_size_arg(const char *str)
17546{
17547 word result = 0;
17548 if (*str != '\0') {
17549 char *endptr;
17550 char ch;
17551 result = (word)STRTOULL(str, &endptr, 10);
17552 ch = *endptr;
17553 if (ch != '\0') {
17554 if (*(endptr + 1) != '\0')
17555 return 0;
17556 switch (ch) {
17557 case 'K':
17558 case 'k':
17559 result <<= 10;
17560 break;
17561 case 'M':
17562 case 'm':
17563 result <<= 20;
17564 break;
17565 case 'G':
17566 case 'g':
17567 result <<= 30;
17568 break;
17569 default:
17570 result = 0;
17571 }
17572 }
17573 }
17574 return result;
17575}
17576#define GC_LOG_STD_NAME "gc.log"
17577GC_API void GC_CALL GC_init(void)
17578{
17579 word initial_heap_sz;
17580 IF_CANCEL(int cancel_state;)
17581#if defined(GC_ASSERTIONS) && defined(GC_ALWAYS_MULTITHREADED)
17582 DCL_LOCK_STATE;
17583#endif
17584 if (EXPECT(GC_is_initialized, TRUE)) return;
17585#ifdef REDIRECT_MALLOC
17586 {
17587 static GC_bool init_started = FALSE;
17588 if (init_started)
17589 ABORT("Redirected malloc() called during GC init");
17590 init_started = TRUE;
17591 }
17592#endif
17593#if defined(GC_INITIAL_HEAP_SIZE) && !defined(CPPCHECK)
17594 initial_heap_sz = GC_INITIAL_HEAP_SIZE;
17595#else
17596 initial_heap_sz = MINHINCR * HBLKSIZE;
17597#endif
17598 DISABLE_CANCEL(cancel_state);
17599#ifdef THREADS
17600#ifndef GC_ALWAYS_MULTITHREADED
17601 GC_ASSERT(!GC_need_to_lock);
17602#endif
17603#ifdef SN_TARGET_PS3
17604 {
17605 pthread_mutexattr_t mattr;
17606 if (0 != pthread_mutexattr_init(&mattr)) {
17607 ABORT("pthread_mutexattr_init failed");
17608 }
17609 if (0 != pthread_mutex_init(&GC_allocate_ml, &mattr)) {
17610 ABORT("pthread_mutex_init failed");
17611 }
17612 (void)pthread_mutexattr_destroy(&mattr);
17613 }
17614#endif
17615#endif
17616#if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
17617#ifndef SPIN_COUNT
17618#define SPIN_COUNT 4000
17619#endif
17620#ifdef MSWINRT_FLAVOR
17621 InitializeCriticalSectionAndSpinCount(&GC_allocate_ml, SPIN_COUNT);
17622#else
17623 {
17624#ifndef MSWINCE
17625 FARPROC pfn = 0;
17626 HMODULE hK32 = GetModuleHandle(TEXT("kernel32.dll"));
17627 if (hK32)
17628 pfn = GetProcAddress(hK32,
17629 "InitializeCriticalSectionAndSpinCount");
17630 if (pfn) {
17631 (*(BOOL (WINAPI *)(LPCRITICAL_SECTION, DWORD))(word)pfn)(
17632 &GC_allocate_ml, SPIN_COUNT);
17633 } else
17634#endif
17635 InitializeCriticalSection(&GC_allocate_ml);
17636 }
17637#endif
17638#endif
17639#if defined(GC_WIN32_THREADS) \
17640 && ((defined(MSWIN32) && !defined(CONSOLE_LOG)) || defined(MSWINCE))
17641 InitializeCriticalSection(&GC_write_cs);
17642#endif
17643 GC_setpagesize();
17644#ifdef MSWIN32
17645 GC_init_win32();
17646#endif
17647#ifdef GC_READ_ENV_FILE
17648 GC_envfile_init();
17649#endif
17650#if !defined(NO_CLOCK) || !defined(SMALL_CONFIG)
17651#ifdef GC_PRINT_VERBOSE_STATS
17652 GC_print_stats = VERBOSE;
17653#else
17654 if (0 != GETENV("GC_PRINT_VERBOSE_STATS")) {
17655 GC_print_stats = VERBOSE;
17656 } else if (0 != GETENV("GC_PRINT_STATS")) {
17657 GC_print_stats = 1;
17658 }
17659#endif
17660#endif
17661#if ((defined(UNIX_LIKE) && !defined(GC_ANDROID_LOG)) \
17662 || (defined(CONSOLE_LOG) && defined(MSWIN32)) \
17663 || defined(CYGWIN32) || defined(SYMBIAN)) && !defined(SMALL_CONFIG)
17664 {
17665 char * file_name = TRUSTED_STRING(GETENV("GC_LOG_FILE"));
17666#ifdef GC_LOG_TO_FILE_ALWAYS
17667 if (NULL == file_name)
17668 file_name = GC_LOG_STD_NAME;
17669#else
17670 if (0 != file_name)
17671#endif
17672 {
17673#if defined(_MSC_VER)
17674 int log_d = _open(file_name, O_CREAT | O_WRONLY | O_APPEND);
17675#else
17676 int log_d = open(file_name, O_CREAT | O_WRONLY | O_APPEND, 0644);
17677#endif
17678 if (log_d < 0) {
17679 GC_err_printf("Failed to open %s as log file\n", file_name);
17680 } else {
17681 char *str;
17682 GC_log = log_d;
17683 str = GETENV("GC_ONLY_LOG_TO_FILE");
17684#ifdef GC_ONLY_LOG_TO_FILE
17685 if (str != NULL && *str == '0' && *(str + 1) == '\0')
17686#else
17687 if (str == NULL || (*str == '0' && *(str + 1) == '\0'))
17688#endif
17689 {
17690 GC_stdout = log_d;
17691 GC_stderr = log_d;
17692 }
17693 }
17694 }
17695 }
17696#endif
17697#if !defined(NO_DEBUGGING) && !defined(GC_DUMP_REGULARLY)
17698 if (0 != GETENV("GC_DUMP_REGULARLY")) {
17699 GC_dump_regularly = TRUE;
17700 }
17701#endif
17702#ifdef KEEP_BACK_PTRS
17703 {
17704 char * backtraces_string = GETENV("GC_BACKTRACES");
17705 if (0 != backtraces_string) {
17706 GC_backtraces = atol(backtraces_string);
17707 if (backtraces_string[0] == '\0') GC_backtraces = 1;
17708 }
17709 }
17710#endif
17711 if (0 != GETENV("GC_FIND_LEAK")) {
17712 GC_find_leak = 1;
17713 }
17714#ifndef SHORT_DBG_HDRS
17715 if (0 != GETENV("GC_FINDLEAK_DELAY_FREE")) {
17716 GC_findleak_delay_free = TRUE;
17717 }
17718#endif
17719 if (0 != GETENV("GC_ALL_INTERIOR_POINTERS")) {
17720 GC_all_interior_pointers = 1;
17721 }
17722 if (0 != GETENV("GC_DONT_GC")) {
17723#ifdef LINT2
17724 GC_disable();
17725#else
17726 GC_dont_gc = 1;
17727#endif
17728 }
17729 if (0 != GETENV("GC_PRINT_BACK_HEIGHT")) {
17730 GC_print_back_height = TRUE;
17731 }
17732 if (0 != GETENV("GC_NO_BLACKLIST_WARNING")) {
17733 GC_large_alloc_warn_interval = LONG_MAX;
17734 }
17735 {
17736 char * addr_string = GETENV("GC_TRACE");
17737 if (0 != addr_string) {
17738#ifndef ENABLE_TRACE
17739 WARN("Tracing not enabled: Ignoring GC_TRACE value\n", 0);
17740#else
17741 word addr = (word)STRTOULL(addr_string, NULL, 16);
17742 if (addr < 0x1000)
17743 WARN("Unlikely trace address: %p\n", (void *)addr);
17744 GC_trace_addr = (ptr_t)addr;
17745#endif
17746 }
17747 }
17748#ifdef GC_COLLECT_AT_MALLOC
17749 {
17750 char * string = GETENV("GC_COLLECT_AT_MALLOC");
17751 if (0 != string) {
17752 size_t min_lb = (size_t)STRTOULL(string, NULL, 10);
17753 if (min_lb > 0)
17754 GC_dbg_collect_at_malloc_min_lb = min_lb;
17755 }
17756 }
17757#endif
17758#if !defined(GC_DISABLE_INCREMENTAL) && !defined(NO_CLOCK)
17759 {
17760 char * time_limit_string = GETENV("GC_PAUSE_TIME_TARGET");
17761 if (0 != time_limit_string) {
17762 long time_limit = atol(time_limit_string);
17763 if (time_limit > 0) {
17764 GC_time_limit = time_limit;
17765 }
17766 }
17767 }
17768#endif
17769#ifndef SMALL_CONFIG
17770 {
17771 char * full_freq_string = GETENV("GC_FULL_FREQUENCY");
17772 if (full_freq_string != NULL) {
17773 int full_freq = atoi(full_freq_string);
17774 if (full_freq > 0)
17775 GC_full_freq = full_freq;
17776 }
17777 }
17778#endif
17779 {
17780 char * interval_string = GETENV("GC_LARGE_ALLOC_WARN_INTERVAL");
17781 if (0 != interval_string) {
17782 long interval = atol(interval_string);
17783 if (interval <= 0) {
17784 WARN("GC_LARGE_ALLOC_WARN_INTERVAL environment variable has "
17785 "bad value: Ignoring\n", 0);
17786 } else {
17787 GC_large_alloc_warn_interval = interval;
17788 }
17789 }
17790 }
17791 {
17792 char * space_divisor_string = GETENV("GC_FREE_SPACE_DIVISOR");
17793 if (space_divisor_string != NULL) {
17794 int space_divisor = atoi(space_divisor_string);
17795 if (space_divisor > 0)
17796 GC_free_space_divisor = (unsigned)space_divisor;
17797 }
17798 }
17799#ifdef USE_MUNMAP
17800 {
17801 char * string = GETENV("GC_UNMAP_THRESHOLD");
17802 if (string != NULL) {
17803 if (*string == '0' && *(string + 1) == '\0') {
17804 GC_unmap_threshold = 0;
17805 } else {
17806 int unmap_threshold = atoi(string);
17807 if (unmap_threshold > 0)
17808 GC_unmap_threshold = unmap_threshold;
17809 }
17810 }
17811 }
17812 {
17813 char * string = GETENV("GC_FORCE_UNMAP_ON_GCOLLECT");
17814 if (string != NULL) {
17815 if (*string == '0' && *(string + 1) == '\0') {
17816 GC_force_unmap_on_gcollect = FALSE;
17817 } else {
17818 GC_force_unmap_on_gcollect = TRUE;
17819 }
17820 }
17821 }
17822 {
17823 char * string = GETENV("GC_USE_ENTIRE_HEAP");
17824 if (string != NULL) {
17825 if (*string == '0' && *(string + 1) == '\0') {
17826 GC_use_entire_heap = FALSE;
17827 } else {
17828 GC_use_entire_heap = TRUE;
17829 }
17830 }
17831 }
17832#endif
17833#if !defined(NO_DEBUGGING) && !defined(NO_CLOCK)
17834 GET_TIME(GC_init_time);
17835#endif
17836 maybe_install_looping_handler();
17837#if ALIGNMENT > GC_DS_TAGS
17838 if (EXTRA_BYTES != 0)
17839 GC_obj_kinds[NORMAL].ok_descriptor = (word)(-ALIGNMENT) | GC_DS_LENGTH;
17840#endif
17841 GC_exclude_static_roots_inner(beginGC_arrays, endGC_arrays);
17842 GC_exclude_static_roots_inner(beginGC_obj_kinds, endGC_obj_kinds);
17843#ifdef SEPARATE_GLOBALS
17844 GC_exclude_static_roots_inner(beginGC_objfreelist, endGC_objfreelist);
17845 GC_exclude_static_roots_inner(beginGC_aobjfreelist, endGC_aobjfreelist);
17846#endif
17847#if defined(USE_PROC_FOR_LIBRARIES) && defined(GC_LINUX_THREADS)
17848 WARN("USE_PROC_FOR_LIBRARIES + GC_LINUX_THREADS performs poorly.\n", 0);
17849#endif
17850#if defined(SEARCH_FOR_DATA_START)
17851 GC_init_linux_data_start();
17852#endif
17853#if defined(NETBSD) && defined(__ELF__)
17854 GC_init_netbsd_elf();
17855#endif
17856#if !defined(THREADS) || defined(GC_PTHREADS) \
17857 || defined(NN_PLATFORM_CTR) || defined(NINTENDO_SWITCH) \
17858 || defined(GC_WIN32_THREADS) || defined(GC_SOLARIS_THREADS)
17859 if (GC_stackbottom == 0) {
17860 GC_stackbottom = GC_get_main_stack_base();
17861#if (defined(LINUX) || defined(HPUX)) && defined(IA64)
17862 GC_register_stackbottom = GC_get_register_stack_base();
17863#endif
17864 } else {
17865#if (defined(LINUX) || defined(HPUX)) && defined(IA64)
17866 if (GC_register_stackbottom == 0) {
17867 WARN("GC_register_stackbottom should be set with GC_stackbottom\n", 0);
17868 GC_register_stackbottom = GC_get_register_stack_base();
17869 }
17870#endif
17871 }
17872#endif
17873#if !defined(CPPCHECK)
17874 GC_STATIC_ASSERT(sizeof(ptr_t) == sizeof(word));
17875 GC_STATIC_ASSERT(sizeof(signed_word) == sizeof(word));
17876#if !defined(_AUX_SOURCE) || defined(__GNUC__)
17877 GC_STATIC_ASSERT((word)(-1) > (word)0);
17878#endif
17879 GC_STATIC_ASSERT((signed_word)(-1) < (signed_word)0);
17880#endif
17881 GC_STATIC_ASSERT(sizeof (struct hblk) == HBLKSIZE);
17882#ifndef THREADS
17883 GC_ASSERT(!((word)GC_stackbottom HOTTER_THAN (word)GC_approx_sp()));
17884#endif
17885 GC_init_headers();
17886#ifndef GC_DISABLE_INCREMENTAL
17887 if (GC_incremental || 0 != GETENV("GC_ENABLE_INCREMENTAL")) {
17888#if defined(BASE_ATOMIC_OPS_EMULATED) || defined(CHECKSUMS) \
17889 || defined(REDIRECT_MALLOC) || defined(REDIRECT_MALLOC_IN_HEADER) \
17890 || defined(SMALL_CONFIG)
17891#else
17892 if (manual_vdb_allowed) {
17893 GC_manual_vdb = TRUE;
17894 GC_incremental = TRUE;
17895 } else
17896#endif
17897 {
17898 GC_incremental = GC_dirty_init();
17899 GC_ASSERT(GC_bytes_allocd == 0);
17900 }
17901 }
17902#endif
17903 if (GC_REGISTER_MAIN_STATIC_DATA()) GC_register_data_segments();
17904 GC_bl_init();
17905 GC_mark_init();
17906 {
17907 char * sz_str = GETENV("GC_INITIAL_HEAP_SIZE");
17908 if (sz_str != NULL) {
17909 initial_heap_sz = GC_parse_mem_size_arg(sz_str);
17910 if (initial_heap_sz <= MINHINCR * HBLKSIZE) {
17911 WARN("Bad initial heap size %s - ignoring it.\n", sz_str);
17912 }
17913 }
17914 }
17915 {
17916 char * sz_str = GETENV("GC_MAXIMUM_HEAP_SIZE");
17917 if (sz_str != NULL) {
17918 word max_heap_sz = GC_parse_mem_size_arg(sz_str);
17919 if (max_heap_sz < initial_heap_sz) {
17920 WARN("Bad maximum heap size %s - ignoring it.\n", sz_str);
17921 }
17922 if (0 == GC_max_retries) GC_max_retries = 2;
17923 GC_set_max_heap_size(max_heap_sz);
17924 }
17925 }
17926#if defined(GC_ASSERTIONS) && defined(GC_ALWAYS_MULTITHREADED)
17927 LOCK();
17928#endif
17929 if (!GC_expand_hp_inner(divHBLKSZ(initial_heap_sz))) {
17930 GC_err_printf("Can't start up: not enough memory\n");
17931 EXIT();
17932 } else {
17933 GC_requested_heapsize += initial_heap_sz;
17934 }
17935 if (GC_all_interior_pointers)
17936 GC_initialize_offsets();
17937 GC_register_displacement_inner(0L);
17938#if defined(GC_LINUX_THREADS) && defined(REDIRECT_MALLOC)
17939 if (!GC_all_interior_pointers) {
17940 GC_register_displacement_inner(sizeof(void *));
17941 }
17942#endif
17943 GC_init_size_map();
17944#ifdef PCR
17945 if (PCR_IL_Lock(PCR_Bool_false, PCR_allSigsBlocked, PCR_waitForever)
17946 != PCR_ERes_okay) {
17947 ABORT("Can't lock load state");
17948 } else if (PCR_IL_Unlock() != PCR_ERes_okay) {
17949 ABORT("Can't unlock load state");
17950 }
17951 PCR_IL_Unlock();
17952 GC_pcr_install();
17953#endif
17954 GC_is_initialized = TRUE;
17955#if defined(GC_PTHREADS) || defined(GC_WIN32_THREADS)
17956#if defined(LINT2) \
17957 && !(defined(GC_ASSERTIONS) && defined(GC_ALWAYS_MULTITHREADED))
17958 LOCK();
17959 GC_thr_init();
17960 UNLOCK();
17961#else
17962 GC_thr_init();
17963#endif
17964#ifdef PARALLEL_MARK
17965#if defined(GC_ASSERTIONS) && defined(GC_ALWAYS_MULTITHREADED)
17966 UNLOCK();
17967#endif
17968 GC_start_mark_threads_inner();
17969#if defined(GC_ASSERTIONS) && defined(GC_ALWAYS_MULTITHREADED)
17970 LOCK();
17971#endif
17972#endif
17973#endif
17974 COND_DUMP;
17975 if (!GC_dont_precollect || GC_incremental) {
17976 GC_gcollect_inner();
17977 }
17978#if defined(GC_ASSERTIONS) && defined(GC_ALWAYS_MULTITHREADED)
17979 UNLOCK();
17980#endif
17981#if defined(THREADS) && defined(UNIX_LIKE) && !defined(NO_GETCONTEXT)
17982 if (GC_dont_gc || GC_dont_precollect)
17983 GC_with_callee_saves_pushed(callee_saves_pushed_dummy_fn, NULL);
17984#endif
17985#ifndef DONT_USE_ATEXIT
17986 if (GC_find_leak) {
17987 atexit(GC_exit_check);
17988 }
17989#endif
17990#if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC) \
17991 || (defined(GC_ALWAYS_MULTITHREADED) && defined(GC_WIN32_THREADS) \
17992 && !defined(GC_NO_THREADS_DISCOVERY))
17993 GC_init_parallel();
17994#endif
17995#if defined(DYNAMIC_LOADING) && defined(DARWIN)
17996 GC_init_dyld();
17997#endif
17998 RESTORE_CANCEL(cancel_state);
17999}
18000GC_API void GC_CALL GC_enable_incremental(void)
18001{
18002#if !defined(GC_DISABLE_INCREMENTAL) && !defined(KEEP_BACK_PTRS)
18003 DCL_LOCK_STATE;
18004 if (!GC_find_leak && 0 == GETENV("GC_DISABLE_INCREMENTAL")) {
18005 LOCK();
18006 if (!GC_incremental) {
18007 GC_setpagesize();
18008 maybe_install_looping_handler();
18009 if (!GC_is_initialized) {
18010 UNLOCK();
18011 GC_incremental = TRUE;
18012 GC_init();
18013 LOCK();
18014 } else {
18015#if !defined(BASE_ATOMIC_OPS_EMULATED) && !defined(CHECKSUMS) \
18016 && !defined(REDIRECT_MALLOC) \
18017 && !defined(REDIRECT_MALLOC_IN_HEADER) && !defined(SMALL_CONFIG)
18018 if (manual_vdb_allowed) {
18019 GC_manual_vdb = TRUE;
18020 GC_incremental = TRUE;
18021 } else
18022#endif
18023 {
18024 GC_incremental = GC_dirty_init();
18025 }
18026 }
18027 if (GC_incremental && !GC_dont_gc) {
18028 IF_CANCEL(int cancel_state;)
18029 DISABLE_CANCEL(cancel_state);
18030 if (GC_bytes_allocd > 0) {
18031 GC_gcollect_inner();
18032 }
18033 GC_read_dirty(FALSE);
18034 RESTORE_CANCEL(cancel_state);
18035 }
18036 }
18037 UNLOCK();
18038 return;
18039 }
18040#endif
18041 GC_init();
18042}
18043#if defined(THREADS)
18044 GC_API void GC_CALL GC_start_mark_threads(void)
18045 {
18046#if defined(PARALLEL_MARK) && defined(CAN_HANDLE_FORK) \
18047 && !defined(THREAD_SANITIZER)
18048 IF_CANCEL(int cancel_state;)
18049 DISABLE_CANCEL(cancel_state);
18050 GC_start_mark_threads_inner();
18051 RESTORE_CANCEL(cancel_state);
18052#else
18053 GC_ASSERT(I_DONT_HOLD_LOCK());
18054#endif
18055 }
18056#endif
18057 GC_API void GC_CALL GC_deinit(void)
18058 {
18059 if (GC_is_initialized) {
18060 GC_is_initialized = FALSE;
18061#if defined(GC_WIN32_THREADS) && (defined(MSWIN32) || defined(MSWINCE))
18062#if !defined(CONSOLE_LOG) || defined(MSWINCE)
18063 DeleteCriticalSection(&GC_write_cs);
18064#endif
18065 DeleteCriticalSection(&GC_allocate_ml);
18066#endif
18067 }
18068 }
18069#if (defined(MSWIN32) && !defined(CONSOLE_LOG)) || defined(MSWINCE)
18070#if defined(_MSC_VER) && defined(_DEBUG) && !defined(MSWINCE)
18071#include <crtdbg.h>
18072#endif
18073 STATIC HANDLE GC_log = 0;
18074#ifdef THREADS
18075#if defined(PARALLEL_MARK) && !defined(GC_ALWAYS_MULTITHREADED)
18076#define IF_NEED_TO_LOCK(x) if (GC_parallel || GC_need_to_lock) x
18077#else
18078#define IF_NEED_TO_LOCK(x) if (GC_need_to_lock) x
18079#endif
18080#else
18081#define IF_NEED_TO_LOCK(x)
18082#endif
18083#ifdef MSWINRT_FLAVOR
18084#include <windows.storage.h>
18085 DECLSPEC_IMPORT HRESULT WINAPI RoGetActivationFactory(
18086 HSTRING activatableClassId,
18087 REFIID iid, void** factory);
18088 static GC_bool getWinRTLogPath(wchar_t* buf, size_t bufLen)
18089 {
18090 static const GUID kIID_IApplicationDataStatics = {
18091 0x5612147B, 0xE843, 0x45E3,
18092 0x94, 0xD8, 0x06, 0x16, 0x9E, 0x3C, 0x8E, 0x17
18093 };
18094 static const GUID kIID_IStorageItem = {
18095 0x4207A996, 0xCA2F, 0x42F7,
18096 0xBD, 0xE8, 0x8B, 0x10, 0x45, 0x7A, 0x7F, 0x30
18097 };
18098 GC_bool result = FALSE;
18099 HSTRING_HEADER appDataClassNameHeader;
18100 HSTRING appDataClassName;
18101 __x_ABI_CWindows_CStorage_CIApplicationDataStatics* appDataStatics = 0;
18102 GC_ASSERT(bufLen > 0);
18103 if (SUCCEEDED(WindowsCreateStringReference(
18104 RuntimeClass_Windows_Storage_ApplicationData,
18105 (sizeof(RuntimeClass_Windows_Storage_ApplicationData)-1)
18106 / sizeof(wchar_t),
18107 &appDataClassNameHeader, &appDataClassName))
18108 && SUCCEEDED(RoGetActivationFactory(appDataClassName,
18109 &kIID_IApplicationDataStatics,
18110 &appDataStatics))) {
18111 __x_ABI_CWindows_CStorage_CIApplicationData* appData = NULL;
18112 __x_ABI_CWindows_CStorage_CIStorageFolder* tempFolder = NULL;
18113 __x_ABI_CWindows_CStorage_CIStorageItem* tempFolderItem = NULL;
18114 HSTRING tempPath = NULL;
18115 if (SUCCEEDED(appDataStatics->lpVtbl->get_Current(appDataStatics,
18116 &appData))
18117 && SUCCEEDED(appData->lpVtbl->get_TemporaryFolder(appData,
18118 &tempFolder))
18119 && SUCCEEDED(tempFolder->lpVtbl->QueryInterface(tempFolder,
18120 &kIID_IStorageItem,
18121 &tempFolderItem))
18122 && SUCCEEDED(tempFolderItem->lpVtbl->get_Path(tempFolderItem,
18123 &tempPath))) {
18124 UINT32 tempPathLen;
18125 const wchar_t* tempPathBuf =
18126 WindowsGetStringRawBuffer(tempPath, &tempPathLen);
18127 buf[0] = '\0';
18128 if (wcsncat_s(buf, bufLen, tempPathBuf, tempPathLen) == 0
18129 && wcscat_s(buf, bufLen, L"\\") == 0
18130 && wcscat_s(buf, bufLen, TEXT(GC_LOG_STD_NAME)) == 0)
18131 result = TRUE;
18132 WindowsDeleteString(tempPath);
18133 }
18134 if (tempFolderItem != NULL)
18135 tempFolderItem->lpVtbl->Release(tempFolderItem);
18136 if (tempFolder != NULL)
18137 tempFolder->lpVtbl->Release(tempFolder);
18138 if (appData != NULL)
18139 appData->lpVtbl->Release(appData);
18140 appDataStatics->lpVtbl->Release(appDataStatics);
18141 }
18142 return result;
18143 }
18144#endif
18145 STATIC HANDLE GC_CreateLogFile(void)
18146 {
18147 HANDLE hFile;
18148#ifdef MSWINRT_FLAVOR
18149 TCHAR pathBuf[_MAX_PATH + 0x10];
18150 hFile = INVALID_HANDLE_VALUE;
18151 if (getWinRTLogPath(pathBuf, _MAX_PATH + 1)) {
18152 CREATEFILE2_EXTENDED_PARAMETERS extParams;
18153 BZERO(&extParams, sizeof(extParams));
18154 extParams.dwSize = sizeof(extParams);
18155 extParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
18156 extParams.dwFileFlags = GC_print_stats == VERBOSE ? 0
18157 : FILE_FLAG_WRITE_THROUGH;
18158 hFile = CreateFile2(pathBuf, GENERIC_WRITE, FILE_SHARE_READ,
18159 CREATE_ALWAYS, &extParams);
18160 }
18161#else
18162 TCHAR *logPath;
18163#if defined(NO_GETENV_WIN32) && defined(CPPCHECK)
18164#define appendToFile FALSE
18165#else
18166 BOOL appendToFile = FALSE;
18167#endif
18168#if !defined(NO_GETENV_WIN32) || !defined(OLD_WIN32_LOG_FILE)
18169 TCHAR pathBuf[_MAX_PATH + 0x10];
18170 logPath = pathBuf;
18171#endif
18172#ifndef NO_GETENV_WIN32
18173 if (GetEnvironmentVariable(TEXT("GC_LOG_FILE"), pathBuf,
18174 _MAX_PATH + 1) - 1U < (DWORD)_MAX_PATH) {
18175 appendToFile = TRUE;
18176 } else
18177#endif
18178 {
18179#ifdef OLD_WIN32_LOG_FILE
18180 logPath = TEXT(GC_LOG_STD_NAME);
18181#else
18182 int len = (int)GetModuleFileName(NULL , pathBuf,
18183 _MAX_PATH + 1);
18184 if (len > 4 && pathBuf[len - 4] == (TCHAR)'.') {
18185 len -= 4;
18186 }
18187 BCOPY(TEXT(".") TEXT(GC_LOG_STD_NAME), &pathBuf[len],
18188 sizeof(TEXT(".") TEXT(GC_LOG_STD_NAME)));
18189#endif
18190 }
18191 hFile = CreateFile(logPath, GENERIC_WRITE, FILE_SHARE_READ,
18192 NULL ,
18193 appendToFile ? OPEN_ALWAYS : CREATE_ALWAYS,
18194 GC_print_stats == VERBOSE ? FILE_ATTRIBUTE_NORMAL :
18195 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
18196 NULL );
18197#ifndef NO_GETENV_WIN32
18198 if (appendToFile && hFile != INVALID_HANDLE_VALUE) {
18199 LONG posHigh = 0;
18200 (void)SetFilePointer(hFile, 0, &posHigh, FILE_END);
18201 }
18202#endif
18203#undef appendToFile
18204#endif
18205 return hFile;
18206 }
18207 STATIC int GC_write(const char *buf, size_t len)
18208 {
18209 BOOL res;
18210 DWORD written;
18211#if defined(THREADS) && defined(GC_ASSERTIONS)
18212 static GC_bool inside_write = FALSE;
18213 if (inside_write)
18214 return -1;
18215#endif
18216 if (len == 0)
18217 return 0;
18218 IF_NEED_TO_LOCK(EnterCriticalSection(&GC_write_cs));
18219#if defined(THREADS) && defined(GC_ASSERTIONS)
18220 if (GC_write_disabled) {
18221 inside_write = TRUE;
18222 ABORT("Assertion failure: GC_write called with write_disabled");
18223 }
18224#endif
18225 if (GC_log == 0) {
18226 GC_log = GC_CreateLogFile();
18227 }
18228 if (GC_log == INVALID_HANDLE_VALUE) {
18229 IF_NEED_TO_LOCK(LeaveCriticalSection(&GC_write_cs));
18230#ifdef NO_DEBUGGING
18231 return 0;
18232#else
18233 return -1;
18234#endif
18235 }
18236 res = WriteFile(GC_log, buf, (DWORD)len, &written, NULL);
18237#if defined(_MSC_VER) && defined(_DEBUG) && !defined(NO_CRT)
18238#ifdef MSWINCE
18239 {
18240 WCHAR wbuf[1024];
18241 wbuf[MultiByteToWideChar(CP_ACP, 0 ,
18242 buf, len, wbuf,
18243 sizeof(wbuf) / sizeof(wbuf[0]) - 1)] = 0;
18244 OutputDebugStringW(wbuf);
18245 }
18246#else
18247 _CrtDbgReport(_CRT_WARN, NULL, 0, NULL, "%.*s", len, buf);
18248#endif
18249#endif
18250 IF_NEED_TO_LOCK(LeaveCriticalSection(&GC_write_cs));
18251 return res ? (int)written : -1;
18252 }
18253#define WRITE(f, buf, len) GC_write(buf, len)
18254#elif defined(OS2) || defined(MACOS)
18255 STATIC FILE * GC_stdout = NULL;
18256 STATIC FILE * GC_stderr = NULL;
18257 STATIC FILE * GC_log = NULL;
18258 STATIC void GC_set_files(void)
18259 {
18260 if (GC_stdout == NULL) {
18261 GC_stdout = stdout;
18262 }
18263 if (GC_stderr == NULL) {
18264 GC_stderr = stderr;
18265 }
18266 if (GC_log == NULL) {
18267 GC_log = stderr;
18268 }
18269 }
18270 GC_INLINE int GC_write(FILE *f, const char *buf, size_t len)
18271 {
18272 int res = fwrite(buf, 1, len, f);
18273 fflush(f);
18274 return res;
18275 }
18276#define WRITE(f, buf, len) (GC_set_files(), GC_write(f, buf, len))
18277#elif defined(GC_ANDROID_LOG)
18278#include <android/log.h>
18279#ifndef GC_ANDROID_LOG_TAG
18280#define GC_ANDROID_LOG_TAG "BDWGC"
18281#endif
18282#define GC_stdout ANDROID_LOG_DEBUG
18283#define GC_stderr ANDROID_LOG_ERROR
18284#define GC_log GC_stdout
18285#define WRITE(level, buf, unused_len) \
18286 __android_log_write(level, GC_ANDROID_LOG_TAG, buf)
18287#elif defined(NN_PLATFORM_CTR)
18288 int n3ds_log_write(const char* text, int length);
18289#define WRITE(level, buf, len) n3ds_log_write(buf, len)
18290#elif defined(NINTENDO_SWITCH)
18291 int switch_log_write(const char* text, int length);
18292#define WRITE(level, buf, len) switch_log_write(buf, len)
18293#else
18294#if !defined(GC_NO_TYPES) && !defined(SN_TARGET_PSP2)
18295#if !defined(AMIGA) && !defined(MSWIN32) && !defined(MSWIN_XBOX1) \
18296 && !defined(__CC_ARM)
18297#include <unistd.h>
18298#endif
18299#if !defined(ECOS) && !defined(NOSYS)
18300#include <errno.h>
18301#endif
18302#endif
18303 STATIC int GC_write(int fd, const char *buf, size_t len)
18304 {
18305#if defined(ECOS) || defined(PLATFORM_WRITE) || defined(SN_TARGET_PSP2) \
18306 || defined(NOSYS)
18307#ifdef ECOS
18308#else
18309#endif
18310 return len;
18311#else
18312 int bytes_written = 0;
18313 IF_CANCEL(int cancel_state;)
18314 DISABLE_CANCEL(cancel_state);
18315 while ((unsigned)bytes_written < len) {
18316#ifdef GC_SOLARIS_THREADS
18317 int result = syscall(SYS_write, fd, buf + bytes_written,
18318 len - bytes_written);
18319#elif defined(_MSC_VER)
18320 int result = _write(fd, buf + bytes_written,
18321 (unsigned)(len - bytes_written));
18322#else
18323 int result = write(fd, buf + bytes_written, len - bytes_written);
18324#endif
18325 if (-1 == result) {
18326 if (EAGAIN == errno)
18327 continue;
18328 RESTORE_CANCEL(cancel_state);
18329 return(result);
18330 }
18331 bytes_written += result;
18332 }
18333 RESTORE_CANCEL(cancel_state);
18334 return(bytes_written);
18335#endif
18336 }
18337#define WRITE(f, buf, len) GC_write(f, buf, len)
18338#endif
18339#define BUFSZ 1024
18340#if defined(DJGPP) || defined(__STRICT_ANSI__)
18341#define GC_VSNPRINTF(buf, bufsz, format, args) vsprintf(buf, format, args)
18342#elif defined(_MSC_VER)
18343#ifdef MSWINCE
18344#define GC_VSNPRINTF StringCchVPrintfA
18345#else
18346#define GC_VSNPRINTF _vsnprintf
18347#endif
18348#else
18349#define GC_VSNPRINTF vsnprintf
18350#endif
18351#define GC_PRINTF_FILLBUF(buf, format) \
18352 do { \
18353 va_list args; \
18354 va_start(args, format); \
18355 (buf)[sizeof(buf) - 1] = 0x15; \
18356 (void)GC_VSNPRINTF(buf, sizeof(buf) - 1, format, args); \
18357 va_end(args); \
18358 if ((buf)[sizeof(buf) - 1] != 0x15) \
18359 ABORT("GC_printf clobbered stack"); \
18360 } while (0)
18361void GC_printf(const char *format, ...)
18362{
18363 if (!GC_quiet) {
18364 char buf[BUFSZ + 1];
18365 GC_PRINTF_FILLBUF(buf, format);
18366#ifdef NACL
18367 (void)WRITE(GC_stdout, buf, strlen(buf));
18368#else
18369 if (WRITE(GC_stdout, buf, strlen(buf)) < 0
18370#if defined(CYGWIN32) || (defined(CONSOLE_LOG) && defined(MSWIN32))
18371 && GC_stdout != GC_DEFAULT_STDOUT_FD
18372#endif
18373 ) {
18374 ABORT("write to stdout failed");
18375 }
18376#endif
18377 }
18378}
18379void GC_err_printf(const char *format, ...)
18380{
18381 char buf[BUFSZ + 1];
18382 GC_PRINTF_FILLBUF(buf, format);
18383 GC_err_puts(buf);
18384}
18385void GC_log_printf(const char *format, ...)
18386{
18387 char buf[BUFSZ + 1];
18388 GC_PRINTF_FILLBUF(buf, format);
18389#ifdef NACL
18390 (void)WRITE(GC_log, buf, strlen(buf));
18391#else
18392 if (WRITE(GC_log, buf, strlen(buf)) < 0
18393#if defined(CYGWIN32) || (defined(CONSOLE_LOG) && defined(MSWIN32))
18394 && GC_log != GC_DEFAULT_STDERR_FD
18395#endif
18396 ) {
18397 ABORT("write to GC log failed");
18398 }
18399#endif
18400}
18401#ifndef GC_ANDROID_LOG
18402#define GC_warn_printf GC_err_printf
18403#else
18404 GC_INNER void GC_info_log_printf(const char *format, ...)
18405 {
18406 char buf[BUFSZ + 1];
18407 GC_PRINTF_FILLBUF(buf, format);
18408 (void)WRITE(ANDROID_LOG_INFO, buf, 0 );
18409 }
18410 GC_INNER void GC_verbose_log_printf(const char *format, ...)
18411 {
18412 char buf[BUFSZ + 1];
18413 GC_PRINTF_FILLBUF(buf, format);
18414 (void)WRITE(ANDROID_LOG_VERBOSE, buf, 0);
18415 }
18416 STATIC void GC_warn_printf(const char *format, ...)
18417 {
18418 char buf[BUFSZ + 1];
18419 GC_PRINTF_FILLBUF(buf, format);
18420 (void)WRITE(ANDROID_LOG_WARN, buf, 0);
18421 }
18422#endif
18423void GC_err_puts(const char *s)
18424{
18425 (void)WRITE(GC_stderr, s, strlen(s));
18426}
18427STATIC void GC_CALLBACK GC_default_warn_proc(char *msg, GC_word arg)
18428{
18429 GC_warn_printf(msg, arg);
18430}
18431GC_INNER GC_warn_proc GC_current_warn_proc = GC_default_warn_proc;
18432GC_API void GC_CALLBACK GC_ignore_warn_proc(char *msg, GC_word arg)
18433{
18434 if (GC_print_stats) {
18435 GC_default_warn_proc(msg, arg);
18436 }
18437}
18438GC_API void GC_CALL GC_set_warn_proc(GC_warn_proc p)
18439{
18440 DCL_LOCK_STATE;
18441 GC_ASSERT(NONNULL_ARG_NOT_NULL(p));
18442#ifdef GC_WIN32_THREADS
18443#ifdef CYGWIN32
18444 GC_ASSERT(GC_is_initialized);
18445#else
18446 if (!GC_is_initialized) GC_init();
18447#endif
18448#endif
18449 LOCK();
18450 GC_current_warn_proc = p;
18451 UNLOCK();
18452}
18453GC_API GC_warn_proc GC_CALL GC_get_warn_proc(void)
18454{
18455 GC_warn_proc result;
18456 DCL_LOCK_STATE;
18457 LOCK();
18458 result = GC_current_warn_proc;
18459 UNLOCK();
18460 return(result);
18461}
18462#if !defined(PCR) && !defined(SMALL_CONFIG)
18463 STATIC void GC_CALLBACK GC_default_on_abort(const char *msg)
18464 {
18465#ifndef DONT_USE_ATEXIT
18466 skip_gc_atexit = TRUE;
18467#endif
18468 if (msg != NULL) {
18469#ifdef MSGBOX_ON_ERROR
18470 GC_win32_MessageBoxA(msg, "Fatal error in GC", MB_ICONERROR | MB_OK);
18471#endif
18472#ifndef GC_ANDROID_LOG
18473#if defined(GC_WIN32_THREADS) && defined(GC_ASSERTIONS) \
18474 && ((defined(MSWIN32) && !defined(CONSOLE_LOG)) || defined(MSWINCE))
18475 if (!GC_write_disabled)
18476#endif
18477 {
18478 if (WRITE(GC_stderr, msg, strlen(msg)) >= 0)
18479 (void)WRITE(GC_stderr, "\n", 1);
18480 }
18481#else
18482 __android_log_assert("*" , GC_ANDROID_LOG_TAG, "%s\n", msg);
18483#endif
18484 }
18485#if !defined(NO_DEBUGGING) && !defined(GC_ANDROID_LOG)
18486 if (GETENV("GC_LOOP_ON_ABORT") != NULL) {
18487 for(;;) {
18488 }
18489 }
18490#endif
18491 }
18492 GC_abort_func GC_on_abort = GC_default_on_abort;
18493 GC_API void GC_CALL GC_set_abort_func(GC_abort_func fn)
18494 {
18495 DCL_LOCK_STATE;
18496 GC_ASSERT(NONNULL_ARG_NOT_NULL(fn));
18497 LOCK();
18498 GC_on_abort = fn;
18499 UNLOCK();
18500 }
18501 GC_API GC_abort_func GC_CALL GC_get_abort_func(void)
18502 {
18503 GC_abort_func fn;
18504 DCL_LOCK_STATE;
18505 LOCK();
18506 fn = GC_on_abort;
18507 UNLOCK();
18508 return fn;
18509 }
18510#endif
18511GC_API void GC_CALL GC_enable(void)
18512{
18513 DCL_LOCK_STATE;
18514 LOCK();
18515 GC_ASSERT(GC_dont_gc != 0);
18516 GC_dont_gc--;
18517 UNLOCK();
18518}
18519GC_API void GC_CALL GC_disable(void)
18520{
18521 DCL_LOCK_STATE;
18522 LOCK();
18523 GC_dont_gc++;
18524 UNLOCK();
18525}
18526GC_API int GC_CALL GC_is_disabled(void)
18527{
18528 return GC_dont_gc != 0;
18529}
18530GC_API void ** GC_CALL GC_new_free_list_inner(void)
18531{
18532 void *result;
18533 GC_ASSERT(I_HOLD_LOCK());
18534 result = GC_INTERNAL_MALLOC((MAXOBJGRANULES+1) * sizeof(ptr_t), PTRFREE);
18535 if (NULL == result) ABORT("Failed to allocate freelist for new kind");
18536 BZERO(result, (MAXOBJGRANULES+1)*sizeof(ptr_t));
18537 return (void **)result;
18538}
18539GC_API void ** GC_CALL GC_new_free_list(void)
18540{
18541 void ** result;
18542 DCL_LOCK_STATE;
18543 LOCK();
18544 result = GC_new_free_list_inner();
18545 UNLOCK();
18546 return result;
18547}
18548GC_API unsigned GC_CALL GC_new_kind_inner(void **fl, GC_word descr,
18549 int adjust, int clear)
18550{
18551 unsigned result = GC_n_kinds;
18552 GC_ASSERT(NONNULL_ARG_NOT_NULL(fl));
18553 GC_ASSERT(adjust == FALSE || adjust == TRUE);
18554 GC_ASSERT(clear == TRUE
18555 || (descr == 0 && adjust == FALSE && clear == FALSE));
18556 if (result < MAXOBJKINDS) {
18557 GC_ASSERT(result > 0);
18558 GC_n_kinds++;
18559 GC_obj_kinds[result].ok_freelist = fl;
18560 GC_obj_kinds[result].ok_reclaim_list = 0;
18561 GC_obj_kinds[result].ok_descriptor = descr;
18562 GC_obj_kinds[result].ok_relocate_descr = adjust;
18563 GC_obj_kinds[result].ok_init = (GC_bool)clear;
18564#ifdef ENABLE_DISCLAIM
18565 GC_obj_kinds[result].ok_mark_unconditionally = FALSE;
18566 GC_obj_kinds[result].ok_disclaim_proc = 0;
18567#endif
18568 } else {
18569 ABORT("Too many kinds");
18570 }
18571 return result;
18572}
18573GC_API unsigned GC_CALL GC_new_kind(void **fl, GC_word descr, int adjust,
18574 int clear)
18575{
18576 unsigned result;
18577 DCL_LOCK_STATE;
18578 LOCK();
18579 result = GC_new_kind_inner(fl, descr, adjust, clear);
18580 UNLOCK();
18581 return result;
18582}
18583GC_API unsigned GC_CALL GC_new_proc_inner(GC_mark_proc proc)
18584{
18585 unsigned result = GC_n_mark_procs;
18586 if (result < MAX_MARK_PROCS) {
18587 GC_n_mark_procs++;
18588 GC_mark_procs[result] = proc;
18589 } else {
18590 ABORT("Too many mark procedures");
18591 }
18592 return result;
18593}
18594GC_API unsigned GC_CALL GC_new_proc(GC_mark_proc proc)
18595{
18596 unsigned result;
18597 DCL_LOCK_STATE;
18598 LOCK();
18599 result = GC_new_proc_inner(proc);
18600 UNLOCK();
18601 return result;
18602}
18603GC_API void * GC_CALL GC_call_with_alloc_lock(GC_fn_type fn, void *client_data)
18604{
18605 void * result;
18606 DCL_LOCK_STATE;
18607#ifdef THREADS
18608 LOCK();
18609#endif
18610 result = (*fn)(client_data);
18611#ifdef THREADS
18612 UNLOCK();
18613#endif
18614 return(result);
18615}
18616GC_API void * GC_CALL GC_call_with_stack_base(GC_stack_base_func fn, void *arg)
18617{
18618 struct GC_stack_base base;
18619 void *result;
18620 base.mem_base = (void *)&base;
18621#ifdef IA64
18622 base.reg_base = (void *)GC_save_regs_in_stack();
18623#endif
18624 result = fn(&base, arg);
18625 GC_noop1(COVERT_DATAFLOW(&base));
18626 return result;
18627}
18628#ifndef THREADS
18629GC_INNER ptr_t GC_blocked_sp = NULL;
18630#ifdef IA64
18631 STATIC ptr_t GC_blocked_register_sp = NULL;
18632#endif
18633GC_INNER struct GC_traced_stack_sect_s *GC_traced_stack_sect = NULL;
18634GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn,
18635 void * client_data)
18636{
18637 struct GC_traced_stack_sect_s stacksect;
18638 GC_ASSERT(GC_is_initialized);
18639 if ((word)GC_stackbottom HOTTER_THAN (word)(&stacksect))
18640 GC_stackbottom = (ptr_t)COVERT_DATAFLOW(&stacksect);
18641 if (GC_blocked_sp == NULL) {
18642 client_data = fn(client_data);
18643 GC_noop1(COVERT_DATAFLOW(&stacksect));
18644 return client_data;
18645 }
18646 stacksect.saved_stack_ptr = GC_blocked_sp;
18647#ifdef IA64
18648 stacksect.backing_store_end = GC_save_regs_in_stack();
18649 stacksect.saved_backing_store_ptr = GC_blocked_register_sp;
18650#endif
18651 stacksect.prev = GC_traced_stack_sect;
18652 GC_blocked_sp = NULL;
18653 GC_traced_stack_sect = &stacksect;
18654 client_data = fn(client_data);
18655 GC_ASSERT(GC_blocked_sp == NULL);
18656 GC_ASSERT(GC_traced_stack_sect == &stacksect);
18657#if defined(CPPCHECK)
18658 GC_noop1((word)GC_traced_stack_sect - (word)GC_blocked_sp);
18659#endif
18660 GC_traced_stack_sect = stacksect.prev;
18661#ifdef IA64
18662 GC_blocked_register_sp = stacksect.saved_backing_store_ptr;
18663#endif
18664 GC_blocked_sp = stacksect.saved_stack_ptr;
18665 return client_data;
18666}
18667STATIC void GC_do_blocking_inner(ptr_t data, void * context GC_ATTR_UNUSED)
18668{
18669 struct blocking_data * d = (struct blocking_data *) data;
18670 GC_ASSERT(GC_is_initialized);
18671 GC_ASSERT(GC_blocked_sp == NULL);
18672#ifdef SPARC
18673 GC_blocked_sp = GC_save_regs_in_stack();
18674#else
18675 GC_blocked_sp = (ptr_t) &d;
18676#endif
18677#ifdef IA64
18678 GC_blocked_register_sp = GC_save_regs_in_stack();
18679#endif
18680 d -> client_data = (d -> fn)(d -> client_data);
18681#ifdef SPARC
18682 GC_ASSERT(GC_blocked_sp != NULL);
18683#else
18684 GC_ASSERT(GC_blocked_sp == (ptr_t)(&d));
18685#endif
18686#if defined(CPPCHECK)
18687 GC_noop1((word)GC_blocked_sp);
18688#endif
18689 GC_blocked_sp = NULL;
18690}
18691 GC_API void GC_CALL GC_set_stackbottom(void *gc_thread_handle,
18692 const struct GC_stack_base *sb)
18693 {
18694 GC_ASSERT(sb -> mem_base != NULL);
18695 GC_ASSERT(NULL == gc_thread_handle || &GC_stackbottom == gc_thread_handle);
18696 GC_ASSERT(NULL == GC_blocked_sp
18697 && NULL == GC_traced_stack_sect);
18698 (void)gc_thread_handle;
18699 GC_stackbottom = (char *)sb->mem_base;
18700#ifdef IA64
18701 GC_register_stackbottom = (ptr_t)sb->reg_base;
18702#endif
18703 }
18704 GC_API void * GC_CALL GC_get_my_stackbottom(struct GC_stack_base *sb)
18705 {
18706 GC_ASSERT(GC_is_initialized);
18707 sb -> mem_base = GC_stackbottom;
18708#ifdef IA64
18709 sb -> reg_base = GC_register_stackbottom;
18710#endif
18711 return &GC_stackbottom;
18712 }
18713#endif
18714GC_API void * GC_CALL GC_do_blocking(GC_fn_type fn, void * client_data)
18715{
18716 struct blocking_data my_data;
18717 my_data.fn = fn;
18718 my_data.client_data = client_data;
18719 GC_with_callee_saves_pushed(GC_do_blocking_inner, (ptr_t)(&my_data));
18720 return my_data.client_data;
18721}
18722#if !defined(NO_DEBUGGING)
18723 GC_API void GC_CALL GC_dump(void)
18724 {
18725 DCL_LOCK_STATE;
18726 LOCK();
18727 GC_dump_named(NULL);
18728 UNLOCK();
18729 }
18730 GC_API void GC_CALL GC_dump_named(const char *name)
18731 {
18732#ifndef NO_CLOCK
18733 CLOCK_TYPE current_time;
18734 GET_TIME(current_time);
18735#endif
18736 if (name != NULL) {
18737 GC_printf("***GC Dump %s\n", name);
18738 } else {
18739 GC_printf("***GC Dump collection #%lu\n", (unsigned long)GC_gc_no);
18740 }
18741#ifndef NO_CLOCK
18742 GC_printf("Time since GC init: %lu ms\n",
18743 MS_TIME_DIFF(current_time, GC_init_time));
18744#endif
18745 GC_printf("\n***Static roots:\n");
18746 GC_print_static_roots();
18747 GC_printf("\n***Heap sections:\n");
18748 GC_print_heap_sects();
18749 GC_printf("\n***Free blocks:\n");
18750 GC_print_hblkfreelist();
18751 GC_printf("\n***Blocks in use:\n");
18752 GC_print_block_list();
18753 }
18754#endif
18755static void block_add_size(struct hblk *h, word pbytes)
18756{
18757 hdr *hhdr = HDR(h);
18758 *(word *)pbytes += (WORDS_TO_BYTES(hhdr->hb_sz) + (HBLKSIZE - 1))
18759 & ~(word)(HBLKSIZE - 1);
18760}
18761GC_API size_t GC_CALL GC_get_memory_use(void)
18762{
18763 word bytes = 0;
18764 DCL_LOCK_STATE;
18765 LOCK();
18766 GC_apply_to_all_blocks(block_add_size, (word)(&bytes));
18767 UNLOCK();
18768 return (size_t)bytes;
18769}
18770GC_API GC_word GC_CALL GC_get_gc_no(void)
18771{
18772 return GC_gc_no;
18773}
18774#ifdef THREADS
18775 GC_API int GC_CALL GC_get_parallel(void)
18776 {
18777 return GC_parallel;
18778 }
18779 GC_API void GC_CALL GC_alloc_lock(void)
18780 {
18781 DCL_LOCK_STATE;
18782 LOCK();
18783 }
18784 GC_API void GC_CALL GC_alloc_unlock(void)
18785 {
18786 UNLOCK();
18787 }
18788 GC_INNER GC_on_thread_event_proc GC_on_thread_event = 0;
18789 GC_API void GC_CALL GC_set_on_thread_event(GC_on_thread_event_proc fn)
18790 {
18791 DCL_LOCK_STATE;
18792 LOCK();
18793 GC_on_thread_event = fn;
18794 UNLOCK();
18795 }
18796 GC_API GC_on_thread_event_proc GC_CALL GC_get_on_thread_event(void)
18797 {
18798 GC_on_thread_event_proc fn;
18799 DCL_LOCK_STATE;
18800 LOCK();
18801 fn = GC_on_thread_event;
18802 UNLOCK();
18803 return fn;
18804 }
18805#endif
18806GC_API void GC_CALL GC_set_oom_fn(GC_oom_func fn)
18807{
18808 GC_ASSERT(NONNULL_ARG_NOT_NULL(fn));
18809 DCL_LOCK_STATE;
18810 LOCK();
18811 GC_oom_fn = fn;
18812 UNLOCK();
18813}
18814GC_API GC_oom_func GC_CALL GC_get_oom_fn(void)
18815{
18816 GC_oom_func fn;
18817 DCL_LOCK_STATE;
18818 LOCK();
18819 fn = GC_oom_fn;
18820 UNLOCK();
18821 return fn;
18822}
18823GC_API void GC_CALL GC_set_on_heap_resize(GC_on_heap_resize_proc fn)
18824{
18825 DCL_LOCK_STATE;
18826 LOCK();
18827 GC_on_heap_resize = fn;
18828 UNLOCK();
18829}
18830GC_API GC_on_heap_resize_proc GC_CALL GC_get_on_heap_resize(void)
18831{
18832 GC_on_heap_resize_proc fn;
18833 DCL_LOCK_STATE;
18834 LOCK();
18835 fn = GC_on_heap_resize;
18836 UNLOCK();
18837 return fn;
18838}
18839GC_API void GC_CALL GC_set_finalizer_notifier(GC_finalizer_notifier_proc fn)
18840{
18841 DCL_LOCK_STATE;
18842 LOCK();
18843 GC_finalizer_notifier = fn;
18844 UNLOCK();
18845}
18846GC_API GC_finalizer_notifier_proc GC_CALL GC_get_finalizer_notifier(void)
18847{
18848 GC_finalizer_notifier_proc fn;
18849 DCL_LOCK_STATE;
18850 LOCK();
18851 fn = GC_finalizer_notifier;
18852 UNLOCK();
18853 return fn;
18854}
18855GC_API void GC_CALL GC_set_find_leak(int value)
18856{
18857 GC_find_leak = value;
18858}
18859GC_API int GC_CALL GC_get_find_leak(void)
18860{
18861 return GC_find_leak;
18862}
18863GC_API void GC_CALL GC_set_all_interior_pointers(int value)
18864{
18865 DCL_LOCK_STATE;
18866 GC_all_interior_pointers = value ? 1 : 0;
18867 if (GC_is_initialized) {
18868 LOCK();
18869 GC_initialize_offsets();
18870 if (!GC_all_interior_pointers)
18871 GC_bl_init_no_interiors();
18872 UNLOCK();
18873 }
18874}
18875GC_API int GC_CALL GC_get_all_interior_pointers(void)
18876{
18877 return GC_all_interior_pointers;
18878}
18879GC_API void GC_CALL GC_set_finalize_on_demand(int value)
18880{
18881 GC_ASSERT(value != -1);
18882 GC_finalize_on_demand = value;
18883}
18884GC_API int GC_CALL GC_get_finalize_on_demand(void)
18885{
18886 return GC_finalize_on_demand;
18887}
18888GC_API void GC_CALL GC_set_java_finalization(int value)
18889{
18890 GC_ASSERT(value != -1);
18891 GC_java_finalization = value;
18892}
18893GC_API int GC_CALL GC_get_java_finalization(void)
18894{
18895 return GC_java_finalization;
18896}
18897GC_API void GC_CALL GC_set_dont_expand(int value)
18898{
18899 GC_ASSERT(value != -1);
18900 GC_dont_expand = value;
18901}
18902GC_API int GC_CALL GC_get_dont_expand(void)
18903{
18904 return GC_dont_expand;
18905}
18906GC_API void GC_CALL GC_set_no_dls(int value)
18907{
18908 GC_ASSERT(value != -1);
18909 GC_no_dls = value;
18910}
18911GC_API int GC_CALL GC_get_no_dls(void)
18912{
18913 return GC_no_dls;
18914}
18915GC_API void GC_CALL GC_set_non_gc_bytes(GC_word value)
18916{
18917 GC_non_gc_bytes = value;
18918}
18919GC_API GC_word GC_CALL GC_get_non_gc_bytes(void)
18920{
18921 return GC_non_gc_bytes;
18922}
18923GC_API void GC_CALL GC_set_free_space_divisor(GC_word value)
18924{
18925 GC_ASSERT(value > 0);
18926 GC_free_space_divisor = value;
18927}
18928GC_API GC_word GC_CALL GC_get_free_space_divisor(void)
18929{
18930 return GC_free_space_divisor;
18931}
18932GC_API void GC_CALL GC_set_max_retries(GC_word value)
18933{
18934 GC_ASSERT((GC_signed_word)value != -1);
18935 GC_max_retries = value;
18936}
18937GC_API GC_word GC_CALL GC_get_max_retries(void)
18938{
18939 return GC_max_retries;
18940}
18941GC_API void GC_CALL GC_set_dont_precollect(int value)
18942{
18943 GC_ASSERT(value != -1);
18944 GC_dont_precollect = value;
18945}
18946GC_API int GC_CALL GC_get_dont_precollect(void)
18947{
18948 return GC_dont_precollect;
18949}
18950GC_API void GC_CALL GC_set_full_freq(int value)
18951{
18952 GC_ASSERT(value >= 0);
18953 GC_full_freq = value;
18954}
18955GC_API int GC_CALL GC_get_full_freq(void)
18956{
18957 return GC_full_freq;
18958}
18959GC_API void GC_CALL GC_set_time_limit(unsigned long value)
18960{
18961 GC_ASSERT((long)value != -1L);
18962 GC_time_limit = value;
18963}
18964GC_API unsigned long GC_CALL GC_get_time_limit(void)
18965{
18966 return GC_time_limit;
18967}
18968GC_API void GC_CALL GC_set_force_unmap_on_gcollect(int value)
18969{
18970 GC_force_unmap_on_gcollect = (GC_bool)value;
18971}
18972GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void)
18973{
18974 return (int)GC_force_unmap_on_gcollect;
18975}
18976GC_API void GC_CALL GC_abort_on_oom(void)
18977{
18978 GC_err_printf("Insufficient memory for the allocation\n");
18979 EXIT();
18980}
18981#ifdef THREADS
18982 GC_API void GC_CALL GC_stop_world_external(void)
18983 {
18984 GC_ASSERT(GC_is_initialized);
18985 LOCK();
18986#ifdef THREAD_LOCAL_ALLOC
18987 GC_ASSERT(!GC_world_stopped);
18988#endif
18989 STOP_WORLD();
18990#ifdef THREAD_LOCAL_ALLOC
18991 GC_world_stopped = TRUE;
18992#endif
18993 }
18994 GC_API void GC_CALL GC_start_world_external(void)
18995 {
18996#ifdef THREAD_LOCAL_ALLOC
18997 GC_ASSERT(GC_world_stopped);
18998 GC_world_stopped = FALSE;
18999#else
19000 GC_ASSERT(GC_is_initialized);
19001#endif
19002 START_WORLD();
19003 UNLOCK();
19004 }
19005#endif
19006#if !defined(OS2) && !defined(PCR) && !defined(AMIGA) && !defined(MACOS) \
19007 && !defined(MSWINCE) && !defined(SN_TARGET_ORBIS) \
19008 && !defined(SN_TARGET_PSP2) && !defined(__CC_ARM)
19009#include <sys/types.h>
19010#if !defined(MSWIN32) && !defined(MSWIN_XBOX1)
19011#include <unistd.h>
19012#endif
19013#endif
19014#include <stdio.h>
19015#if defined(MSWINCE) || defined(SN_TARGET_PS3)
19016#define SIGSEGV 0
19017#else
19018#include <signal.h>
19019#endif
19020#if defined(UNIX_LIKE) || defined(CYGWIN32) || defined(NACL) \
19021 || defined(SYMBIAN)
19022#include <fcntl.h>
19023#endif
19024#if defined(LINUX) || defined(LINUX_STACKBOTTOM)
19025#include <ctype.h>
19026#endif
19027#ifdef AMIGA
19028#define GC_AMIGA_DEF
19029#if !defined(GC_AMIGA_DEF) && !defined(GC_AMIGA_SB) && !defined(GC_AMIGA_DS) && !defined(GC_AMIGA_AM)
19030#include <stdio.h>
19031#include <signal.h>
19032#define GC_AMIGA_DEF
19033#define GC_AMIGA_SB
19034#define GC_AMIGA_DS
19035#define GC_AMIGA_AM
19036#endif
19037#ifdef GC_AMIGA_DEF
19038#ifndef __GNUC__
19039#include <exec/exec.h>
19040#endif
19041#include <proto/exec.h>
19042#include <proto/dos.h>
19043#include <dos/dosextens.h>
19044#include <workbench/startup.h>
19045#endif
19046#ifdef GC_AMIGA_SB
19047ptr_t GC_get_main_stack_base(void)
19048{
19049 struct Process *proc = (struct Process*)SysBase->ThisTask;
19050 if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS
19051 && proc->pr_CLI != NULL) {
19052 return (char *)proc->pr_ReturnAddr + sizeof(ULONG);
19053 } else {
19054 return (char *)proc->pr_Task.tc_SPUpper;
19055 }
19056}
19057#endif
19058#ifdef GC_AMIGA_DS
19059 void GC_register_data_segments(void)
19060 {
19061 struct Process *proc;
19062 struct CommandLineInterface *cli;
19063 BPTR myseglist;
19064 ULONG *data;
19065#ifdef __GNUC__
19066 ULONG dataSegSize;
19067 GC_bool found_segment = FALSE;
19068 extern char __data_size[];
19069 dataSegSize=__data_size+8;
19070#endif
19071 proc= (struct Process*)SysBase->ThisTask;
19072 myseglist = proc->pr_SegList;
19073 if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS) {
19074 if (proc->pr_CLI != NULL) {
19075 cli = BADDR(proc->pr_CLI);
19076 myseglist = cli->cli_Module;
19077 }
19078 } else {
19079 ABORT("Not a Process.");
19080 }
19081 if (myseglist == NULL) {
19082 ABORT("Arrrgh.. can't find segments, aborting");
19083 }
19084 for (data = (ULONG *)BADDR(myseglist); data != NULL;
19085 data = (ULONG *)BADDR(data[0])) {
19086 if ((ULONG)GC_register_data_segments < (ULONG)(&data[1])
19087 || (ULONG)GC_register_data_segments > (ULONG)(&data[1])
19088 + data[-1]) {
19089#ifdef __GNUC__
19090 if (dataSegSize == data[-1]) {
19091 found_segment = TRUE;
19092 }
19093#endif
19094 GC_add_roots_inner((char *)&data[1],
19095 ((char *)&data[1]) + data[-1], FALSE);
19096 }
19097 }
19098#ifdef __GNUC__
19099 if (!found_segment) {
19100 ABORT("Can`t find correct Segments.\nSolution: Use an newer version of ixemul.library");
19101 }
19102#endif
19103 }
19104#endif
19105#ifdef GC_AMIGA_AM
19106#ifndef GC_AMIGA_FASTALLOC
19107void *GC_amiga_allocwrapper(size_t size,void *(*AllocFunction)(size_t size2)){
19108 return (*AllocFunction)(size);
19109}
19110void *(*GC_amiga_allocwrapper_do)(size_t size,void *(*AllocFunction)(size_t size2))
19111 =GC_amiga_allocwrapper;
19112#else
19113void *GC_amiga_allocwrapper_firsttime(size_t size,void *(*AllocFunction)(size_t size2));
19114void *(*GC_amiga_allocwrapper_do)(size_t size,void *(*AllocFunction)(size_t size2))
19115 =GC_amiga_allocwrapper_firsttime;
19116struct GC_Amiga_AllocedMemoryHeader{
19117 ULONG size;
19118 struct GC_Amiga_AllocedMemoryHeader *next;
19119};
19120struct GC_Amiga_AllocedMemoryHeader *GC_AMIGAMEM=(struct GC_Amiga_AllocedMemoryHeader *)(int)~(NULL);
19121ULONG GC_AMIGA_MEMF = MEMF_FAST | MEMF_CLEAR;
19122#ifndef GC_AMIGA_ONLYFAST
19123BOOL GC_amiga_dontalloc=FALSE;
19124#endif
19125#ifdef GC_AMIGA_PRINTSTATS
19126int succ=0,succ2=0;
19127int nsucc=0,nsucc2=0;
19128int nullretries=0;
19129int numcollects=0;
19130int chipa=0;
19131int allochip=0;
19132int allocfast=0;
19133int cur0=0;
19134int cur1=0;
19135int cur10=0;
19136int cur50=0;
19137int cur150=0;
19138int cur151=0;
19139int ncur0=0;
19140int ncur1=0;
19141int ncur10=0;
19142int ncur50=0;
19143int ncur150=0;
19144int ncur151=0;
19145#endif
19146void GC_amiga_free_all_mem(void){
19147 struct GC_Amiga_AllocedMemoryHeader *gc_am=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(GC_AMIGAMEM));
19148#ifdef GC_AMIGA_PRINTSTATS
19149 printf("\n\n"
19150 "%d bytes of chip-mem, and %d bytes of fast-mem where allocated from the OS.\n",
19151 allochip,allocfast
19152 );
19153 printf(
19154 "%d bytes of chip-mem were returned from the GC_AMIGA_FASTALLOC supported allocating functions.\n",
19155 chipa
19156 );
19157 printf("\n");
19158 printf("GC_gcollect was called %d times to avoid returning NULL or start allocating with the MEMF_ANY flag.\n",numcollects);
19159 printf("%d of them was a success. (the others had to use allocation from the OS.)\n",nullretries);
19160 printf("\n");
19161 printf("Succeeded forcing %d gc-allocations (%d bytes) of chip-mem to be fast-mem.\n",succ,succ2);
19162 printf("Failed forcing %d gc-allocations (%d bytes) of chip-mem to be fast-mem.\n",nsucc,nsucc2);
19163 printf("\n");
19164 printf(
19165 "Number of retries before succeeding a chip->fast force:\n"
19166 "0: %d, 1: %d, 2-9: %d, 10-49: %d, 50-149: %d, >150: %d\n",
19167 cur0,cur1,cur10,cur50,cur150,cur151
19168 );
19169 printf(
19170 "Number of retries before giving up a chip->fast force:\n"
19171 "0: %d, 1: %d, 2-9: %d, 10-49: %d, 50-149: %d, >150: %d\n",
19172 ncur0,ncur1,ncur10,ncur50,ncur150,ncur151
19173 );
19174#endif
19175 while(gc_am!=NULL){
19176 struct GC_Amiga_AllocedMemoryHeader *temp = gc_am->next;
19177 FreeMem(gc_am,gc_am->size);
19178 gc_am=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(temp));
19179 }
19180}
19181#ifndef GC_AMIGA_ONLYFAST
19182char *chipmax;
19183size_t latestsize;
19184#endif
19185#ifdef GC_AMIGA_FASTALLOC
19186void *GC_amiga_get_mem(size_t size){
19187 struct GC_Amiga_AllocedMemoryHeader *gc_am;
19188#ifndef GC_AMIGA_ONLYFAST
19189 if(GC_amiga_dontalloc==TRUE){
19190 return NULL;
19191 }
19192 if(GC_AMIGA_MEMF==(MEMF_ANY|MEMF_CLEAR) && size>100000 && latestsize<50000) return NULL;
19193#endif
19194 gc_am=AllocMem((ULONG)(size + sizeof(struct GC_Amiga_AllocedMemoryHeader)),GC_AMIGA_MEMF);
19195 if(gc_am==NULL) return NULL;
19196 gc_am->next=GC_AMIGAMEM;
19197 gc_am->size=size + sizeof(struct GC_Amiga_AllocedMemoryHeader);
19198 GC_AMIGAMEM=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(gc_am));
19199#ifdef GC_AMIGA_PRINTSTATS
19200 if((char *)gc_am<chipmax){
19201 allochip+=size;
19202 }else{
19203 allocfast+=size;
19204 }
19205#endif
19206 return gc_am+1;
19207}
19208#endif
19209#ifndef GC_AMIGA_ONLYFAST
19210#ifdef GC_AMIGA_RETRY
19211void *GC_amiga_rec_alloc(size_t size,void *(*AllocFunction)(size_t size2),const int rec){
19212 void *ret;
19213 ret=(*AllocFunction)(size);
19214#ifdef GC_AMIGA_PRINTSTATS
19215 if((char *)ret>chipmax || ret==NULL){
19216 if(ret==NULL){
19217 nsucc++;
19218 nsucc2+=size;
19219 if(rec==0) ncur0++;
19220 if(rec==1) ncur1++;
19221 if(rec>1 && rec<10) ncur10++;
19222 if(rec>=10 && rec<50) ncur50++;
19223 if(rec>=50 && rec<150) ncur150++;
19224 if(rec>=150) ncur151++;
19225 }else{
19226 succ++;
19227 succ2+=size;
19228 if(rec==0) cur0++;
19229 if(rec==1) cur1++;
19230 if(rec>1 && rec<10) cur10++;
19231 if(rec>=10 && rec<50) cur50++;
19232 if(rec>=50 && rec<150) cur150++;
19233 if(rec>=150) cur151++;
19234 }
19235 }
19236#endif
19237 if (((char *)ret)<=chipmax && ret!=NULL && (rec<(size>500000?9:size/5000))){
19238 ret=GC_amiga_rec_alloc(size,AllocFunction,rec+1);
19239 }
19240 return ret;
19241}
19242#endif
19243void *GC_amiga_allocwrapper_any(size_t size,void *(*AllocFunction)(size_t size2)){
19244 void *ret;
19245 GC_amiga_dontalloc=TRUE;
19246 latestsize=size;
19247 ret=(*AllocFunction)(size);
19248 if(((char *)ret) <= chipmax){
19249 if(ret==NULL){
19250#ifdef GC_AMIGA_GC
19251 if(!GC_dont_gc){
19252 GC_gcollect();
19253#ifdef GC_AMIGA_PRINTSTATS
19254 numcollects++;
19255#endif
19256 ret=(*AllocFunction)(size);
19257 }
19258 if(ret==NULL)
19259#endif
19260 {
19261 GC_amiga_dontalloc=FALSE;
19262 ret=(*AllocFunction)(size);
19263 if(ret==NULL){
19264 WARN("Out of Memory! Returning NIL!\n", 0);
19265 }
19266 }
19267#ifdef GC_AMIGA_PRINTSTATS
19268 else{
19269 nullretries++;
19270 }
19271 if(ret!=NULL && (char *)ret<=chipmax) chipa+=size;
19272#endif
19273 }
19274#ifdef GC_AMIGA_RETRY
19275 else{
19276 void *ret2;
19277 if(
19278 AllocFunction!=GC_malloc_uncollectable
19279#ifdef GC_ATOMIC_UNCOLLECTABLE
19280 && AllocFunction!=GC_malloc_atomic_uncollectable
19281#endif
19282 ){
19283 ret2=GC_amiga_rec_alloc(size,AllocFunction,0);
19284 }else{
19285 ret2=(*AllocFunction)(size);
19286#ifdef GC_AMIGA_PRINTSTATS
19287 if((char *)ret2<chipmax || ret2==NULL){
19288 nsucc++;
19289 nsucc2+=size;
19290 ncur0++;
19291 }else{
19292 succ++;
19293 succ2+=size;
19294 cur0++;
19295 }
19296#endif
19297 }
19298 if(((char *)ret2)>chipmax){
19299 GC_free(ret);
19300 ret=ret2;
19301 }else{
19302 GC_free(ret2);
19303 }
19304 }
19305#endif
19306 }
19307#if defined(CPPCHECK)
19308 if (GC_amiga_dontalloc)
19309#endif
19310 GC_amiga_dontalloc=FALSE;
19311 return ret;
19312}
19313void (*GC_amiga_toany)(void)=NULL;
19314void GC_amiga_set_toany(void (*func)(void)){
19315 GC_amiga_toany=func;
19316}
19317#endif
19318void *GC_amiga_allocwrapper_fast(size_t size,void *(*AllocFunction)(size_t size2)){
19319 void *ret;
19320 ret=(*AllocFunction)(size);
19321 if(ret==NULL){
19322#ifdef GC_AMIGA_GC
19323 if(!GC_dont_gc){
19324 GC_gcollect();
19325#ifdef GC_AMIGA_PRINTSTATS
19326 numcollects++;
19327#endif
19328 ret=(*AllocFunction)(size);
19329 }
19330 if(ret==NULL)
19331#endif
19332 {
19333#ifndef GC_AMIGA_ONLYFAST
19334 GC_AMIGA_MEMF=MEMF_ANY | MEMF_CLEAR;
19335 if(GC_amiga_toany!=NULL) (*GC_amiga_toany)();
19336 GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_any;
19337 return GC_amiga_allocwrapper_any(size,AllocFunction);
19338#endif
19339 }
19340#ifdef GC_AMIGA_PRINTSTATS
19341 else{
19342 nullretries++;
19343 }
19344#endif
19345 }
19346 return ret;
19347}
19348void *GC_amiga_allocwrapper_firsttime(size_t size,void *(*AllocFunction)(size_t size2)){
19349 atexit(&GC_amiga_free_all_mem);
19350 chipmax=(char *)SysBase->MaxLocMem;
19351 GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_fast;
19352 return GC_amiga_allocwrapper_fast(size,AllocFunction);
19353}
19354#endif
19355void *GC_amiga_realloc(void *old_object,size_t new_size_in_bytes){
19356#ifndef GC_AMIGA_FASTALLOC
19357 return GC_realloc(old_object,new_size_in_bytes);
19358#else
19359 void *ret;
19360 latestsize=new_size_in_bytes;
19361 ret=GC_realloc(old_object,new_size_in_bytes);
19362 if(ret==NULL && new_size_in_bytes != 0
19363 && GC_AMIGA_MEMF==(MEMF_FAST | MEMF_CLEAR)){
19364#ifdef GC_AMIGA_GC
19365 if(!GC_dont_gc){
19366 GC_gcollect();
19367#ifdef GC_AMIGA_PRINTSTATS
19368 numcollects++;
19369#endif
19370 ret=GC_realloc(old_object,new_size_in_bytes);
19371 }
19372 if(ret==NULL)
19373#endif
19374 {
19375#ifndef GC_AMIGA_ONLYFAST
19376 GC_AMIGA_MEMF=MEMF_ANY | MEMF_CLEAR;
19377 if(GC_amiga_toany!=NULL) (*GC_amiga_toany)();
19378 GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_any;
19379 ret=GC_realloc(old_object,new_size_in_bytes);
19380#endif
19381 }
19382#ifdef GC_AMIGA_PRINTSTATS
19383 else{
19384 nullretries++;
19385 }
19386#endif
19387 }
19388 if(ret==NULL && new_size_in_bytes != 0){
19389 WARN("Out of Memory! Returning NIL!\n", 0);
19390 }
19391#ifdef GC_AMIGA_PRINTSTATS
19392 if(((char *)ret)<chipmax && ret!=NULL){
19393 chipa+=new_size_in_bytes;
19394 }
19395#endif
19396 return ret;
19397#endif
19398}
19399#endif
19400#undef GC_AMIGA_DEF
19401#endif
19402#ifdef MACOS
19403#include <Processes.h>
19404#endif
19405#ifdef IRIX5
19406#include <sys/uio.h>
19407#include <malloc.h>
19408#endif
19409#if defined(MMAP_SUPPORTED) || defined(ADD_HEAP_GUARD_PAGES)
19410#if defined(USE_MUNMAP) && !defined(USE_MMAP) && !defined(CPPCHECK)
19411#error Invalid config: USE_MUNMAP requires USE_MMAP
19412#endif
19413#include <sys/types.h>
19414#include <sys/mman.h>
19415#include <sys/stat.h>
19416#endif
19417#if defined(ADD_HEAP_GUARD_PAGES) || defined(LINUX_STACKBOTTOM) \
19418 || defined(MMAP_SUPPORTED) || defined(NEED_PROC_MAPS)
19419#include <errno.h>
19420#endif
19421#ifdef DARWIN
19422#include <mach-o/getsect.h>
19423#endif
19424#ifdef DJGPP
19425 typedef long unsigned int caddr_t;
19426#endif
19427#ifdef PCR
19428#include "mm/PCR_MM.h"
19429#endif
19430#if defined(GC_DARWIN_THREADS) && defined(MPROTECT_VDB)
19431#ifndef GC_DARWIN_STOP_WORLD_H
19432#define GC_DARWIN_STOP_WORLD_H
19433#if !defined(GC_DARWIN_THREADS)
19434#error darwin_stop_world.h included without GC_DARWIN_THREADS defined
19435#endif
19436#include <mach/mach.h>
19437#include <mach/thread_act.h>
19438EXTERN_C_BEGIN
19439struct thread_stop_info {
19440 mach_port_t mach_thread;
19441 ptr_t stack_ptr;
19442};
19443#ifndef DARWIN_DONT_PARSE_STACK
19444 GC_INNER ptr_t GC_FindTopOfStack(unsigned long);
19445#endif
19446#ifdef MPROTECT_VDB
19447 GC_INNER void GC_mprotect_stop(void);
19448 GC_INNER void GC_mprotect_resume(void);
19449#ifndef GC_NO_THREADS_DISCOVERY
19450 GC_INNER void GC_darwin_register_mach_handler_thread(mach_port_t thread);
19451#endif
19452#endif
19453#if defined(PARALLEL_MARK) && !defined(GC_NO_THREADS_DISCOVERY)
19454 GC_INNER GC_bool GC_is_mach_marker(thread_act_t);
19455#endif
19456EXTERN_C_END
19457#endif
19458#endif
19459#if !defined(NO_EXECUTE_PERMISSION)
19460 STATIC GC_bool GC_pages_executable = TRUE;
19461#else
19462 STATIC GC_bool GC_pages_executable = FALSE;
19463#endif
19464#define IGNORE_PAGES_EXECUTABLE 1
19465#if ((defined(LINUX_STACKBOTTOM) || defined(NEED_PROC_MAPS) \
19466 || defined(PROC_VDB) || defined(SOFT_VDB)) && !defined(PROC_READ)) \
19467 || defined(CPPCHECK)
19468#define PROC_READ read
19469#endif
19470#if defined(LINUX_STACKBOTTOM) || defined(NEED_PROC_MAPS)
19471 STATIC ssize_t GC_repeat_read(int fd, char *buf, size_t count)
19472 {
19473 size_t num_read = 0;
19474 ASSERT_CANCEL_DISABLED();
19475 while (num_read < count) {
19476 ssize_t result = PROC_READ(fd, buf + num_read, count - num_read);
19477 if (result < 0) return result;
19478 if (result == 0) break;
19479 num_read += result;
19480 }
19481 return num_read;
19482 }
19483#endif
19484#ifdef NEED_PROC_MAPS
19485#ifdef THREADS
19486 STATIC size_t GC_get_file_len(int f)
19487 {
19488 size_t total = 0;
19489 ssize_t result;
19490#define GET_FILE_LEN_BUF_SZ 500
19491 char buf[GET_FILE_LEN_BUF_SZ];
19492 do {
19493 result = PROC_READ(f, buf, sizeof(buf));
19494 if (result == -1) return 0;
19495 total += result;
19496 } while (result > 0);
19497 return total;
19498 }
19499 STATIC size_t GC_get_maps_len(void)
19500 {
19501 int f = open("/proc/self/maps", O_RDONLY);
19502 size_t result;
19503 if (f < 0) return 0;
19504 result = GC_get_file_len(f);
19505 close(f);
19506 return result;
19507 }
19508#endif
19509GC_INNER const char * GC_get_maps(void)
19510{
19511 ssize_t result;
19512 static char *maps_buf = NULL;
19513 static size_t maps_buf_sz = 1;
19514 size_t maps_size;
19515#ifdef THREADS
19516 size_t old_maps_size = 0;
19517#endif
19518 GC_ASSERT(I_HOLD_LOCK());
19519#ifdef THREADS
19520 maps_size = GC_get_maps_len();
19521 if (0 == maps_size)
19522 ABORT("Cannot determine length of /proc/self/maps");
19523#else
19524 maps_size = 4000;
19525#endif
19526 do {
19527 int f;
19528 while (maps_size >= maps_buf_sz) {
19529#ifdef LINT2
19530 GC_noop1((word)maps_buf);
19531#else
19532 GC_scratch_recycle_no_gww(maps_buf, maps_buf_sz);
19533#endif
19534 while (maps_size >= maps_buf_sz) maps_buf_sz *= 2;
19535 maps_buf = GC_scratch_alloc(maps_buf_sz);
19536 if (NULL == maps_buf)
19537 ABORT_ARG1("Insufficient space for /proc/self/maps buffer",
19538 ", %lu bytes requested", (unsigned long)maps_buf_sz);
19539#ifdef THREADS
19540 maps_size = GC_get_maps_len();
19541 if (0 == maps_size)
19542 ABORT("Cannot determine length of /proc/self/maps");
19543#endif
19544 }
19545 GC_ASSERT(maps_buf_sz >= maps_size + 1);
19546 f = open("/proc/self/maps", O_RDONLY);
19547 if (-1 == f)
19548 ABORT_ARG1("Cannot open /proc/self/maps",
19549 ": errno= %d", errno);
19550#ifdef THREADS
19551 old_maps_size = maps_size;
19552#endif
19553 maps_size = 0;
19554 do {
19555 result = GC_repeat_read(f, maps_buf, maps_buf_sz-1);
19556 if (result <= 0) {
19557 ABORT_ARG1("Failed to read /proc/self/maps",
19558 ": errno= %d", result < 0 ? errno : 0);
19559 }
19560 maps_size += result;
19561 } while ((size_t)result == maps_buf_sz-1);
19562 close(f);
19563#ifdef THREADS
19564 if (maps_size > old_maps_size) {
19565 WARN("Unexpected asynchronous /proc/self/maps growth"
19566 " (to %" WARN_PRIdPTR " bytes)\n", maps_size);
19567 }
19568#endif
19569 } while (maps_size >= maps_buf_sz
19570#ifdef THREADS
19571 || maps_size < old_maps_size
19572#endif
19573 );
19574 maps_buf[maps_size] = '\0';
19575 return maps_buf;
19576}
19577#if (defined(DYNAMIC_LOADING) && defined(USE_PROC_FOR_LIBRARIES)) \
19578 || defined(IA64) || defined(INCLUDE_LINUX_THREAD_DESCR) \
19579 || defined(REDIRECT_MALLOC)
19580 GC_INNER const char *GC_parse_map_entry(const char *maps_ptr,
19581 ptr_t *start, ptr_t *end,
19582 const char **prot, unsigned *maj_dev,
19583 const char **mapping_name)
19584 {
19585 const unsigned char *start_start, *end_start, *maj_dev_start;
19586 const unsigned char *p;
19587 if (maps_ptr == NULL || *maps_ptr == '\0') {
19588 return NULL;
19589 }
19590 p = (const unsigned char *)maps_ptr;
19591 while (isspace(*p)) ++p;
19592 start_start = p;
19593 GC_ASSERT(isxdigit(*start_start));
19594 *start = (ptr_t)strtoul((const char *)start_start, (char **)&p, 16);
19595 GC_ASSERT(*p=='-');
19596 ++p;
19597 end_start = p;
19598 GC_ASSERT(isxdigit(*end_start));
19599 *end = (ptr_t)strtoul((const char *)end_start, (char **)&p, 16);
19600 GC_ASSERT(isspace(*p));
19601 while (isspace(*p)) ++p;
19602 GC_ASSERT(*p == 'r' || *p == '-');
19603 *prot = (const char *)p;
19604 while (!isspace(*p)) ++p;
19605 while (isspace(*p)) p++;
19606 GC_ASSERT(isxdigit(*p));
19607 while (!isspace(*p)) ++p;
19608 while (isspace(*p)) p++;
19609 maj_dev_start = p;
19610 GC_ASSERT(isxdigit(*maj_dev_start));
19611 *maj_dev = strtoul((const char *)maj_dev_start, NULL, 16);
19612 if (mapping_name != NULL) {
19613 while (*p && *p != '\n' && *p != '/' && *p != '[') p++;
19614 *mapping_name = (const char *)p;
19615 }
19616 while (*p && *p++ != '\n');
19617 return (const char *)p;
19618 }
19619#endif
19620#if defined(IA64) || defined(INCLUDE_LINUX_THREAD_DESCR)
19621 GC_INNER GC_bool GC_enclosing_mapping(ptr_t addr, ptr_t *startp,
19622 ptr_t *endp)
19623 {
19624 const char *prot;
19625 ptr_t my_start, my_end;
19626 unsigned int maj_dev;
19627 const char *maps_ptr = GC_get_maps();
19628 for (;;) {
19629 maps_ptr = GC_parse_map_entry(maps_ptr, &my_start, &my_end,
19630 &prot, &maj_dev, 0);
19631 if (NULL == maps_ptr) break;
19632 if (prot[1] == 'w' && maj_dev == 0
19633 && (word)my_end > (word)addr && (word)my_start <= (word)addr) {
19634 *startp = my_start;
19635 *endp = my_end;
19636 return TRUE;
19637 }
19638 }
19639 return FALSE;
19640 }
19641#endif
19642#if defined(REDIRECT_MALLOC)
19643 GC_INNER GC_bool GC_text_mapping(char *nm, ptr_t *startp, ptr_t *endp)
19644 {
19645 size_t nm_len = strlen(nm);
19646 const char *prot, *map_path;
19647 ptr_t my_start, my_end;
19648 unsigned int maj_dev;
19649 const char *maps_ptr = GC_get_maps();
19650 for (;;) {
19651 maps_ptr = GC_parse_map_entry(maps_ptr, &my_start, &my_end,
19652 &prot, &maj_dev, &map_path);
19653 if (NULL == maps_ptr) break;
19654 if (prot[0] == 'r' && prot[1] == '-' && prot[2] == 'x') {
19655 const char *p = map_path;
19656 while (*p != '\0' && *p != '\n' && *p != ' ' && *p != '\t') ++p;
19657 while (*p != '/' && (word)p >= (word)map_path) --p;
19658 ++p;
19659 if (strncmp(nm, p, nm_len) == 0) {
19660 *startp = my_start;
19661 *endp = my_end;
19662 return TRUE;
19663 }
19664 }
19665 }
19666 return FALSE;
19667 }
19668#endif
19669#ifdef IA64
19670 static ptr_t backing_store_base_from_proc(void)
19671 {
19672 ptr_t my_start, my_end;
19673 if (!GC_enclosing_mapping(GC_save_regs_in_stack(), &my_start, &my_end)) {
19674 GC_COND_LOG_PRINTF("Failed to find backing store base from /proc\n");
19675 return 0;
19676 }
19677 return my_start;
19678 }
19679#endif
19680#endif
19681#if defined(SEARCH_FOR_DATA_START)
19682#if defined(LINUX) || defined(HURD)
19683 EXTERN_C_BEGIN
19684#pragma weak __data_start
19685#pragma weak data_start
19686 extern int __data_start[], data_start[];
19687 EXTERN_C_END
19688#endif
19689 ptr_t GC_data_start = NULL;
19690 GC_INNER void GC_init_linux_data_start(void)
19691 {
19692 ptr_t data_end = DATAEND;
19693#if (defined(LINUX) || defined(HURD)) && defined(USE_PROG_DATA_START)
19694 if (COVERT_DATAFLOW(__data_start) != 0) {
19695 GC_data_start = (ptr_t)(__data_start);
19696 } else {
19697 GC_data_start = (ptr_t)(data_start);
19698 }
19699 if (COVERT_DATAFLOW(GC_data_start) != 0) {
19700 if ((word)GC_data_start > (word)data_end)
19701 ABORT_ARG2("Wrong __data_start/_end pair",
19702 ": %p .. %p", (void *)GC_data_start, (void *)data_end);
19703 return;
19704 }
19705#ifdef DEBUG_ADD_DEL_ROOTS
19706 GC_log_printf("__data_start not provided\n");
19707#endif
19708#endif
19709 if (GC_no_dls) {
19710 GC_data_start = data_end;
19711 return;
19712 }
19713 GC_data_start = (ptr_t)GC_find_limit(data_end, FALSE);
19714 }
19715#endif
19716#ifdef ECOS
19717#ifndef ECOS_GC_MEMORY_SIZE
19718#define ECOS_GC_MEMORY_SIZE (448 * 1024)
19719#endif
19720 static char ecos_gc_memory[ECOS_GC_MEMORY_SIZE];
19721 static char *ecos_gc_brk = ecos_gc_memory;
19722 static void *tiny_sbrk(ptrdiff_t increment)
19723 {
19724 void *p = ecos_gc_brk;
19725 ecos_gc_brk += increment;
19726 if ((word)ecos_gc_brk > (word)(ecos_gc_memory + sizeof(ecos_gc_memory))) {
19727 ecos_gc_brk -= increment;
19728 return NULL;
19729 }
19730 return p;
19731 }
19732#define sbrk tiny_sbrk
19733#endif
19734#if defined(NETBSD) && defined(__ELF__)
19735 ptr_t GC_data_start = NULL;
19736 EXTERN_C_BEGIN
19737 extern char **environ;
19738 EXTERN_C_END
19739 GC_INNER void GC_init_netbsd_elf(void)
19740 {
19741 GC_data_start = (ptr_t)GC_find_limit(&environ, FALSE);
19742 }
19743#endif
19744#if defined(ADDRESS_SANITIZER) && (defined(UNIX_LIKE) \
19745 || defined(NEED_FIND_LIMIT) || defined(MPROTECT_VDB)) \
19746 && !defined(CUSTOM_ASAN_DEF_OPTIONS)
19747 GC_API const char *__asan_default_options(void)
19748 {
19749 return "allow_user_segv_handler=1";
19750 }
19751#endif
19752#ifdef OPENBSD
19753 static struct sigaction old_segv_act;
19754 STATIC JMP_BUF GC_jmp_buf_openbsd;
19755 STATIC void GC_fault_handler_openbsd(int sig GC_ATTR_UNUSED)
19756 {
19757 LONGJMP(GC_jmp_buf_openbsd, 1);
19758 }
19759#ifdef GC_OPENBSD_UTHREADS
19760#include <sys/syscall.h>
19761 EXTERN_C_BEGIN
19762 extern sigset_t __syscall(quad_t, ...);
19763 EXTERN_C_END
19764 STATIC ptr_t GC_find_limit_openbsd(ptr_t p, ptr_t bound)
19765 {
19766 static volatile ptr_t result;
19767 struct sigaction act;
19768 word pgsz = (word)sysconf(_SC_PAGESIZE);
19769 GC_ASSERT((word)bound >= pgsz);
19770 GC_ASSERT(I_HOLD_LOCK());
19771 act.sa_handler = GC_fault_handler_openbsd;
19772 sigemptyset(&act.sa_mask);
19773 act.sa_flags = SA_NODEFER | SA_RESTART;
19774 sigaction(SIGSEGV, &act, &old_segv_act);
19775 if (SETJMP(GC_jmp_buf_openbsd) == 0) {
19776 result = (ptr_t)((word)p & ~(pgsz-1));
19777 for (;;) {
19778 if ((word)result >= (word)bound - pgsz) {
19779 result = bound;
19780 break;
19781 }
19782 result += pgsz;
19783 GC_noop1((word)(*result));
19784 }
19785 }
19786#ifdef THREADS
19787 __syscall(SYS_sigprocmask, SIG_UNBLOCK, sigmask(SIGPROF));
19788#endif
19789 sigaction(SIGSEGV, &old_segv_act, 0);
19790 return(result);
19791 }
19792#endif
19793 static volatile int firstpass;
19794 STATIC ptr_t GC_skip_hole_openbsd(ptr_t p, ptr_t bound)
19795 {
19796 static volatile ptr_t result;
19797 struct sigaction act;
19798 word pgsz = (word)sysconf(_SC_PAGESIZE);
19799 GC_ASSERT((word)bound >= pgsz);
19800 GC_ASSERT(I_HOLD_LOCK());
19801 act.sa_handler = GC_fault_handler_openbsd;
19802 sigemptyset(&act.sa_mask);
19803 act.sa_flags = SA_NODEFER | SA_RESTART;
19804 sigaction(SIGSEGV, &act, &old_segv_act);
19805 firstpass = 1;
19806 result = (ptr_t)((word)p & ~(pgsz-1));
19807 if (SETJMP(GC_jmp_buf_openbsd) != 0 || firstpass) {
19808 firstpass = 0;
19809 if ((word)result >= (word)bound - pgsz) {
19810 result = bound;
19811 } else {
19812 result += pgsz;
19813 GC_noop1((word)(*result));
19814 }
19815 }
19816 sigaction(SIGSEGV, &old_segv_act, 0);
19817 return(result);
19818 }
19819#endif
19820#ifdef OS2
19821#include <stddef.h>
19822#if !defined(__IBMC__) && !defined(__WATCOMC__)
19823struct exe_hdr {
19824 unsigned short magic_number;
19825 unsigned short padding[29];
19826 long new_exe_offset;
19827};
19828#define E_MAGIC(x) (x).magic_number
19829#define EMAGIC 0x5A4D
19830#define E_LFANEW(x) (x).new_exe_offset
19831struct e32_exe {
19832 unsigned char magic_number[2];
19833 unsigned char byte_order;
19834 unsigned char word_order;
19835 unsigned long exe_format_level;
19836 unsigned short cpu;
19837 unsigned short os;
19838 unsigned long padding1[13];
19839 unsigned long object_table_offset;
19840 unsigned long object_count;
19841 unsigned long padding2[31];
19842};
19843#define E32_MAGIC1(x) (x).magic_number[0]
19844#define E32MAGIC1 'L'
19845#define E32_MAGIC2(x) (x).magic_number[1]
19846#define E32MAGIC2 'X'
19847#define E32_BORDER(x) (x).byte_order
19848#define E32LEBO 0
19849#define E32_WORDER(x) (x).word_order
19850#define E32LEWO 0
19851#define E32_CPU(x) (x).cpu
19852#define E32CPU286 1
19853#define E32_OBJTAB(x) (x).object_table_offset
19854#define E32_OBJCNT(x) (x).object_count
19855struct o32_obj {
19856 unsigned long size;
19857 unsigned long base;
19858 unsigned long flags;
19859 unsigned long pagemap;
19860 unsigned long mapsize;
19861 unsigned long reserved;
19862};
19863#define O32_FLAGS(x) (x).flags
19864#define OBJREAD 0x0001L
19865#define OBJWRITE 0x0002L
19866#define OBJINVALID 0x0080L
19867#define O32_SIZE(x) (x).size
19868#define O32_BASE(x) (x).base
19869#else
19870#ifndef WORD
19871#define WORD unsigned short
19872#endif
19873#ifndef DWORD
19874#define DWORD unsigned long
19875#endif
19876#define EXE386 1
19877#include <newexe.h>
19878#include <exe386.h>
19879#endif
19880#define INCL_DOSEXCEPTIONS
19881#define INCL_DOSPROCESS
19882#define INCL_DOSERRORS
19883#define INCL_DOSMODULEMGR
19884#define INCL_DOSMEMMGR
19885#include <os2.h>
19886#endif
19887GC_INNER size_t GC_page_size = 0;
19888#if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
19889#ifndef VER_PLATFORM_WIN32_CE
19890#define VER_PLATFORM_WIN32_CE 3
19891#endif
19892#if defined(MSWINCE) && defined(THREADS)
19893 GC_INNER GC_bool GC_dont_query_stack_min = FALSE;
19894#endif
19895 GC_INNER SYSTEM_INFO GC_sysinfo;
19896 GC_INNER void GC_setpagesize(void)
19897 {
19898 GetSystemInfo(&GC_sysinfo);
19899#if defined(CYGWIN32) && (defined(MPROTECT_VDB) || defined(USE_MUNMAP))
19900 GC_page_size = (size_t)GC_sysinfo.dwAllocationGranularity;
19901 GC_ASSERT(GC_page_size >= (size_t)GC_sysinfo.dwPageSize);
19902#else
19903 GC_page_size = (size_t)GC_sysinfo.dwPageSize;
19904#endif
19905#if defined(MSWINCE) && !defined(_WIN32_WCE_EMULATION)
19906 {
19907 OSVERSIONINFO verInfo;
19908 verInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
19909 if (!GetVersionEx(&verInfo))
19910 ABORT("GetVersionEx failed");
19911 if (verInfo.dwPlatformId == VER_PLATFORM_WIN32_CE &&
19912 verInfo.dwMajorVersion < 6) {
19913 GC_sysinfo.lpMaximumApplicationAddress = (LPVOID)((word)32 << 20);
19914#ifdef THREADS
19915 if (verInfo.dwMajorVersion < 5)
19916 GC_dont_query_stack_min = TRUE;
19917#endif
19918 }
19919 }
19920#endif
19921 }
19922#ifndef CYGWIN32
19923#define is_writable(prot) ((prot) == PAGE_READWRITE \
19924 || (prot) == PAGE_WRITECOPY \
19925 || (prot) == PAGE_EXECUTE_READWRITE \
19926 || (prot) == PAGE_EXECUTE_WRITECOPY)
19927 STATIC word GC_get_writable_length(ptr_t p, ptr_t *base)
19928 {
19929 MEMORY_BASIC_INFORMATION buf;
19930 word result;
19931 word protect;
19932 result = VirtualQuery(p, &buf, sizeof(buf));
19933 if (result != sizeof(buf)) ABORT("Weird VirtualQuery result");
19934 if (base != 0) *base = (ptr_t)(buf.AllocationBase);
19935 protect = (buf.Protect & ~(PAGE_GUARD | PAGE_NOCACHE));
19936 if (!is_writable(protect)) {
19937 return(0);
19938 }
19939 if (buf.State != MEM_COMMIT) return(0);
19940 return(buf.RegionSize);
19941 }
19942 GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *sb)
19943 {
19944 ptr_t trunc_sp;
19945 word size;
19946 if (!GC_page_size) GC_setpagesize();
19947 trunc_sp = (ptr_t)((word)GC_approx_sp() & ~(GC_page_size - 1));
19948 size = GC_get_writable_length(trunc_sp, 0);
19949 GC_ASSERT(size != 0);
19950 sb -> mem_base = trunc_sp + size;
19951 return GC_SUCCESS;
19952 }
19953#else
19954 GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *sb)
19955 {
19956#ifdef X86_64
19957 sb -> mem_base = ((NT_TIB*)NtCurrentTeb())->StackBase;
19958#else
19959 void * _tlsbase;
19960 __asm__ ("movl %%fs:4, %0"
19961 : "=r" (_tlsbase));
19962 sb -> mem_base = _tlsbase;
19963#endif
19964 return GC_SUCCESS;
19965 }
19966#endif
19967#define HAVE_GET_STACK_BASE
19968#else
19969 GC_INNER void GC_setpagesize(void)
19970 {
19971#if defined(MPROTECT_VDB) || defined(PROC_VDB) || defined(SOFT_VDB) \
19972 || defined(USE_MMAP)
19973 GC_page_size = (size_t)GETPAGESIZE();
19974#if !defined(CPPCHECK)
19975 if (0 == GC_page_size)
19976 ABORT("getpagesize failed");
19977#endif
19978#else
19979 GC_page_size = HBLKSIZE;
19980#endif
19981 }
19982#endif
19983#ifdef HAIKU
19984#include <kernel/OS.h>
19985 GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *sb)
19986 {
19987 thread_info th;
19988 get_thread_info(find_thread(NULL),&th);
19989 sb->mem_base = th.stack_end;
19990 return GC_SUCCESS;
19991 }
19992#define HAVE_GET_STACK_BASE
19993#endif
19994#ifdef OS2
19995 GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *sb)
19996 {
19997 PTIB ptib;
19998 PPIB ppib;
19999 if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
20000 WARN("DosGetInfoBlocks failed\n", 0);
20001 return GC_UNIMPLEMENTED;
20002 }
20003 sb->mem_base = ptib->tib_pstacklimit;
20004 return GC_SUCCESS;
20005 }
20006#define HAVE_GET_STACK_BASE
20007#endif
20008#ifdef AMIGA
20009#define GC_AMIGA_SB
20010#undef GC_AMIGA_SB
20011#define GET_MAIN_STACKBASE_SPECIAL
20012#endif
20013#if defined(NEED_FIND_LIMIT) || defined(UNIX_LIKE)
20014 typedef void (*GC_fault_handler_t)(int);
20015#if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) \
20016 || defined(HAIKU) || defined(HURD) || defined(FREEBSD) \
20017 || defined(NETBSD)
20018 static struct sigaction old_segv_act;
20019#if defined(_sigargs) \
20020 || defined(HURD) || defined(NETBSD) || defined(FREEBSD)
20021 static struct sigaction old_bus_act;
20022#endif
20023#else
20024 static GC_fault_handler_t old_segv_handler;
20025#ifdef HAVE_SIGBUS
20026 static GC_fault_handler_t old_bus_handler;
20027#endif
20028#endif
20029 GC_INNER void GC_set_and_save_fault_handler(GC_fault_handler_t h)
20030 {
20031#if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) \
20032 || defined(HAIKU) || defined(HURD) || defined(FREEBSD) \
20033 || defined(NETBSD) || defined(OPENBSD)
20034 struct sigaction act;
20035 act.sa_handler = h;
20036#ifdef SIGACTION_FLAGS_NODEFER_HACK
20037 act.sa_flags = SA_RESTART | SA_NODEFER;
20038#else
20039 act.sa_flags = SA_RESTART;
20040#endif
20041 (void) sigemptyset(&act.sa_mask);
20042#ifdef GC_IRIX_THREADS
20043 (void) sigaction(SIGSEGV, 0, &old_segv_act);
20044 (void) sigaction(SIGSEGV, &act, 0);
20045#else
20046 (void) sigaction(SIGSEGV, &act, &old_segv_act);
20047#if defined(IRIX5) && defined(_sigargs) \
20048 || defined(HURD) || defined(NETBSD) || defined(FREEBSD)
20049 (void) sigaction(SIGBUS, &act, &old_bus_act);
20050#endif
20051#endif
20052#else
20053 old_segv_handler = signal(SIGSEGV, h);
20054#ifdef HAVE_SIGBUS
20055 old_bus_handler = signal(SIGBUS, h);
20056#endif
20057#endif
20058#if defined(CPPCHECK) && defined(ADDRESS_SANITIZER)
20059 GC_noop1((word)&__asan_default_options);
20060#endif
20061 }
20062#endif
20063#if defined(NEED_FIND_LIMIT) \
20064 || (defined(USE_PROC_FOR_LIBRARIES) && defined(THREADS))
20065#define MIN_PAGE_SIZE 256
20066 GC_INNER JMP_BUF GC_jmp_buf;
20067 STATIC void GC_fault_handler(int sig GC_ATTR_UNUSED)
20068 {
20069 LONGJMP(GC_jmp_buf, 1);
20070 }
20071 GC_INNER void GC_setup_temporary_fault_handler(void)
20072 {
20073 GC_ASSERT(I_HOLD_LOCK());
20074 GC_set_and_save_fault_handler(GC_fault_handler);
20075 }
20076 GC_INNER void GC_reset_fault_handler(void)
20077 {
20078#if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) \
20079 || defined(HAIKU) || defined(HURD) || defined(FREEBSD) \
20080 || defined(NETBSD) || defined(OPENBSD)
20081 (void) sigaction(SIGSEGV, &old_segv_act, 0);
20082#if defined(IRIX5) && defined(_sigargs) \
20083 || defined(HURD) || defined(NETBSD)
20084 (void) sigaction(SIGBUS, &old_bus_act, 0);
20085#endif
20086#else
20087 (void) signal(SIGSEGV, old_segv_handler);
20088#ifdef HAVE_SIGBUS
20089 (void) signal(SIGBUS, old_bus_handler);
20090#endif
20091#endif
20092 }
20093 GC_ATTR_NO_SANITIZE_ADDR
20094 STATIC ptr_t GC_find_limit_with_bound(ptr_t p, GC_bool up, ptr_t bound)
20095 {
20096 static volatile ptr_t result;
20097 GC_ASSERT(up ? (word)bound >= MIN_PAGE_SIZE
20098 : (word)bound <= ~(word)MIN_PAGE_SIZE);
20099 GC_ASSERT(I_HOLD_LOCK());
20100 GC_setup_temporary_fault_handler();
20101 if (SETJMP(GC_jmp_buf) == 0) {
20102 result = (ptr_t)(((word)(p))
20103 & ~(MIN_PAGE_SIZE-1));
20104 for (;;) {
20105 if (up) {
20106 if ((word)result >= (word)bound - MIN_PAGE_SIZE) {
20107 result = bound;
20108 break;
20109 }
20110 result += MIN_PAGE_SIZE;
20111 } else {
20112 if ((word)result <= (word)bound + MIN_PAGE_SIZE) {
20113 result = bound - MIN_PAGE_SIZE;
20114 break;
20115 }
20116 result -= MIN_PAGE_SIZE;
20117 }
20118 GC_noop1((word)(*result));
20119 }
20120 }
20121 GC_reset_fault_handler();
20122 if (!up) {
20123 result += MIN_PAGE_SIZE;
20124 }
20125 return(result);
20126 }
20127 void * GC_find_limit(void * p, int up)
20128 {
20129 return GC_find_limit_with_bound((ptr_t)p, (GC_bool)up,
20130 up ? (ptr_t)GC_WORD_MAX : 0);
20131 }
20132#endif
20133#ifdef HPUX_MAIN_STACKBOTTOM
20134#include <sys/param.h>
20135#include <sys/pstat.h>
20136 STATIC ptr_t GC_hpux_main_stack_base(void)
20137 {
20138 struct pst_vm_status vm_status;
20139 int i = 0;
20140 while (pstat_getprocvm(&vm_status, sizeof(vm_status), 0, i++) == 1) {
20141 if (vm_status.pst_type == PS_STACK)
20142 return (ptr_t)vm_status.pst_vaddr;
20143 }
20144#ifdef STACK_GROWS_UP
20145 return (ptr_t)GC_find_limit(GC_approx_sp(), FALSE);
20146#else
20147 return (ptr_t)GC_find_limit(GC_approx_sp(), TRUE);
20148#endif
20149 }
20150#endif
20151#ifdef HPUX_STACKBOTTOM
20152#include <sys/param.h>
20153#include <sys/pstat.h>
20154 GC_INNER ptr_t GC_get_register_stack_base(void)
20155 {
20156 struct pst_vm_status vm_status;
20157 int i = 0;
20158 while (pstat_getprocvm(&vm_status, sizeof(vm_status), 0, i++) == 1) {
20159 if (vm_status.pst_type == PS_RSESTACK) {
20160 return (ptr_t) vm_status.pst_vaddr;
20161 }
20162 }
20163 return (ptr_t)(((word)GC_stackbottom - BACKING_STORE_DISPLACEMENT - 1)
20164 & ~(BACKING_STORE_ALIGNMENT - 1));
20165 }
20166#endif
20167#ifdef LINUX_STACKBOTTOM
20168#include <sys/types.h>
20169#include <sys/stat.h>
20170#define STAT_SKIP 27
20171#ifdef USE_LIBC_PRIVATES
20172 EXTERN_C_BEGIN
20173#pragma weak __libc_stack_end
20174 extern ptr_t __libc_stack_end;
20175#ifdef IA64
20176#pragma weak __libc_ia64_register_backing_store_base
20177 extern ptr_t __libc_ia64_register_backing_store_base;
20178#endif
20179 EXTERN_C_END
20180#endif
20181#ifdef IA64
20182 GC_INNER ptr_t GC_get_register_stack_base(void)
20183 {
20184 ptr_t result;
20185#ifdef USE_LIBC_PRIVATES
20186 if (0 != &__libc_ia64_register_backing_store_base
20187 && 0 != __libc_ia64_register_backing_store_base) {
20188 return __libc_ia64_register_backing_store_base;
20189 }
20190#endif
20191 result = backing_store_base_from_proc();
20192 if (0 == result) {
20193 result = (ptr_t)GC_find_limit(GC_save_regs_in_stack(), FALSE);
20194 }
20195 return result;
20196 }
20197#endif
20198 STATIC ptr_t GC_linux_main_stack_base(void)
20199 {
20200#define STAT_BUF_SIZE 4096
20201 char stat_buf[STAT_BUF_SIZE];
20202 int f;
20203 word result;
20204 ssize_t i, buf_offset = 0, len;
20205#ifdef USE_LIBC_PRIVATES
20206 if (0 != &__libc_stack_end && 0 != __libc_stack_end ) {
20207#if defined(IA64)
20208 if (((word)__libc_stack_end & 0xfff) + 0x10 < 0x1000) {
20209 return __libc_stack_end + 0x10;
20210 }
20211#elif defined(SPARC)
20212 if (__libc_stack_end != (ptr_t) (unsigned long)0x1)
20213 return __libc_stack_end;
20214#else
20215 return __libc_stack_end;
20216#endif
20217 }
20218#endif
20219 f = open("/proc/self/stat", O_RDONLY);
20220 if (-1 == f)
20221 ABORT_ARG1("Could not open /proc/self/stat", ": errno= %d", errno);
20222 len = GC_repeat_read(f, stat_buf, sizeof(stat_buf));
20223 if (len < 0)
20224 ABORT_ARG1("Failed to read /proc/self/stat",
20225 ": errno= %d", errno);
20226 close(f);
20227 for (i = 0; i < STAT_SKIP; ++i) {
20228 while (buf_offset < len && isspace(stat_buf[buf_offset++])) {
20229 }
20230 while (buf_offset < len && !isspace(stat_buf[buf_offset++])) {
20231 }
20232 }
20233 while (buf_offset < len && isspace(stat_buf[buf_offset])) {
20234 buf_offset++;
20235 }
20236 for (i = 0; buf_offset + i < len; i++) {
20237 if (!isdigit(stat_buf[buf_offset + i])) break;
20238 }
20239 if (buf_offset + i >= len) ABORT("Could not parse /proc/self/stat");
20240 stat_buf[buf_offset + i] = '\0';
20241 result = (word)STRTOULL(&stat_buf[buf_offset], NULL, 10);
20242 if (result < 0x100000 || (result & (sizeof(word) - 1)) != 0)
20243 ABORT_ARG1("Absurd stack bottom value",
20244 ": 0x%lx", (unsigned long)result);
20245 return (ptr_t)result;
20246 }
20247#endif
20248#ifdef FREEBSD_STACKBOTTOM
20249#include <unistd.h>
20250#include <sys/types.h>
20251#include <sys/sysctl.h>
20252 STATIC ptr_t GC_freebsd_main_stack_base(void)
20253 {
20254 int nm[2] = {CTL_KERN, KERN_USRSTACK};
20255 ptr_t base;
20256 size_t len = sizeof(ptr_t);
20257 int r = sysctl(nm, 2, &base, &len, NULL, 0);
20258 if (r) ABORT("Error getting main stack base");
20259 return base;
20260 }
20261#endif
20262#if defined(ECOS) || defined(NOSYS)
20263 ptr_t GC_get_main_stack_base(void)
20264 {
20265 return STACKBOTTOM;
20266 }
20267#define GET_MAIN_STACKBASE_SPECIAL
20268#elif defined(SYMBIAN)
20269 EXTERN_C_BEGIN
20270 extern int GC_get_main_symbian_stack_base(void);
20271 EXTERN_C_END
20272 ptr_t GC_get_main_stack_base(void)
20273 {
20274 return (ptr_t)GC_get_main_symbian_stack_base();
20275 }
20276#define GET_MAIN_STACKBASE_SPECIAL
20277#elif defined(EMSCRIPTEN)
20278#include <emscripten.h>
20279 static void* emscripten_stack_base;
20280 static void scan_stack_cb(void *begin, void *end)
20281 {
20282 (void)begin;
20283 emscripten_stack_base = end;
20284 }
20285 ptr_t GC_get_main_stack_base(void)
20286 {
20287 emscripten_scan_stack(scan_stack_cb);
20288 return (ptr_t)emscripten_stack_base;
20289 }
20290#define GET_MAIN_STACKBASE_SPECIAL
20291#elif !defined(AMIGA) && !defined(HAIKU) && !defined(OS2) \
20292 && !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32) \
20293 && !defined(GC_OPENBSD_THREADS) \
20294 && (!defined(GC_SOLARIS_THREADS) || defined(_STRICT_STDC))
20295#if (defined(HAVE_PTHREAD_ATTR_GET_NP) || defined(HAVE_PTHREAD_GETATTR_NP)) \
20296 && (defined(THREADS) || defined(USE_GET_STACKBASE_FOR_MAIN))
20297#include <pthread.h>
20298#ifdef HAVE_PTHREAD_NP_H
20299#include <pthread_np.h>
20300#endif
20301#elif defined(DARWIN) && !defined(NO_PTHREAD_GET_STACKADDR_NP)
20302#include <pthread.h>
20303#undef STACKBOTTOM
20304#define STACKBOTTOM (ptr_t)pthread_get_stackaddr_np(pthread_self())
20305#endif
20306 ptr_t GC_get_main_stack_base(void)
20307 {
20308 ptr_t result;
20309#if (defined(HAVE_PTHREAD_ATTR_GET_NP) \
20310 || defined(HAVE_PTHREAD_GETATTR_NP)) \
20311 && (defined(USE_GET_STACKBASE_FOR_MAIN) \
20312 || (defined(THREADS) && !defined(REDIRECT_MALLOC)))
20313 pthread_attr_t attr;
20314 void *stackaddr;
20315 size_t size;
20316#ifdef HAVE_PTHREAD_ATTR_GET_NP
20317 if (pthread_attr_init(&attr) == 0
20318 && (pthread_attr_get_np(pthread_self(), &attr) == 0
20319 ? TRUE : (pthread_attr_destroy(&attr), FALSE)))
20320#else
20321 if (pthread_getattr_np(pthread_self(), &attr) == 0)
20322#endif
20323 {
20324 if (pthread_attr_getstack(&attr, &stackaddr, &size) == 0
20325 && stackaddr != NULL) {
20326 (void)pthread_attr_destroy(&attr);
20327#ifdef STACK_GROWS_DOWN
20328 stackaddr = (char *)stackaddr + size;
20329#endif
20330 return (ptr_t)stackaddr;
20331 }
20332 (void)pthread_attr_destroy(&attr);
20333 }
20334 WARN("pthread_getattr_np or pthread_attr_getstack failed"
20335 " for main thread\n", 0);
20336#endif
20337#ifdef STACKBOTTOM
20338 result = STACKBOTTOM;
20339#else
20340#ifdef HEURISTIC1
20341#define STACKBOTTOM_ALIGNMENT_M1 ((word)STACK_GRAN - 1)
20342#ifdef STACK_GROWS_DOWN
20343 result = (ptr_t)(((word)GC_approx_sp() + STACKBOTTOM_ALIGNMENT_M1)
20344 & ~STACKBOTTOM_ALIGNMENT_M1);
20345#else
20346 result = (ptr_t)((word)GC_approx_sp() & ~STACKBOTTOM_ALIGNMENT_M1);
20347#endif
20348#elif defined(HPUX_MAIN_STACKBOTTOM)
20349 result = GC_hpux_main_stack_base();
20350#elif defined(LINUX_STACKBOTTOM)
20351 result = GC_linux_main_stack_base();
20352#elif defined(FREEBSD_STACKBOTTOM)
20353 result = GC_freebsd_main_stack_base();
20354#elif defined(HEURISTIC2)
20355 {
20356 ptr_t sp = GC_approx_sp();
20357#ifdef STACK_GROWS_DOWN
20358 result = (ptr_t)GC_find_limit(sp, TRUE);
20359#if defined(HEURISTIC2_LIMIT) && !defined(CPPCHECK)
20360 if ((word)result > (word)HEURISTIC2_LIMIT
20361 && (word)sp < (word)HEURISTIC2_LIMIT) {
20362 result = HEURISTIC2_LIMIT;
20363 }
20364#endif
20365#else
20366 result = (ptr_t)GC_find_limit(sp, FALSE);
20367#if defined(HEURISTIC2_LIMIT) && !defined(CPPCHECK)
20368 if ((word)result < (word)HEURISTIC2_LIMIT
20369 && (word)sp > (word)HEURISTIC2_LIMIT) {
20370 result = HEURISTIC2_LIMIT;
20371 }
20372#endif
20373#endif
20374 }
20375#elif defined(STACK_NOT_SCANNED) || defined(CPPCHECK)
20376 result = NULL;
20377#else
20378#error None of HEURISTIC* and *STACKBOTTOM defined!
20379#endif
20380#if defined(STACK_GROWS_DOWN) && !defined(CPPCHECK)
20381 if (result == 0)
20382 result = (ptr_t)(signed_word)(-sizeof(ptr_t));
20383#endif
20384#endif
20385#if !defined(CPPCHECK)
20386 GC_ASSERT((word)GC_approx_sp() HOTTER_THAN (word)result);
20387#endif
20388 return(result);
20389 }
20390#define GET_MAIN_STACKBASE_SPECIAL
20391#endif
20392#if (defined(HAVE_PTHREAD_ATTR_GET_NP) || defined(HAVE_PTHREAD_GETATTR_NP)) \
20393 && defined(THREADS) && !defined(HAVE_GET_STACK_BASE)
20394#include <pthread.h>
20395#ifdef HAVE_PTHREAD_NP_H
20396#include <pthread_np.h>
20397#endif
20398 GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *b)
20399 {
20400 pthread_attr_t attr;
20401 size_t size;
20402#ifdef IA64
20403 DCL_LOCK_STATE;
20404#endif
20405#ifdef HAVE_PTHREAD_ATTR_GET_NP
20406 if (pthread_attr_init(&attr) != 0)
20407 ABORT("pthread_attr_init failed");
20408 if (pthread_attr_get_np(pthread_self(), &attr) != 0) {
20409 WARN("pthread_attr_get_np failed\n", 0);
20410 (void)pthread_attr_destroy(&attr);
20411 return GC_UNIMPLEMENTED;
20412 }
20413#else
20414 if (pthread_getattr_np(pthread_self(), &attr) != 0) {
20415 WARN("pthread_getattr_np failed\n", 0);
20416 return GC_UNIMPLEMENTED;
20417 }
20418#endif
20419 if (pthread_attr_getstack(&attr, &(b -> mem_base), &size) != 0) {
20420 ABORT("pthread_attr_getstack failed");
20421 }
20422 (void)pthread_attr_destroy(&attr);
20423#ifdef STACK_GROWS_DOWN
20424 b -> mem_base = (char *)(b -> mem_base) + size;
20425#endif
20426#ifdef IA64
20427 LOCK();
20428 {
20429 IF_CANCEL(int cancel_state;)
20430 ptr_t bsp;
20431 ptr_t next_stack;
20432 DISABLE_CANCEL(cancel_state);
20433 bsp = GC_save_regs_in_stack();
20434 next_stack = GC_greatest_stack_base_below(bsp);
20435 if (0 == next_stack) {
20436 b -> reg_base = GC_find_limit(bsp, FALSE);
20437 } else {
20438 b -> reg_base = GC_find_limit_with_bound(bsp, FALSE, next_stack);
20439 }
20440 RESTORE_CANCEL(cancel_state);
20441 }
20442 UNLOCK();
20443#endif
20444 return GC_SUCCESS;
20445 }
20446#define HAVE_GET_STACK_BASE
20447#endif
20448#if defined(GC_DARWIN_THREADS) && !defined(NO_PTHREAD_GET_STACKADDR_NP)
20449#include <pthread.h>
20450 GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *b)
20451 {
20452 b->mem_base = pthread_get_stackaddr_np(pthread_self());
20453 GC_ASSERT((word)GC_approx_sp() HOTTER_THAN (word)b->mem_base);
20454 return GC_SUCCESS;
20455 }
20456#define HAVE_GET_STACK_BASE
20457#endif
20458#ifdef GC_OPENBSD_THREADS
20459#include <sys/signal.h>
20460#include <pthread.h>
20461#include <pthread_np.h>
20462 GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *sb)
20463 {
20464 stack_t stack;
20465 if (pthread_stackseg_np(pthread_self(), &stack))
20466 ABORT("pthread_stackseg_np(self) failed");
20467 sb->mem_base = stack.ss_sp;
20468 return GC_SUCCESS;
20469 }
20470#define HAVE_GET_STACK_BASE
20471#endif
20472#if defined(GC_SOLARIS_THREADS) && !defined(_STRICT_STDC)
20473#include <thread.h>
20474#include <signal.h>
20475#include <pthread.h>
20476 static pthread_t stackbase_main_self = 0;
20477 static void *stackbase_main_ss_sp = NULL;
20478 GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *b)
20479 {
20480 stack_t s;
20481 pthread_t self = pthread_self();
20482 if (self == stackbase_main_self)
20483 {
20484 b -> mem_base = stackbase_main_ss_sp;
20485 GC_ASSERT(b -> mem_base != NULL);
20486 return GC_SUCCESS;
20487 }
20488 if (thr_stksegment(&s)) {
20489 ABORT("thr_stksegment failed");
20490 }
20491 GC_ASSERT((word)GC_approx_sp() HOTTER_THAN (word)s.ss_sp);
20492 if (!stackbase_main_self && thr_main() != 0)
20493 {
20494 stackbase_main_ss_sp = s.ss_sp;
20495 stackbase_main_self = self;
20496 }
20497 b -> mem_base = s.ss_sp;
20498 return GC_SUCCESS;
20499 }
20500#define HAVE_GET_STACK_BASE
20501#endif
20502#ifdef GC_RTEMS_PTHREADS
20503 GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *sb)
20504 {
20505 sb->mem_base = rtems_get_stack_bottom();
20506 return GC_SUCCESS;
20507 }
20508#define HAVE_GET_STACK_BASE
20509#endif
20510#ifndef HAVE_GET_STACK_BASE
20511#ifdef NEED_FIND_LIMIT
20512 GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *b)
20513 {
20514 IF_CANCEL(int cancel_state;)
20515 DCL_LOCK_STATE;
20516 LOCK();
20517 DISABLE_CANCEL(cancel_state);
20518#ifdef STACK_GROWS_DOWN
20519 b -> mem_base = GC_find_limit(GC_approx_sp(), TRUE);
20520#ifdef IA64
20521 b -> reg_base = GC_find_limit(GC_save_regs_in_stack(), FALSE);
20522#endif
20523#else
20524 b -> mem_base = GC_find_limit(GC_approx_sp(), FALSE);
20525#endif
20526 RESTORE_CANCEL(cancel_state);
20527 UNLOCK();
20528 return GC_SUCCESS;
20529 }
20530#else
20531 GC_API int GC_CALL GC_get_stack_base(
20532 struct GC_stack_base *b GC_ATTR_UNUSED)
20533 {
20534#if defined(GET_MAIN_STACKBASE_SPECIAL) && !defined(THREADS) \
20535 && !defined(IA64)
20536 b->mem_base = GC_get_main_stack_base();
20537 return GC_SUCCESS;
20538#else
20539 return GC_UNIMPLEMENTED;
20540#endif
20541 }
20542#endif
20543#endif
20544#ifndef GET_MAIN_STACKBASE_SPECIAL
20545 ptr_t GC_get_main_stack_base(void)
20546 {
20547 struct GC_stack_base sb;
20548 if (GC_get_stack_base(&sb) != GC_SUCCESS)
20549 ABORT("GC_get_stack_base failed");
20550 GC_ASSERT((word)GC_approx_sp() HOTTER_THAN (word)sb.mem_base);
20551 return (ptr_t)sb.mem_base;
20552 }
20553#endif
20554#ifdef OS2
20555void GC_register_data_segments(void)
20556{
20557 PTIB ptib;
20558 PPIB ppib;
20559 HMODULE module_handle;
20560#define PBUFSIZ 512
20561 UCHAR path[PBUFSIZ];
20562 FILE * myexefile;
20563 struct exe_hdr hdrdos;
20564 struct e32_exe hdr386;
20565 struct o32_obj seg;
20566 int nsegs;
20567#if defined(CPPCHECK)
20568 hdrdos.padding[0] = 0;
20569 hdr386.exe_format_level = 0;
20570 hdr386.os = 0;
20571 hdr386.padding1[0] = 0;
20572 hdr386.padding2[0] = 0;
20573 seg.pagemap = 0;
20574 seg.mapsize = 0;
20575 seg.reserved = 0;
20576#endif
20577 if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
20578 ABORT("DosGetInfoBlocks failed");
20579 }
20580 module_handle = ppib -> pib_hmte;
20581 if (DosQueryModuleName(module_handle, PBUFSIZ, path) != NO_ERROR) {
20582 ABORT("DosQueryModuleName failed");
20583 }
20584 myexefile = fopen(path, "rb");
20585 if (myexefile == 0) {
20586 ABORT_ARG1("Failed to open executable", ": %s", path);
20587 }
20588 if (fread((char *)(&hdrdos), 1, sizeof(hdrdos), myexefile)
20589 < sizeof(hdrdos)) {
20590 ABORT_ARG1("Could not read MSDOS header", " from: %s", path);
20591 }
20592 if (E_MAGIC(hdrdos) != EMAGIC) {
20593 ABORT_ARG1("Bad DOS magic number", " in file: %s", path);
20594 }
20595 if (fseek(myexefile, E_LFANEW(hdrdos), SEEK_SET) != 0) {
20596 ABORT_ARG1("Bad DOS magic number", " in file: %s", path);
20597 }
20598 if (fread((char *)(&hdr386), 1, sizeof(hdr386), myexefile)
20599 < sizeof(hdr386)) {
20600 ABORT_ARG1("Could not read OS/2 header", " from: %s", path);
20601 }
20602 if (E32_MAGIC1(hdr386) != E32MAGIC1 || E32_MAGIC2(hdr386) != E32MAGIC2) {
20603 ABORT_ARG1("Bad OS/2 magic number", " in file: %s", path);
20604 }
20605 if (E32_BORDER(hdr386) != E32LEBO || E32_WORDER(hdr386) != E32LEWO) {
20606 ABORT_ARG1("Bad byte order in executable", " file: %s", path);
20607 }
20608 if (E32_CPU(hdr386) == E32CPU286) {
20609 ABORT_ARG1("GC cannot handle 80286 executables", ": %s", path);
20610 }
20611 if (fseek(myexefile, E_LFANEW(hdrdos) + E32_OBJTAB(hdr386),
20612 SEEK_SET) != 0) {
20613 ABORT_ARG1("Seek to object table failed", " in file: %s", path);
20614 }
20615 for (nsegs = E32_OBJCNT(hdr386); nsegs > 0; nsegs--) {
20616 int flags;
20617 if (fread((char *)(&seg), 1, sizeof(seg), myexefile) < sizeof(seg)) {
20618 ABORT_ARG1("Could not read obj table entry", " from file: %s", path);
20619 }
20620 flags = O32_FLAGS(seg);
20621 if (!(flags & OBJWRITE)) continue;
20622 if (!(flags & OBJREAD)) continue;
20623 if (flags & OBJINVALID) {
20624 GC_err_printf("Object with invalid pages?\n");
20625 continue;
20626 }
20627 GC_add_roots_inner((ptr_t)O32_BASE(seg),
20628 (ptr_t)(O32_BASE(seg)+O32_SIZE(seg)), FALSE);
20629 }
20630 (void)fclose(myexefile);
20631}
20632#else
20633#if defined(GWW_VDB)
20634#ifndef MEM_WRITE_WATCH
20635#define MEM_WRITE_WATCH 0x200000
20636#endif
20637#ifndef WRITE_WATCH_FLAG_RESET
20638#define WRITE_WATCH_FLAG_RESET 1
20639#endif
20640#define GC_ULONG_PTR word
20641 typedef UINT (WINAPI * GetWriteWatch_type)(
20642 DWORD, PVOID, GC_ULONG_PTR ,
20643 PVOID *, GC_ULONG_PTR *, PULONG);
20644 static FARPROC GetWriteWatch_func;
20645 static DWORD GetWriteWatch_alloc_flag;
20646#define GC_GWW_AVAILABLE() (GetWriteWatch_func != 0)
20647 static void detect_GetWriteWatch(void)
20648 {
20649 static GC_bool done;
20650 HMODULE hK32;
20651 if (done)
20652 return;
20653#if defined(MPROTECT_VDB)
20654 {
20655 char * str = GETENV("GC_USE_GETWRITEWATCH");
20656#if defined(GC_PREFER_MPROTECT_VDB)
20657 if (str == NULL || (*str == '0' && *(str + 1) == '\0')) {
20658 done = TRUE;
20659 return;
20660 }
20661#else
20662 if (str != NULL && *str == '0' && *(str + 1) == '\0') {
20663 done = TRUE;
20664 return;
20665 }
20666#endif
20667 }
20668#endif
20669#ifdef MSWINRT_FLAVOR
20670 {
20671 MEMORY_BASIC_INFORMATION memInfo;
20672 SIZE_T result = VirtualQuery(GetProcAddress,
20673 &memInfo, sizeof(memInfo));
20674 if (result != sizeof(memInfo))
20675 ABORT("Weird VirtualQuery result");
20676 hK32 = (HMODULE)memInfo.AllocationBase;
20677 }
20678#else
20679 hK32 = GetModuleHandle(TEXT("kernel32.dll"));
20680#endif
20681 if (hK32 != (HMODULE)0 &&
20682 (GetWriteWatch_func = GetProcAddress(hK32, "GetWriteWatch")) != 0) {
20683 void * page;
20684 GC_ASSERT(GC_page_size != 0);
20685 page = VirtualAlloc(NULL, GC_page_size, MEM_WRITE_WATCH | MEM_RESERVE,
20686 PAGE_READWRITE);
20687 if (page != NULL) {
20688 PVOID pages[16];
20689 GC_ULONG_PTR count = 16;
20690 DWORD page_size;
20691 if ((*(GetWriteWatch_type)(word)GetWriteWatch_func)(
20692 WRITE_WATCH_FLAG_RESET, page,
20693 GC_page_size, pages, &count,
20694 &page_size) != 0) {
20695 GetWriteWatch_func = 0;
20696 } else {
20697 GetWriteWatch_alloc_flag = MEM_WRITE_WATCH;
20698 }
20699 VirtualFree(page, 0 , MEM_RELEASE);
20700 } else {
20701 GetWriteWatch_func = 0;
20702 }
20703 }
20704 done = TRUE;
20705 }
20706#else
20707#define GetWriteWatch_alloc_flag 0
20708#endif
20709#if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
20710#ifdef MSWIN32
20711 GC_INNER GC_bool GC_no_win32_dlls = FALSE;
20712 GC_INNER GC_bool GC_wnt = FALSE;
20713 GC_INNER void GC_init_win32(void)
20714 {
20715#if defined(_WIN64) || (defined(_MSC_VER) && _MSC_VER >= 1800)
20716 GC_wnt = TRUE;
20717#else
20718 DWORD v = GetVersion();
20719 GC_wnt = !(v & 0x80000000);
20720 GC_no_win32_dlls |= ((!GC_wnt) && (v & 0xff) <= 3);
20721#endif
20722#ifdef USE_MUNMAP
20723 if (GC_no_win32_dlls) {
20724 GC_unmap_threshold = 0;
20725 }
20726#endif
20727 }
20728 STATIC ptr_t GC_least_described_address(ptr_t start)
20729 {
20730 MEMORY_BASIC_INFORMATION buf;
20731 LPVOID limit = GC_sysinfo.lpMinimumApplicationAddress;
20732 ptr_t p = (ptr_t)((word)start & ~(GC_page_size - 1));
20733 GC_ASSERT(GC_page_size != 0);
20734 for (;;) {
20735 size_t result;
20736 LPVOID q = (LPVOID)(p - GC_page_size);
20737 if ((word)q > (word)p || (word)q < (word)limit) break;
20738 result = VirtualQuery(q, &buf, sizeof(buf));
20739 if (result != sizeof(buf) || buf.AllocationBase == 0) break;
20740 p = (ptr_t)(buf.AllocationBase);
20741 }
20742 return p;
20743 }
20744#endif
20745#if defined(USE_WINALLOC) && !defined(REDIRECT_MALLOC)
20746 STATIC size_t GC_max_root_size = 100000;
20747 STATIC struct GC_malloc_heap_list {
20748 void * allocation_base;
20749 struct GC_malloc_heap_list *next;
20750 } *GC_malloc_heap_l = 0;
20751 STATIC GC_bool GC_is_malloc_heap_base(void *p)
20752 {
20753 struct GC_malloc_heap_list *q = GC_malloc_heap_l;
20754 while (0 != q) {
20755 if (q -> allocation_base == p) return TRUE;
20756 q = q -> next;
20757 }
20758 return FALSE;
20759 }
20760 STATIC void *GC_get_allocation_base(void *p)
20761 {
20762 MEMORY_BASIC_INFORMATION buf;
20763 size_t result = VirtualQuery(p, &buf, sizeof(buf));
20764 if (result != sizeof(buf)) {
20765 ABORT("Weird VirtualQuery result");
20766 }
20767 return buf.AllocationBase;
20768 }
20769 GC_INNER void GC_add_current_malloc_heap(void)
20770 {
20771 struct GC_malloc_heap_list *new_l = (struct GC_malloc_heap_list *)
20772 malloc(sizeof(struct GC_malloc_heap_list));
20773 void *candidate;
20774 if (NULL == new_l) return;
20775 candidate = GC_get_allocation_base(new_l);
20776 if (GC_is_malloc_heap_base(candidate)) {
20777 size_t req_size = 10000;
20778 do {
20779 void *p = malloc(req_size);
20780 if (0 == p) {
20781 free(new_l);
20782 return;
20783 }
20784 candidate = GC_get_allocation_base(p);
20785 free(p);
20786 req_size *= 2;
20787 } while (GC_is_malloc_heap_base(candidate)
20788 && req_size < GC_max_root_size/10 && req_size < 500000);
20789 if (GC_is_malloc_heap_base(candidate)) {
20790 free(new_l);
20791 return;
20792 }
20793 }
20794 GC_COND_LOG_PRINTF("Found new system malloc AllocationBase at %p\n",
20795 candidate);
20796 new_l -> allocation_base = candidate;
20797 new_l -> next = GC_malloc_heap_l;
20798 GC_malloc_heap_l = new_l;
20799 }
20800 STATIC void GC_free_malloc_heap_list(void)
20801 {
20802 struct GC_malloc_heap_list *q = GC_malloc_heap_l;
20803 GC_malloc_heap_l = NULL;
20804 while (q != NULL) {
20805 struct GC_malloc_heap_list *next = q -> next;
20806 free(q);
20807 q = next;
20808 }
20809 }
20810#endif
20811 GC_INNER GC_bool GC_is_heap_base(void *p)
20812 {
20813 int i;
20814#if defined(USE_WINALLOC) && !defined(REDIRECT_MALLOC)
20815 if (GC_root_size > GC_max_root_size)
20816 GC_max_root_size = GC_root_size;
20817 if (GC_is_malloc_heap_base(p))
20818 return TRUE;
20819#endif
20820 for (i = 0; i < (int)GC_n_heap_bases; i++) {
20821 if (GC_heap_bases[i] == p) return TRUE;
20822 }
20823 return FALSE;
20824 }
20825#ifdef MSWIN32
20826 STATIC void GC_register_root_section(ptr_t static_root)
20827 {
20828 MEMORY_BASIC_INFORMATION buf;
20829 LPVOID p;
20830 char * base;
20831 char * limit;
20832 if (!GC_no_win32_dlls) return;
20833 p = base = limit = GC_least_described_address(static_root);
20834 while ((word)p < (word)GC_sysinfo.lpMaximumApplicationAddress) {
20835 size_t result = VirtualQuery(p, &buf, sizeof(buf));
20836 char * new_limit;
20837 DWORD protect;
20838 if (result != sizeof(buf) || buf.AllocationBase == 0
20839 || GC_is_heap_base(buf.AllocationBase)) break;
20840 new_limit = (char *)p + buf.RegionSize;
20841 protect = buf.Protect;
20842 if (buf.State == MEM_COMMIT
20843 && is_writable(protect)) {
20844 if ((char *)p == limit) {
20845 limit = new_limit;
20846 } else {
20847 if (base != limit) GC_add_roots_inner(base, limit, FALSE);
20848 base = (char *)p;
20849 limit = new_limit;
20850 }
20851 }
20852 if ((word)p > (word)new_limit ) break;
20853 p = (LPVOID)new_limit;
20854 }
20855 if (base != limit) GC_add_roots_inner(base, limit, FALSE);
20856 }
20857#endif
20858 void GC_register_data_segments(void)
20859 {
20860#ifdef MSWIN32
20861 GC_register_root_section((ptr_t)&GC_pages_executable);
20862#endif
20863 }
20864#else
20865#if (defined(SVR4) || defined(AIX) || defined(DGUX) \
20866 || (defined(LINUX) && defined(SPARC))) && !defined(PCR)
20867 ptr_t GC_SysVGetDataStart(size_t max_page_size, ptr_t etext_addr)
20868 {
20869 word text_end = ((word)(etext_addr) + sizeof(word) - 1)
20870 & ~(word)(sizeof(word) - 1);
20871 word next_page = ((text_end + (word)max_page_size - 1)
20872 & ~((word)max_page_size - 1));
20873 word page_offset = (text_end & ((word)max_page_size - 1));
20874 volatile ptr_t result = (char *)(next_page + page_offset);
20875 GC_setup_temporary_fault_handler();
20876 if (SETJMP(GC_jmp_buf) == 0) {
20877#ifdef AO_HAVE_fetch_and_add
20878 volatile AO_t zero = 0;
20879 (void)AO_fetch_and_add((volatile AO_t *)result, zero);
20880#else
20881 char v = *result;
20882#if defined(CPPCHECK)
20883 GC_noop1((word)&v);
20884#endif
20885 *result = v;
20886#endif
20887 GC_reset_fault_handler();
20888 } else {
20889 GC_reset_fault_handler();
20890 result = (char *)GC_find_limit(DATAEND, FALSE);
20891 }
20892 return ( ptr_t)result;
20893 }
20894#endif
20895#ifdef DATASTART_USES_BSDGETDATASTART
20896 GC_INNER ptr_t GC_FreeBSDGetDataStart(size_t max_page_size,
20897 ptr_t etext_addr)
20898 {
20899 word text_end = ((word)(etext_addr) + sizeof(word) - 1)
20900 & ~(word)(sizeof(word) - 1);
20901 volatile word next_page = (text_end + (word)max_page_size - 1)
20902 & ~((word)max_page_size - 1);
20903 volatile ptr_t result = (ptr_t)text_end;
20904 GC_setup_temporary_fault_handler();
20905 if (SETJMP(GC_jmp_buf) == 0) {
20906 for (; next_page < (word)DATAEND; next_page += (word)max_page_size)
20907 *(volatile char *)next_page;
20908 GC_reset_fault_handler();
20909 } else {
20910 GC_reset_fault_handler();
20911 result = (ptr_t)GC_find_limit(DATAEND, FALSE);
20912 }
20913 return(result);
20914 }
20915#endif
20916#ifdef AMIGA
20917#define GC_AMIGA_DS
20918#undef GC_AMIGA_DS
20919#elif defined(OPENBSD)
20920void GC_register_data_segments(void)
20921{
20922 ptr_t region_start = DATASTART;
20923 if ((word)region_start - 1U >= (word)DATAEND)
20924 ABORT_ARG2("Wrong DATASTART/END pair",
20925 ": %p .. %p", (void *)region_start, (void *)DATAEND);
20926 for (;;) {
20927#ifdef GC_OPENBSD_UTHREADS
20928 ptr_t region_end = GC_find_limit_openbsd(region_start, DATAEND);
20929#else
20930 ptr_t region_end = GC_find_limit_with_bound(region_start, TRUE, DATAEND);
20931#endif
20932 GC_add_roots_inner(region_start, region_end, FALSE);
20933 if ((word)region_end >= (word)DATAEND)
20934 break;
20935 region_start = GC_skip_hole_openbsd(region_end, DATAEND);
20936 }
20937}
20938#else
20939#if !defined(PCR) && !defined(MACOS) && defined(REDIRECT_MALLOC) \
20940 && defined(GC_SOLARIS_THREADS)
20941 EXTERN_C_BEGIN
20942 extern caddr_t sbrk(int);
20943 EXTERN_C_END
20944#endif
20945 void GC_register_data_segments(void)
20946 {
20947#if !defined(PCR) && !defined(MACOS)
20948#if defined(REDIRECT_MALLOC) && defined(GC_SOLARIS_THREADS)
20949 GC_ASSERT(DATASTART);
20950 {
20951 ptr_t p = (ptr_t)sbrk(0);
20952 if ((word)DATASTART < (word)p)
20953 GC_add_roots_inner(DATASTART, p, FALSE);
20954 }
20955#else
20956 if ((word)DATASTART - 1U >= (word)DATAEND) {
20957 ABORT_ARG2("Wrong DATASTART/END pair",
20958 ": %p .. %p", (void *)DATASTART, (void *)DATAEND);
20959 }
20960 GC_add_roots_inner(DATASTART, DATAEND, FALSE);
20961#ifdef GC_HAVE_DATAREGION2
20962 if ((word)DATASTART2 - 1U >= (word)DATAEND2)
20963 ABORT_ARG2("Wrong DATASTART/END2 pair",
20964 ": %p .. %p", (void *)DATASTART2, (void *)DATAEND2);
20965 GC_add_roots_inner(DATASTART2, DATAEND2, FALSE);
20966#endif
20967#endif
20968#endif
20969#if defined(MACOS)
20970 {
20971#if defined(THINK_C)
20972 extern void* GC_MacGetDataStart(void);
20973 GC_add_roots_inner((ptr_t)GC_MacGetDataStart(),
20974 (ptr_t)LMGetCurrentA5(), FALSE);
20975#else
20976#if defined(__MWERKS__)
20977#if !__POWERPC__
20978 extern void* GC_MacGetDataStart(void);
20979#if __option(far_data)
20980 extern void* GC_MacGetDataEnd(void);
20981#endif
20982 GC_add_roots_inner((ptr_t)GC_MacGetDataStart(),
20983 (ptr_t)LMGetCurrentA5(), FALSE);
20984#if __option(far_data)
20985 GC_add_roots_inner((ptr_t)LMGetCurrentA5(),
20986 (ptr_t)GC_MacGetDataEnd(), FALSE);
20987#endif
20988#else
20989 extern char __data_start__[], __data_end__[];
20990 GC_add_roots_inner((ptr_t)&__data_start__,
20991 (ptr_t)&__data_end__, FALSE);
20992#endif
20993#endif
20994#endif
20995 }
20996#endif
20997 }
20998#endif
20999#endif
21000#endif
21001#if !defined(OS2) && !defined(PCR) && !defined(AMIGA) \
21002 && !defined(USE_WINALLOC) && !defined(MACOS) && !defined(DOS4GW) \
21003 && !defined(NINTENDO_SWITCH) && !defined(NONSTOP) \
21004 && !defined(SN_TARGET_ORBIS) && !defined(SN_TARGET_PS3) \
21005 && !defined(SN_TARGET_PSP2) && !defined(RTEMS) && !defined(__CC_ARM)
21006#define SBRK_ARG_T ptrdiff_t
21007#if defined(MMAP_SUPPORTED)
21008#ifdef USE_MMAP_FIXED
21009#define GC_MMAP_FLAGS MAP_FIXED | MAP_PRIVATE
21010#else
21011#define GC_MMAP_FLAGS MAP_PRIVATE
21012#endif
21013#ifdef USE_MMAP_ANON
21014#define zero_fd -1
21015#if defined(MAP_ANONYMOUS) && !defined(CPPCHECK)
21016#define OPT_MAP_ANON MAP_ANONYMOUS
21017#else
21018#define OPT_MAP_ANON MAP_ANON
21019#endif
21020#else
21021 static int zero_fd = -1;
21022#define OPT_MAP_ANON 0
21023#endif
21024#ifndef MSWIN_XBOX1
21025#if defined(SYMBIAN) && !defined(USE_MMAP_ANON)
21026 EXTERN_C_BEGIN
21027 extern char *GC_get_private_path_and_zero_file(void);
21028 EXTERN_C_END
21029#endif
21030 STATIC ptr_t GC_unix_mmap_get_mem(size_t bytes)
21031 {
21032 void *result;
21033 static ptr_t last_addr = HEAP_START;
21034#ifndef USE_MMAP_ANON
21035 static GC_bool initialized = FALSE;
21036 if (!EXPECT(initialized, TRUE)) {
21037#ifdef SYMBIAN
21038 char *path = GC_get_private_path_and_zero_file();
21039 if (path != NULL) {
21040 zero_fd = open(path, O_RDWR | O_CREAT, 0644);
21041 free(path);
21042 }
21043#else
21044 zero_fd = open("/dev/zero", O_RDONLY);
21045#endif
21046 if (zero_fd == -1)
21047 ABORT("Could not open /dev/zero");
21048 if (fcntl(zero_fd, F_SETFD, FD_CLOEXEC) == -1)
21049 WARN("Could not set FD_CLOEXEC for /dev/zero\n", 0);
21050 initialized = TRUE;
21051 }
21052#endif
21053 GC_ASSERT(GC_page_size != 0);
21054 if (bytes & (GC_page_size - 1)) ABORT("Bad GET_MEM arg");
21055 result = mmap(last_addr, bytes, (PROT_READ | PROT_WRITE)
21056 | (GC_pages_executable ? PROT_EXEC : 0),
21057 GC_MMAP_FLAGS | OPT_MAP_ANON, zero_fd, 0);
21058#undef IGNORE_PAGES_EXECUTABLE
21059 if (EXPECT(MAP_FAILED == result, FALSE)) {
21060 if (HEAP_START == last_addr && GC_pages_executable && EACCES == errno)
21061 ABORT("Cannot allocate executable pages");
21062 return NULL;
21063 }
21064 last_addr = (ptr_t)(((word)result + bytes + GC_page_size - 1)
21065 & ~(GC_page_size - 1));
21066#if !defined(LINUX)
21067 if (last_addr == 0) {
21068 munmap(result, ~GC_page_size - (size_t)result + 1);
21069 return GC_unix_mmap_get_mem(bytes);
21070 }
21071#else
21072 GC_ASSERT(last_addr != 0);
21073#endif
21074 if (((word)result % HBLKSIZE) != 0)
21075 ABORT(
21076 "GC_unix_get_mem: Memory returned by mmap is not aligned to HBLKSIZE.");
21077 return((ptr_t)result);
21078 }
21079#endif
21080#endif
21081#if defined(USE_MMAP)
21082 ptr_t GC_unix_get_mem(size_t bytes)
21083 {
21084 return GC_unix_mmap_get_mem(bytes);
21085 }
21086#else
21087STATIC ptr_t GC_unix_sbrk_get_mem(size_t bytes)
21088{
21089 ptr_t result;
21090#ifdef IRIX5
21091 __LOCK_MALLOC();
21092#endif
21093 {
21094 ptr_t cur_brk = (ptr_t)sbrk(0);
21095 SBRK_ARG_T lsbs = (word)cur_brk & (GC_page_size-1);
21096 GC_ASSERT(GC_page_size != 0);
21097 if ((SBRK_ARG_T)bytes < 0) {
21098 result = 0;
21099 goto out;
21100 }
21101 if (lsbs != 0) {
21102 if((ptr_t)sbrk((SBRK_ARG_T)GC_page_size - lsbs) == (ptr_t)(-1)) {
21103 result = 0;
21104 goto out;
21105 }
21106 }
21107#ifdef ADD_HEAP_GUARD_PAGES
21108 {
21109 ptr_t guard = (ptr_t)sbrk((SBRK_ARG_T)GC_page_size);
21110 if (mprotect(guard, GC_page_size, PROT_NONE) != 0)
21111 ABORT("ADD_HEAP_GUARD_PAGES: mprotect failed");
21112 }
21113#endif
21114 result = (ptr_t)sbrk((SBRK_ARG_T)bytes);
21115 if (result == (ptr_t)(-1)) result = 0;
21116 }
21117 out:
21118#ifdef IRIX5
21119 __UNLOCK_MALLOC();
21120#endif
21121 return(result);
21122}
21123ptr_t GC_unix_get_mem(size_t bytes)
21124{
21125#if defined(MMAP_SUPPORTED)
21126 static GC_bool sbrk_failed = FALSE;
21127 ptr_t result = 0;
21128 if (GC_pages_executable) {
21129 return GC_unix_mmap_get_mem(bytes);
21130 }
21131 if (!sbrk_failed) result = GC_unix_sbrk_get_mem(bytes);
21132 if (0 == result) {
21133 sbrk_failed = TRUE;
21134 result = GC_unix_mmap_get_mem(bytes);
21135 }
21136 if (0 == result) {
21137 result = GC_unix_sbrk_get_mem(bytes);
21138 }
21139 return result;
21140#else
21141 return GC_unix_sbrk_get_mem(bytes);
21142#endif
21143}
21144#endif
21145#endif
21146#ifdef OS2
21147void * os2_alloc(size_t bytes)
21148{
21149 void * result;
21150 if (DosAllocMem(&result, bytes, (PAG_READ | PAG_WRITE | PAG_COMMIT)
21151 | (GC_pages_executable ? PAG_EXECUTE : 0))
21152 != NO_ERROR) {
21153 return(0);
21154 }
21155 if (result == 0) return(os2_alloc(bytes));
21156 return(result);
21157}
21158#endif
21159#ifdef MSWIN_XBOX1
21160 ptr_t GC_durango_get_mem(size_t bytes)
21161 {
21162 if (0 == bytes) return NULL;
21163 return (ptr_t)VirtualAlloc(NULL, bytes, MEM_COMMIT | MEM_TOP_DOWN,
21164 PAGE_READWRITE);
21165 }
21166#elif defined(MSWINCE)
21167 ptr_t GC_wince_get_mem(size_t bytes)
21168 {
21169 ptr_t result = 0;
21170 word i;
21171 GC_ASSERT(GC_page_size != 0);
21172 bytes = ROUNDUP_PAGESIZE(bytes);
21173 for (i = 0; i < GC_n_heap_bases; i++) {
21174 if (((word)(-(signed_word)GC_heap_lengths[i])
21175 & (GC_sysinfo.dwAllocationGranularity-1))
21176 >= bytes) {
21177 result = GC_heap_bases[i] + GC_heap_lengths[i];
21178 break;
21179 }
21180 }
21181 if (i == GC_n_heap_bases) {
21182 size_t res_bytes =
21183 SIZET_SAT_ADD(bytes, (size_t)GC_sysinfo.dwAllocationGranularity-1)
21184 & ~((size_t)GC_sysinfo.dwAllocationGranularity-1);
21185 result = (ptr_t) VirtualAlloc(NULL, res_bytes,
21186 MEM_RESERVE | MEM_TOP_DOWN,
21187 GC_pages_executable ? PAGE_EXECUTE_READWRITE :
21188 PAGE_READWRITE);
21189 if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
21190 if (GC_n_heap_bases >= MAX_HEAP_SECTS) ABORT("Too many heap sections");
21191 if (result == NULL) return NULL;
21192 GC_heap_bases[GC_n_heap_bases] = result;
21193 GC_heap_lengths[GC_n_heap_bases] = 0;
21194 GC_n_heap_bases++;
21195 }
21196 result = (ptr_t) VirtualAlloc(result, bytes, MEM_COMMIT,
21197 GC_pages_executable ? PAGE_EXECUTE_READWRITE :
21198 PAGE_READWRITE);
21199#undef IGNORE_PAGES_EXECUTABLE
21200 if (result != NULL) {
21201 if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
21202 GC_heap_lengths[i] += bytes;
21203 }
21204 return(result);
21205 }
21206#elif (defined(USE_WINALLOC) && !defined(MSWIN_XBOX1)) || defined(CYGWIN32)
21207#ifdef USE_GLOBAL_ALLOC
21208#define GLOBAL_ALLOC_TEST 1
21209#else
21210#define GLOBAL_ALLOC_TEST GC_no_win32_dlls
21211#endif
21212#if (defined(GC_USE_MEM_TOP_DOWN) && defined(USE_WINALLOC)) \
21213 || defined(CPPCHECK)
21214 DWORD GC_mem_top_down = MEM_TOP_DOWN;
21215#else
21216#define GC_mem_top_down 0
21217#endif
21218 ptr_t GC_win32_get_mem(size_t bytes)
21219 {
21220 ptr_t result;
21221#ifndef USE_WINALLOC
21222 result = GC_unix_get_mem(bytes);
21223#else
21224#if defined(MSWIN32) && !defined(MSWINRT_FLAVOR)
21225 if (GLOBAL_ALLOC_TEST) {
21226 result = (ptr_t)GlobalAlloc(0, SIZET_SAT_ADD(bytes, HBLKSIZE));
21227 result = (ptr_t)(((word)result + HBLKSIZE - 1)
21228 & ~(word)(HBLKSIZE - 1));
21229 } else
21230#endif
21231 {
21232#ifdef MPROTECT_VDB
21233#ifdef GWW_VDB
21234#define VIRTUAL_ALLOC_PAD (GC_GWW_AVAILABLE() ? 0 : 1)
21235#else
21236#define VIRTUAL_ALLOC_PAD 1
21237#endif
21238#else
21239#define VIRTUAL_ALLOC_PAD 0
21240#endif
21241 result = (ptr_t) VirtualAlloc(NULL,
21242 SIZET_SAT_ADD(bytes, VIRTUAL_ALLOC_PAD),
21243 GetWriteWatch_alloc_flag
21244 | (MEM_COMMIT | MEM_RESERVE)
21245 | GC_mem_top_down,
21246 GC_pages_executable ? PAGE_EXECUTE_READWRITE :
21247 PAGE_READWRITE);
21248#undef IGNORE_PAGES_EXECUTABLE
21249 }
21250#endif
21251 if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
21252 if (GC_n_heap_bases >= MAX_HEAP_SECTS) ABORT("Too many heap sections");
21253 if (0 != result) GC_heap_bases[GC_n_heap_bases++] = result;
21254 return(result);
21255 }
21256#endif
21257#if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32) \
21258 || defined(MSWIN_XBOX1)
21259 GC_API void GC_CALL GC_win32_free_heap(void)
21260 {
21261#if defined(USE_WINALLOC) && !defined(REDIRECT_MALLOC) \
21262 && !defined(MSWIN_XBOX1)
21263 GC_free_malloc_heap_list();
21264#endif
21265#if (defined(USE_WINALLOC) && !defined(MSWIN_XBOX1) \
21266 && !defined(MSWINCE)) || defined(CYGWIN32)
21267#ifndef MSWINRT_FLAVOR
21268#ifndef CYGWIN32
21269 if (GLOBAL_ALLOC_TEST)
21270#endif
21271 {
21272 while (GC_n_heap_bases-- > 0) {
21273#ifdef CYGWIN32
21274#else
21275 GlobalFree(GC_heap_bases[GC_n_heap_bases]);
21276#endif
21277 GC_heap_bases[GC_n_heap_bases] = 0;
21278 }
21279 return;
21280 }
21281#endif
21282#ifndef CYGWIN32
21283 while (GC_n_heap_bases > 0) {
21284 VirtualFree(GC_heap_bases[--GC_n_heap_bases], 0, MEM_RELEASE);
21285 GC_heap_bases[GC_n_heap_bases] = 0;
21286 }
21287#endif
21288#endif
21289 }
21290#endif
21291#ifdef AMIGA
21292#define GC_AMIGA_AM
21293#undef GC_AMIGA_AM
21294#endif
21295#if defined(HAIKU)
21296#include <stdlib.h>
21297 ptr_t GC_haiku_get_mem(size_t bytes)
21298 {
21299 void* mem;
21300 GC_ASSERT(GC_page_size != 0);
21301 if (posix_memalign(&mem, GC_page_size, bytes) == 0)
21302 return mem;
21303 return NULL;
21304 }
21305#endif
21306#if (defined(USE_MUNMAP) || defined(MPROTECT_VDB)) && !defined(USE_WINALLOC)
21307#define ABORT_ON_REMAP_FAIL(C_msg_prefix, start_addr, len) \
21308 ABORT_ARG3(C_msg_prefix " failed", \
21309 " at %p (length %lu), errno= %d", \
21310 (void *)(start_addr), (unsigned long)(len), errno)
21311#endif
21312#ifdef USE_MUNMAP
21313#if !defined(NN_PLATFORM_CTR) && !defined(MSWIN32) && !defined(MSWINCE) \
21314 && !defined(MSWIN_XBOX1)
21315#include <unistd.h>
21316#ifdef SN_TARGET_PS3
21317#include <sys/memory.h>
21318#else
21319#include <sys/mman.h>
21320#endif
21321#include <sys/stat.h>
21322#include <sys/types.h>
21323#endif
21324STATIC ptr_t GC_unmap_start(ptr_t start, size_t bytes)
21325{
21326 ptr_t result = (ptr_t)(((word)start + GC_page_size - 1)
21327 & ~(GC_page_size - 1));
21328 GC_ASSERT(GC_page_size != 0);
21329 if ((word)(result + GC_page_size) > (word)(start + bytes)) return 0;
21330 return result;
21331}
21332static void block_unmap_inner(ptr_t start_addr, size_t len)
21333{
21334 if (0 == start_addr) return;
21335#ifdef USE_WINALLOC
21336 while (len != 0) {
21337 MEMORY_BASIC_INFORMATION mem_info;
21338 word free_len;
21339 if (VirtualQuery(start_addr, &mem_info, sizeof(mem_info))
21340 != sizeof(mem_info))
21341 ABORT("Weird VirtualQuery result");
21342 free_len = (len < mem_info.RegionSize) ? len : mem_info.RegionSize;
21343 if (!VirtualFree(start_addr, free_len, MEM_DECOMMIT))
21344 ABORT("VirtualFree failed");
21345 GC_unmapped_bytes += free_len;
21346 start_addr += free_len;
21347 len -= free_len;
21348 }
21349#elif defined(SN_TARGET_PS3)
21350 ps3_free_mem(start_addr, len);
21351#else
21352 if (len != 0) {
21353#if defined(AIX) || defined(CYGWIN32) || defined(HAIKU) \
21354 || (defined(LINUX) && !defined(PREFER_MMAP_PROT_NONE)) \
21355 || defined(HPUX)
21356 if (mprotect(start_addr, len, PROT_NONE))
21357 ABORT_ON_REMAP_FAIL("unmap: mprotect", start_addr, len);
21358#elif defined(EMSCRIPTEN)
21359#else
21360 void * result = mmap(start_addr, len, PROT_NONE,
21361 MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON,
21362 zero_fd, 0);
21363 if (EXPECT(MAP_FAILED == result, FALSE))
21364 ABORT_ON_REMAP_FAIL("unmap: mmap", start_addr, len);
21365 if (result != (void *)start_addr)
21366 ABORT("unmap: mmap() result differs from start_addr");
21367#if defined(CPPCHECK) || defined(LINT2)
21368 GC_noop1((word)result);
21369#endif
21370#endif
21371 GC_unmapped_bytes += len;
21372 }
21373#endif
21374}
21375GC_INNER void GC_unmap(ptr_t start, size_t bytes)
21376{
21377 ptr_t start_addr = GC_unmap_start(start, bytes);
21378 ptr_t end_addr = GC_unmap_end(start, bytes);
21379 block_unmap_inner(start_addr, (size_t)(end_addr - start_addr));
21380}
21381GC_INNER void GC_remap(ptr_t start, size_t bytes)
21382{
21383 ptr_t start_addr = GC_unmap_start(start, bytes);
21384 ptr_t end_addr = GC_unmap_end(start, bytes);
21385 word len = end_addr - start_addr;
21386 if (0 == start_addr) return;
21387#ifdef USE_WINALLOC
21388 while (len != 0) {
21389 MEMORY_BASIC_INFORMATION mem_info;
21390 word alloc_len;
21391 ptr_t result;
21392 if (VirtualQuery(start_addr, &mem_info, sizeof(mem_info))
21393 != sizeof(mem_info))
21394 ABORT("Weird VirtualQuery result");
21395 alloc_len = (len < mem_info.RegionSize) ? len : mem_info.RegionSize;
21396 result = (ptr_t)VirtualAlloc(start_addr, alloc_len, MEM_COMMIT,
21397 GC_pages_executable
21398 ? PAGE_EXECUTE_READWRITE
21399 : PAGE_READWRITE);
21400 if (result != start_addr) {
21401 if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
21402 GetLastError() == ERROR_OUTOFMEMORY) {
21403 ABORT("Not enough memory to process remapping");
21404 } else {
21405 ABORT("VirtualAlloc remapping failed");
21406 }
21407 }
21408#ifdef LINT2
21409 GC_noop1((word)result);
21410#endif
21411 GC_unmapped_bytes -= alloc_len;
21412 start_addr += alloc_len;
21413 len -= alloc_len;
21414 }
21415#else
21416 {
21417#if defined(NACL) || defined(NETBSD)
21418 void *result = mmap(start_addr, len, (PROT_READ | PROT_WRITE)
21419 | (GC_pages_executable ? PROT_EXEC : 0),
21420 MAP_PRIVATE | MAP_FIXED | OPT_MAP_ANON,
21421 zero_fd, 0 );
21422 if (EXPECT(MAP_FAILED == result, FALSE))
21423 ABORT_ON_REMAP_FAIL("remap: mmap", start_addr, len);
21424 if (result != (void *)start_addr)
21425 ABORT("remap: mmap() result differs from start_addr");
21426#if defined(CPPCHECK) || defined(LINT2)
21427 GC_noop1((word)result);
21428#endif
21429#else
21430 if (mprotect(start_addr, len, (PROT_READ | PROT_WRITE)
21431 | (GC_pages_executable ? PROT_EXEC : 0)))
21432 ABORT_ON_REMAP_FAIL("remap: mprotect", start_addr, len);
21433#endif
21434 }
21435#undef IGNORE_PAGES_EXECUTABLE
21436 GC_unmapped_bytes -= len;
21437#endif
21438}
21439GC_INNER void GC_unmap_gap(ptr_t start1, size_t bytes1, ptr_t start2,
21440 size_t bytes2)
21441{
21442 ptr_t start1_addr = GC_unmap_start(start1, bytes1);
21443 ptr_t end1_addr = GC_unmap_end(start1, bytes1);
21444 ptr_t start2_addr = GC_unmap_start(start2, bytes2);
21445 ptr_t start_addr = end1_addr;
21446 ptr_t end_addr = start2_addr;
21447 GC_ASSERT(start1 + bytes1 == start2);
21448 if (0 == start1_addr) start_addr = GC_unmap_start(start1, bytes1 + bytes2);
21449 if (0 == start2_addr) end_addr = GC_unmap_end(start1, bytes1 + bytes2);
21450 block_unmap_inner(start_addr, (size_t)(end_addr - start_addr));
21451}
21452#endif
21453#ifndef THREADS
21454#ifdef EMSCRIPTEN
21455 static void scan_regs_cb(void *begin, void *end)
21456 {
21457 GC_push_all_stack((ptr_t)begin, (ptr_t)end);
21458 }
21459 STATIC void GC_CALLBACK GC_default_push_other_roots(void)
21460 {
21461 emscripten_scan_registers(scan_regs_cb);
21462 }
21463#else
21464#define GC_default_push_other_roots 0
21465#endif
21466#else
21467#ifdef PCR
21468PCR_ERes GC_push_thread_stack(PCR_Th_T *t, PCR_Any dummy)
21469{
21470 struct PCR_ThCtl_TInfoRep info;
21471 PCR_ERes result;
21472 info.ti_stkLow = info.ti_stkHi = 0;
21473 result = PCR_ThCtl_GetInfo(t, &info);
21474 GC_push_all_stack((ptr_t)(info.ti_stkLow), (ptr_t)(info.ti_stkHi));
21475 return(result);
21476}
21477PCR_ERes GC_push_old_obj(void *p, size_t size, PCR_Any data)
21478{
21479 GC_push_all_stack((ptr_t)p, (ptr_t)p + size);
21480 return(PCR_ERes_okay);
21481}
21482extern struct PCR_MM_ProcsRep * GC_old_allocator;
21483STATIC void GC_CALLBACK GC_default_push_other_roots(void)
21484{
21485 if ((*(GC_old_allocator->mmp_enumerate))(PCR_Bool_false,
21486 GC_push_old_obj, 0)
21487 != PCR_ERes_okay) {
21488 ABORT("Old object enumeration failed");
21489 }
21490 if (PCR_ERes_IsErr(
21491 PCR_ThCtl_ApplyToAllOtherThreads(GC_push_thread_stack,0))
21492 || PCR_ERes_IsErr(GC_push_thread_stack(PCR_Th_CurrThread(), 0))) {
21493 ABORT("Thread stack marking failed");
21494 }
21495}
21496#elif defined(SN_TARGET_PS3)
21497 STATIC void GC_CALLBACK GC_default_push_other_roots(void)
21498 {
21499 ABORT("GC_default_push_other_roots is not implemented");
21500 }
21501 void GC_push_thread_structures(void)
21502 {
21503 ABORT("GC_push_thread_structures is not implemented");
21504 }
21505#else
21506 STATIC void GC_CALLBACK GC_default_push_other_roots(void)
21507 {
21508 GC_push_all_stacks();
21509 }
21510#endif
21511#endif
21512GC_push_other_roots_proc GC_push_other_roots = GC_default_push_other_roots;
21513GC_API void GC_CALL GC_set_push_other_roots(GC_push_other_roots_proc fn)
21514{
21515 GC_push_other_roots = fn;
21516}
21517GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void)
21518{
21519 return GC_push_other_roots;
21520}
21521#if defined(SOFT_VDB) && !defined(NO_SOFT_VDB_LINUX_VER_RUNTIME_CHECK) \
21522 || (defined(GLIBC_2_19_TSX_BUG) && defined(THREADS))
21523 GC_INNER int GC_parse_version(int *pminor, const char *pverstr) {
21524 char *endp;
21525 unsigned long value = strtoul(pverstr, &endp, 10);
21526 int major = (int)value;
21527 if (major < 0 || (char *)pverstr == endp || (unsigned)major != value) {
21528 return -1;
21529 }
21530 if (*endp != '.') {
21531 *pminor = -1;
21532 } else {
21533 value = strtoul(endp + 1, &endp, 10);
21534 *pminor = (int)value;
21535 if (*pminor < 0 || (unsigned)(*pminor) != value) {
21536 return -1;
21537 }
21538 }
21539 return major;
21540 }
21541#endif
21542#if (defined(CHECKSUMS) && (defined(GWW_VDB) || defined(SOFT_VDB))) \
21543 || defined(PROC_VDB)
21544 STATIC void GC_or_pages(page_hash_table pht1, page_hash_table pht2)
21545 {
21546 unsigned i;
21547 for (i = 0; i < PHT_SIZE; i++) pht1[i] |= pht2[i];
21548 }
21549#endif
21550#ifdef GWW_VDB
21551#define GC_GWW_BUF_LEN (MAXHINCR * HBLKSIZE / 4096 )
21552 static PVOID gww_buf[GC_GWW_BUF_LEN];
21553#ifndef MPROTECT_VDB
21554#define GC_gww_dirty_init GC_dirty_init
21555#endif
21556 GC_INNER GC_bool GC_gww_dirty_init(void)
21557 {
21558 detect_GetWriteWatch();
21559 return GC_GWW_AVAILABLE();
21560 }
21561 GC_INLINE void GC_gww_read_dirty(GC_bool output_unneeded)
21562 {
21563 word i;
21564 if (!output_unneeded)
21565 BZERO(GC_grungy_pages, sizeof(GC_grungy_pages));
21566 for (i = 0; i != GC_n_heap_sects; ++i) {
21567 GC_ULONG_PTR count;
21568 do {
21569 PVOID * pages = gww_buf;
21570 DWORD page_size;
21571 count = GC_GWW_BUF_LEN;
21572 if ((*(GetWriteWatch_type)(word)GetWriteWatch_func)(
21573 WRITE_WATCH_FLAG_RESET,
21574 GC_heap_sects[i].hs_start,
21575 GC_heap_sects[i].hs_bytes,
21576 pages, &count, &page_size) != 0) {
21577 static int warn_count = 0;
21578 struct hblk * start = (struct hblk *)GC_heap_sects[i].hs_start;
21579 static struct hblk *last_warned = 0;
21580 size_t nblocks = divHBLKSZ(GC_heap_sects[i].hs_bytes);
21581 if (i != 0 && last_warned != start && warn_count++ < 5) {
21582 last_warned = start;
21583 WARN("GC_gww_read_dirty unexpectedly failed at %p: "
21584 "Falling back to marking all pages dirty\n", start);
21585 }
21586 if (!output_unneeded) {
21587 unsigned j;
21588 for (j = 0; j < nblocks; ++j) {
21589 word hash = PHT_HASH(start + j);
21590 set_pht_entry_from_index(GC_grungy_pages, hash);
21591 }
21592 }
21593 count = 1;
21594 } else if (!output_unneeded) {
21595 PVOID * pages_end = pages + count;
21596 while (pages != pages_end) {
21597 struct hblk * h = (struct hblk *) *pages++;
21598 struct hblk * h_end = (struct hblk *) ((char *) h + page_size);
21599 do {
21600 set_pht_entry_from_index(GC_grungy_pages, PHT_HASH(h));
21601 } while ((word)(++h) < (word)h_end);
21602 }
21603 }
21604 } while (count == GC_GWW_BUF_LEN);
21605 }
21606#ifdef CHECKSUMS
21607 GC_ASSERT(!output_unneeded);
21608 GC_or_pages(GC_written_pages, GC_grungy_pages);
21609#endif
21610 }
21611#elif defined(SOFT_VDB)
21612 static int clear_refs_fd = -1;
21613#define GC_GWW_AVAILABLE() (clear_refs_fd != -1)
21614#else
21615#define GC_GWW_AVAILABLE() FALSE
21616#endif
21617#ifdef DEFAULT_VDB
21618 GC_INNER GC_bool GC_dirty_init(void)
21619 {
21620 GC_VERBOSE_LOG_PRINTF("Initializing DEFAULT_VDB...\n");
21621 return TRUE;
21622 }
21623#endif
21624#ifndef GC_DISABLE_INCREMENTAL
21625#if !defined(THREADS) || defined(HAVE_LOCKFREE_AO_OR)
21626#define async_set_pht_entry_from_index(db, index) \
21627 set_pht_entry_from_index_concurrent(db, index)
21628#elif defined(AO_HAVE_test_and_set_acquire)
21629 GC_INNER volatile AO_TS_t GC_fault_handler_lock = AO_TS_INITIALIZER;
21630 static void async_set_pht_entry_from_index(volatile page_hash_table db,
21631 size_t index)
21632 {
21633 GC_acquire_dirty_lock();
21634 set_pht_entry_from_index(db, index);
21635 GC_release_dirty_lock();
21636 }
21637#else
21638#error No test_and_set operation: Introduces a race.
21639#endif
21640#endif
21641#ifdef MPROTECT_VDB
21642#ifdef DARWIN
21643#include <mach/vm_map.h>
21644 STATIC mach_port_t GC_task_self = 0;
21645#define PROTECT_INNER(addr, len, allow_write, C_msg_prefix) \
21646 if (vm_protect(GC_task_self, (vm_address_t)(addr), (vm_size_t)(len), \
21647 FALSE, VM_PROT_READ \
21648 | ((allow_write) ? VM_PROT_WRITE : 0) \
21649 | (GC_pages_executable ? VM_PROT_EXECUTE : 0)) \
21650 == KERN_SUCCESS) {} else ABORT(C_msg_prefix \
21651 "vm_protect() failed")
21652#elif !defined(USE_WINALLOC)
21653#include <sys/mman.h>
21654#include <signal.h>
21655#if !defined(CYGWIN32) && !defined(HAIKU)
21656#include <sys/syscall.h>
21657#endif
21658#define PROTECT_INNER(addr, len, allow_write, C_msg_prefix) \
21659 if (mprotect((caddr_t)(addr), (size_t)(len), \
21660 PROT_READ | ((allow_write) ? PROT_WRITE : 0) \
21661 | (GC_pages_executable ? PROT_EXEC : 0)) >= 0) { \
21662 } else if (GC_pages_executable) { \
21663 ABORT_ON_REMAP_FAIL(C_msg_prefix \
21664 "mprotect vdb executable pages", \
21665 addr, len); \
21666 } else ABORT_ON_REMAP_FAIL(C_msg_prefix "mprotect vdb", addr, len)
21667#undef IGNORE_PAGES_EXECUTABLE
21668#else
21669#ifndef MSWINCE
21670#include <signal.h>
21671#endif
21672 static DWORD protect_junk;
21673#define PROTECT_INNER(addr, len, allow_write, C_msg_prefix) \
21674 if (VirtualProtect(addr, len, \
21675 GC_pages_executable ? \
21676 ((allow_write) ? PAGE_EXECUTE_READWRITE : \
21677 PAGE_EXECUTE_READ) : \
21678 (allow_write) ? PAGE_READWRITE : \
21679 PAGE_READONLY, \
21680 &protect_junk)) { \
21681 } else ABORT_ARG1(C_msg_prefix "VirtualProtect failed", \
21682 ": errcode= 0x%X", (unsigned)GetLastError())
21683#endif
21684#define PROTECT(addr, len) PROTECT_INNER(addr, len, FALSE, "")
21685#define UNPROTECT(addr, len) PROTECT_INNER(addr, len, TRUE, "un-")
21686#if defined(MSWIN32)
21687 typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_HNDLR_PTR;
21688#undef SIG_DFL
21689#define SIG_DFL (LPTOP_LEVEL_EXCEPTION_FILTER)((signed_word)-1)
21690#elif defined(MSWINCE)
21691 typedef LONG (WINAPI *SIG_HNDLR_PTR)(struct _EXCEPTION_POINTERS *);
21692#undef SIG_DFL
21693#define SIG_DFL (SIG_HNDLR_PTR) (-1)
21694#elif defined(DARWIN)
21695 typedef void (* SIG_HNDLR_PTR)();
21696#else
21697 typedef void (* SIG_HNDLR_PTR)(int, siginfo_t *, void *);
21698 typedef void (* PLAIN_HNDLR_PTR)(int);
21699#endif
21700#if defined(__GLIBC__)
21701#if __GLIBC__ < 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ < 2
21702#error glibc too old?
21703#endif
21704#endif
21705#ifndef DARWIN
21706 STATIC SIG_HNDLR_PTR GC_old_segv_handler = 0;
21707#if defined(FREEBSD) || defined(HPUX) || defined(HURD) || defined(LINUX)
21708 STATIC SIG_HNDLR_PTR GC_old_bus_handler = 0;
21709#ifndef LINUX
21710 STATIC GC_bool GC_old_bus_handler_used_si = FALSE;
21711#endif
21712#endif
21713#if !defined(MSWIN32) && !defined(MSWINCE)
21714 STATIC GC_bool GC_old_segv_handler_used_si = FALSE;
21715#endif
21716#endif
21717#ifdef THREADS
21718 GC_ATTR_NO_SANITIZE_THREAD
21719 static GC_bool is_header_found_async(void *addr)
21720 {
21721#ifdef HASH_TL
21722 hdr *result;
21723 GET_HDR((ptr_t)addr, result);
21724 return result != NULL;
21725#else
21726 return HDR_INNER(addr) != NULL;
21727#endif
21728 }
21729#else
21730#define is_header_found_async(addr) (HDR(addr) != NULL)
21731#endif
21732#ifndef DARWIN
21733#if !defined(MSWIN32) && !defined(MSWINCE)
21734#include <errno.h>
21735#if defined(FREEBSD) || defined(HURD) || defined(HPUX)
21736#define SIG_OK (sig == SIGBUS || sig == SIGSEGV)
21737#else
21738#define SIG_OK (sig == SIGSEGV)
21739#endif
21740#if defined(FREEBSD)
21741#ifndef SEGV_ACCERR
21742#define SEGV_ACCERR 2
21743#endif
21744#if defined(AARCH64) || defined(ARM32) || defined(MIPS) \
21745 || __FreeBSD__ >= 7
21746#define CODE_OK (si -> si_code == SEGV_ACCERR)
21747#elif defined(POWERPC)
21748#define AIM
21749#include <machine/trap.h>
21750#define CODE_OK (si -> si_code == EXC_DSI \
21751 || si -> si_code == SEGV_ACCERR)
21752#else
21753#define CODE_OK (si -> si_code == BUS_PAGE_FAULT \
21754 || si -> si_code == SEGV_ACCERR)
21755#endif
21756#elif defined(OSF1)
21757#define CODE_OK (si -> si_code == 2 )
21758#elif defined(IRIX5)
21759#define CODE_OK (si -> si_code == EACCES)
21760#elif defined(CYGWIN32) || defined(HAIKU) || defined(HURD)
21761#define CODE_OK TRUE
21762#elif defined(LINUX)
21763#define CODE_OK TRUE
21764#elif defined(HPUX)
21765#define CODE_OK (si -> si_code == SEGV_ACCERR \
21766 || si -> si_code == BUS_ADRERR \
21767 || si -> si_code == BUS_UNKNOWN \
21768 || si -> si_code == SEGV_UNKNOWN \
21769 || si -> si_code == BUS_OBJERR)
21770#elif defined(SUNOS5SIGS)
21771#define CODE_OK (si -> si_code == SEGV_ACCERR)
21772#endif
21773#ifndef NO_GETCONTEXT
21774#include <ucontext.h>
21775#endif
21776 STATIC void GC_write_fault_handler(int sig, siginfo_t *si, void *raw_sc)
21777#else
21778#define SIG_OK (exc_info -> ExceptionRecord -> ExceptionCode \
21779 == STATUS_ACCESS_VIOLATION)
21780#define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] \
21781 == 1)
21782 STATIC LONG WINAPI GC_write_fault_handler(
21783 struct _EXCEPTION_POINTERS *exc_info)
21784#endif
21785 {
21786#if !defined(MSWIN32) && !defined(MSWINCE)
21787 char *addr = (char *)si->si_addr;
21788#else
21789 char * addr = (char *) (exc_info -> ExceptionRecord
21790 -> ExceptionInformation[1]);
21791#endif
21792 if (SIG_OK && CODE_OK) {
21793 struct hblk * h = (struct hblk *)((word)addr & ~(GC_page_size-1));
21794 GC_bool in_allocd_block;
21795 size_t i;
21796 GC_ASSERT(GC_page_size != 0);
21797#ifdef CHECKSUMS
21798 GC_record_fault(h);
21799#endif
21800#ifdef SUNOS5SIGS
21801 in_allocd_block = FALSE;
21802 for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
21803 if (is_header_found_async(&h[i])) {
21804 in_allocd_block = TRUE;
21805 break;
21806 }
21807 }
21808#else
21809 in_allocd_block = is_header_found_async(addr);
21810#endif
21811 if (!in_allocd_block) {
21812 SIG_HNDLR_PTR old_handler;
21813#if defined(MSWIN32) || defined(MSWINCE)
21814 old_handler = GC_old_segv_handler;
21815#else
21816 GC_bool used_si;
21817#if defined(FREEBSD) || defined(HURD) || defined(HPUX)
21818 if (sig == SIGBUS) {
21819 old_handler = GC_old_bus_handler;
21820 used_si = GC_old_bus_handler_used_si;
21821 } else
21822#endif
21823 {
21824 old_handler = GC_old_segv_handler;
21825 used_si = GC_old_segv_handler_used_si;
21826 }
21827#endif
21828 if (old_handler == (SIG_HNDLR_PTR)(signed_word)SIG_DFL) {
21829#if !defined(MSWIN32) && !defined(MSWINCE)
21830 ABORT_ARG1("Unexpected bus error or segmentation fault",
21831 " at %p", (void *)addr);
21832#else
21833 return(EXCEPTION_CONTINUE_SEARCH);
21834#endif
21835 } else {
21836#if defined(MSWIN32) || defined(MSWINCE)
21837 return((*old_handler)(exc_info));
21838#else
21839 if (used_si)
21840 ((SIG_HNDLR_PTR)old_handler) (sig, si, raw_sc);
21841 else
21842 ((PLAIN_HNDLR_PTR)(signed_word)old_handler)(sig);
21843 return;
21844#endif
21845 }
21846 }
21847 UNPROTECT(h, GC_page_size);
21848 for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
21849 word index = PHT_HASH(h+i);
21850 async_set_pht_entry_from_index(GC_dirty_pages, index);
21851 }
21852#if defined(MSWIN32) || defined(MSWINCE)
21853 return(EXCEPTION_CONTINUE_EXECUTION);
21854#else
21855 return;
21856#endif
21857 }
21858#if defined(MSWIN32) || defined(MSWINCE)
21859 return EXCEPTION_CONTINUE_SEARCH;
21860#else
21861 ABORT_ARG1("Unexpected bus error or segmentation fault",
21862 " at %p", (void *)addr);
21863#endif
21864 }
21865#if defined(GC_WIN32_THREADS) && !defined(CYGWIN32)
21866 GC_INNER void GC_set_write_fault_handler(void)
21867 {
21868 SetUnhandledExceptionFilter(GC_write_fault_handler);
21869 }
21870#endif
21871#ifdef SOFT_VDB
21872 static GC_bool soft_dirty_init(void);
21873#endif
21874 GC_INNER GC_bool GC_dirty_init(void)
21875 {
21876#if !defined(MSWIN32) && !defined(MSWINCE)
21877 struct sigaction act, oldact;
21878 act.sa_flags = SA_RESTART | SA_SIGINFO;
21879 act.sa_sigaction = GC_write_fault_handler;
21880 (void)sigemptyset(&act.sa_mask);
21881#if defined(THREADS) && !defined(GC_OPENBSD_UTHREADS) \
21882 && !defined(GC_WIN32_THREADS) && !defined(NACL)
21883 (void)sigaddset(&act.sa_mask, GC_get_suspend_signal());
21884#endif
21885#endif
21886 GC_VERBOSE_LOG_PRINTF(
21887 "Initializing mprotect virtual dirty bit implementation\n");
21888 if (GC_page_size % HBLKSIZE != 0) {
21889 ABORT("Page size not multiple of HBLKSIZE");
21890 }
21891#ifdef GWW_VDB
21892 if (GC_gww_dirty_init()) {
21893 GC_COND_LOG_PRINTF("Using GetWriteWatch()\n");
21894 return TRUE;
21895 }
21896#elif defined(SOFT_VDB)
21897 if (soft_dirty_init()) {
21898 GC_COND_LOG_PRINTF("Using soft-dirty bit feature\n");
21899 return TRUE;
21900 }
21901#endif
21902#ifdef MSWIN32
21903 GC_old_segv_handler = SetUnhandledExceptionFilter(
21904 GC_write_fault_handler);
21905 if (GC_old_segv_handler != NULL) {
21906 GC_COND_LOG_PRINTF("Replaced other UnhandledExceptionFilter\n");
21907 } else {
21908 GC_old_segv_handler = SIG_DFL;
21909 }
21910#elif defined(MSWINCE)
21911#else
21912#if defined(GC_IRIX_THREADS)
21913 sigaction(SIGSEGV, 0, &oldact);
21914 sigaction(SIGSEGV, &act, 0);
21915#else
21916 {
21917 int res = sigaction(SIGSEGV, &act, &oldact);
21918 if (res != 0) ABORT("Sigaction failed");
21919 }
21920#endif
21921 if (oldact.sa_flags & SA_SIGINFO) {
21922 GC_old_segv_handler = oldact.sa_sigaction;
21923 GC_old_segv_handler_used_si = TRUE;
21924 } else {
21925 GC_old_segv_handler = (SIG_HNDLR_PTR)(signed_word)oldact.sa_handler;
21926 GC_old_segv_handler_used_si = FALSE;
21927 }
21928 if (GC_old_segv_handler == (SIG_HNDLR_PTR)(signed_word)SIG_IGN) {
21929 WARN("Previously ignored segmentation violation!?\n", 0);
21930 GC_old_segv_handler = (SIG_HNDLR_PTR)(signed_word)SIG_DFL;
21931 }
21932 if (GC_old_segv_handler != (SIG_HNDLR_PTR)(signed_word)SIG_DFL) {
21933 GC_VERBOSE_LOG_PRINTF("Replaced other SIGSEGV handler\n");
21934 }
21935#if defined(HPUX) || defined(LINUX) || defined(HURD) \
21936 || (defined(FREEBSD) && (defined(__GLIBC__) || defined(SUNOS5SIGS)))
21937 sigaction(SIGBUS, &act, &oldact);
21938 if ((oldact.sa_flags & SA_SIGINFO) != 0) {
21939 GC_old_bus_handler = oldact.sa_sigaction;
21940#if !defined(LINUX)
21941 GC_old_bus_handler_used_si = TRUE;
21942#endif
21943 } else {
21944 GC_old_bus_handler = (SIG_HNDLR_PTR)(signed_word)oldact.sa_handler;
21945 }
21946 if (GC_old_bus_handler == (SIG_HNDLR_PTR)(signed_word)SIG_IGN) {
21947 WARN("Previously ignored bus error!?\n", 0);
21948#if !defined(LINUX)
21949 GC_old_bus_handler = (SIG_HNDLR_PTR)(signed_word)SIG_DFL;
21950#else
21951#endif
21952 } else if (GC_old_bus_handler != (SIG_HNDLR_PTR)(signed_word)SIG_DFL) {
21953 GC_VERBOSE_LOG_PRINTF("Replaced other SIGBUS handler\n");
21954 }
21955#endif
21956#endif
21957#if defined(CPPCHECK) && defined(ADDRESS_SANITIZER)
21958 GC_noop1((word)&__asan_default_options);
21959#endif
21960 return TRUE;
21961 }
21962#endif
21963GC_API int GC_CALL GC_incremental_protection_needs(void)
21964{
21965 GC_ASSERT(GC_is_initialized);
21966#if defined(GWW_VDB) || defined(SOFT_VDB)
21967 if (GC_GWW_AVAILABLE())
21968 return GC_PROTECTS_NONE;
21969#endif
21970 if (GC_page_size == HBLKSIZE) {
21971 return GC_PROTECTS_POINTER_HEAP;
21972 } else {
21973 return GC_PROTECTS_POINTER_HEAP | GC_PROTECTS_PTRFREE_HEAP;
21974 }
21975}
21976#define HAVE_INCREMENTAL_PROTECTION_NEEDS
21977#define IS_PTRFREE(hhdr) ((hhdr)->hb_descr == 0)
21978#define PAGE_ALIGNED(x) !((word)(x) & (GC_page_size - 1))
21979STATIC void GC_protect_heap(void)
21980{
21981 unsigned i;
21982 GC_bool protect_all =
21983 (0 != (GC_incremental_protection_needs() & GC_PROTECTS_PTRFREE_HEAP));
21984 GC_ASSERT(GC_page_size != 0);
21985 for (i = 0; i < GC_n_heap_sects; i++) {
21986 ptr_t start = GC_heap_sects[i].hs_start;
21987 size_t len = GC_heap_sects[i].hs_bytes;
21988 if (protect_all) {
21989 PROTECT(start, len);
21990 } else {
21991 struct hblk * current;
21992 struct hblk * current_start;
21993 struct hblk * limit;
21994 GC_ASSERT(PAGE_ALIGNED(len));
21995 GC_ASSERT(PAGE_ALIGNED(start));
21996 current_start = current = (struct hblk *)start;
21997 limit = (struct hblk *)(start + len);
21998 while ((word)current < (word)limit) {
21999 hdr * hhdr;
22000 word nhblks;
22001 GC_bool is_ptrfree;
22002 GC_ASSERT(PAGE_ALIGNED(current));
22003 GET_HDR(current, hhdr);
22004 if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
22005 GC_ASSERT(current_start == current);
22006 current_start = ++current;
22007 continue;
22008 }
22009 if (HBLK_IS_FREE(hhdr)) {
22010 GC_ASSERT(PAGE_ALIGNED(hhdr -> hb_sz));
22011 nhblks = divHBLKSZ(hhdr -> hb_sz);
22012 is_ptrfree = TRUE;
22013 } else {
22014 nhblks = OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
22015 is_ptrfree = IS_PTRFREE(hhdr);
22016 }
22017 if (is_ptrfree) {
22018 if ((word)current_start < (word)current) {
22019 PROTECT(current_start, (ptr_t)current - (ptr_t)current_start);
22020 }
22021 current_start = (current += nhblks);
22022 } else {
22023 current += nhblks;
22024 }
22025 }
22026 if ((word)current_start < (word)current) {
22027 PROTECT(current_start, (ptr_t)current - (ptr_t)current_start);
22028 }
22029 }
22030 }
22031}
22032#endif
22033#if !defined(THREADS) && (defined(PROC_VDB) || defined(SOFT_VDB))
22034 static pid_t saved_proc_pid;
22035#endif
22036#ifdef PROC_VDB
22037#include <errno.h>
22038#include <sys/types.h>
22039#include <sys/signal.h>
22040#include <sys/syscall.h>
22041#include <sys/stat.h>
22042#ifdef GC_NO_SYS_FAULT_H
22043#define PG_MODIFIED 1
22044 struct prpageheader {
22045 int dummy[2];
22046 unsigned long pr_nmap;
22047 unsigned long pr_npage;
22048 };
22049 struct prasmap {
22050 char *pr_vaddr;
22051 size_t pr_npage;
22052 char dummy1[64+8];
22053 unsigned pr_mflags;
22054 unsigned pr_pagesize;
22055 int dummy2[2];
22056 };
22057#else
22058#include <sys/fault.h>
22059#include <sys/procfs.h>
22060#endif
22061#define INITIAL_BUF_SZ 16384
22062 STATIC size_t GC_proc_buf_size = INITIAL_BUF_SZ;
22063 STATIC char *GC_proc_buf = NULL;
22064 STATIC int GC_proc_fd = -1;
22065 static GC_bool proc_dirty_open_files(void)
22066 {
22067 char buf[40];
22068 pid_t pid = getpid();
22069 (void)snprintf(buf, sizeof(buf), "/proc/%ld/pagedata", (long)pid);
22070 buf[sizeof(buf) - 1] = '\0';
22071 GC_proc_fd = open(buf, O_RDONLY);
22072 if (-1 == GC_proc_fd) {
22073 WARN("/proc open failed; cannot enable GC incremental mode\n", 0);
22074 return FALSE;
22075 }
22076 if (syscall(SYS_fcntl, GC_proc_fd, F_SETFD, FD_CLOEXEC) == -1)
22077 WARN("Could not set FD_CLOEXEC for /proc\n", 0);
22078#ifndef THREADS
22079 saved_proc_pid = pid;
22080#endif
22081 return TRUE;
22082 }
22083#ifdef CAN_HANDLE_FORK
22084 GC_INNER void GC_dirty_update_child(void)
22085 {
22086 if (-1 == GC_proc_fd)
22087 return;
22088 close(GC_proc_fd);
22089 if (!proc_dirty_open_files())
22090 GC_incremental = FALSE;
22091 }
22092#endif
22093GC_INNER GC_bool GC_dirty_init(void)
22094{
22095 if (GC_bytes_allocd != 0 || GC_bytes_allocd_before_gc != 0) {
22096 memset(GC_written_pages, 0xff, sizeof(page_hash_table));
22097 GC_VERBOSE_LOG_PRINTF(
22098 "Allocated %lu bytes: all pages may have been written\n",
22099 (unsigned long)(GC_bytes_allocd + GC_bytes_allocd_before_gc));
22100 }
22101 if (!proc_dirty_open_files())
22102 return FALSE;
22103 GC_proc_buf = GC_scratch_alloc(GC_proc_buf_size);
22104 if (GC_proc_buf == NULL)
22105 ABORT("Insufficient space for /proc read");
22106 return TRUE;
22107}
22108GC_INLINE void GC_proc_read_dirty(GC_bool output_unneeded)
22109{
22110 int nmaps;
22111 char * bufp = GC_proc_buf;
22112 int i;
22113#ifndef THREADS
22114 if (getpid() != saved_proc_pid
22115 && (-1 == GC_proc_fd
22116 || (close(GC_proc_fd), !proc_dirty_open_files()))) {
22117 if (!output_unneeded)
22118 memset(GC_grungy_pages, 0xff, sizeof(page_hash_table));
22119 memset(GC_written_pages, 0xff, sizeof(page_hash_table));
22120 return;
22121 }
22122#endif
22123 BZERO(GC_grungy_pages, sizeof(GC_grungy_pages));
22124 if (PROC_READ(GC_proc_fd, bufp, GC_proc_buf_size) <= 0) {
22125 size_t new_size = 2 * GC_proc_buf_size;
22126 char *new_buf;
22127 WARN("/proc read failed: GC_proc_buf_size= %" WARN_PRIdPTR "\n",
22128 (signed_word)GC_proc_buf_size);
22129 new_buf = GC_scratch_alloc(new_size);
22130 if (new_buf != 0) {
22131 GC_scratch_recycle_no_gww(bufp, GC_proc_buf_size);
22132 GC_proc_buf = bufp = new_buf;
22133 GC_proc_buf_size = new_size;
22134 }
22135 if (PROC_READ(GC_proc_fd, bufp, GC_proc_buf_size) <= 0) {
22136 WARN("Insufficient space for /proc read\n", 0);
22137 if (!output_unneeded)
22138 memset(GC_grungy_pages, 0xff, sizeof (page_hash_table));
22139 memset(GC_written_pages, 0xff, sizeof(page_hash_table));
22140 return;
22141 }
22142 }
22143 nmaps = ((struct prpageheader *)bufp) -> pr_nmap;
22144#ifdef DEBUG_DIRTY_BITS
22145 GC_log_printf("Proc VDB read: pr_nmap= %u, pr_npage= %lu\n",
22146 nmaps, ((struct prpageheader *)bufp)->pr_npage);
22147#endif
22148#if defined(GC_NO_SYS_FAULT_H) && defined(CPPCHECK)
22149 GC_noop1(((struct prpageheader *)bufp)->dummy[0]);
22150#endif
22151 bufp += sizeof(struct prpageheader);
22152 for (i = 0; i < nmaps; i++) {
22153 struct prasmap * map = (struct prasmap *)bufp;
22154 ptr_t vaddr = (ptr_t)(map -> pr_vaddr);
22155 unsigned long npages = map -> pr_npage;
22156 unsigned pagesize = map -> pr_pagesize;
22157 ptr_t limit;
22158#if defined(GC_NO_SYS_FAULT_H) && defined(CPPCHECK)
22159 GC_noop1(map->dummy1[0] + map->dummy2[0]);
22160#endif
22161#ifdef DEBUG_DIRTY_BITS
22162 GC_log_printf(
22163 "pr_vaddr= %p, npage= %lu, mflags= 0x%x, pagesize= 0x%x\n",
22164 (void *)vaddr, npages, map->pr_mflags, pagesize);
22165#endif
22166 bufp += sizeof(struct prasmap);
22167 limit = vaddr + pagesize * npages;
22168 for (; (word)vaddr < (word)limit; vaddr += pagesize) {
22169 if ((*bufp++) & PG_MODIFIED) {
22170 struct hblk * h;
22171 ptr_t next_vaddr = vaddr + pagesize;
22172#ifdef DEBUG_DIRTY_BITS
22173 GC_log_printf("dirty page at: %p\n", (void *)vaddr);
22174#endif
22175 for (h = (struct hblk *)vaddr;
22176 (word)h < (word)next_vaddr; h++) {
22177 word index = PHT_HASH(h);
22178 set_pht_entry_from_index(GC_grungy_pages, index);
22179 }
22180 }
22181 }
22182 bufp = (char *)(((word)bufp + (sizeof(long)-1))
22183 & ~(word)(sizeof(long)-1));
22184 }
22185#ifdef DEBUG_DIRTY_BITS
22186 GC_log_printf("Proc VDB read done\n");
22187#endif
22188 GC_or_pages(GC_written_pages, GC_grungy_pages);
22189}
22190#endif
22191#ifdef SOFT_VDB
22192#ifndef VDB_BUF_SZ
22193#define VDB_BUF_SZ 16384
22194#endif
22195 static int open_proc_fd(pid_t pid, const char *proc_filename, int mode)
22196 {
22197 int f;
22198 char buf[40];
22199 (void)snprintf(buf, sizeof(buf), "/proc/%ld/%s", (long)pid,
22200 proc_filename);
22201 buf[sizeof(buf) - 1] = '\0';
22202 f = open(buf, mode);
22203 if (-1 == f) {
22204 WARN("/proc/self/%s open failed; cannot enable GC incremental mode\n",
22205 proc_filename);
22206 } else if (fcntl(f, F_SETFD, FD_CLOEXEC) == -1) {
22207 WARN("Could not set FD_CLOEXEC for /proc\n", 0);
22208 }
22209 return f;
22210 }
22211#include <stdint.h>
22212 typedef uint64_t pagemap_elem_t;
22213 static pagemap_elem_t *soft_vdb_buf;
22214 static int pagemap_fd;
22215 static GC_bool soft_dirty_open_files(void)
22216 {
22217 pid_t pid = getpid();
22218 clear_refs_fd = open_proc_fd(pid, "clear_refs", O_WRONLY);
22219 if (-1 == clear_refs_fd)
22220 return FALSE;
22221 pagemap_fd = open_proc_fd(pid, "pagemap", O_RDONLY);
22222 if (-1 == pagemap_fd) {
22223 close(clear_refs_fd);
22224 clear_refs_fd = -1;
22225 return FALSE;
22226 }
22227#ifndef THREADS
22228 saved_proc_pid = pid;
22229#endif
22230 return TRUE;
22231 }
22232#ifdef CAN_HANDLE_FORK
22233 GC_INNER void GC_dirty_update_child(void)
22234 {
22235 if (-1 == clear_refs_fd)
22236 return;
22237 close(clear_refs_fd);
22238 close(pagemap_fd);
22239 if (!soft_dirty_open_files())
22240 GC_incremental = FALSE;
22241 }
22242#endif
22243#define PM_SOFTDIRTY_MASK ((pagemap_elem_t)1 << 55)
22244 static GC_bool detect_soft_dirty_supported(ptr_t vaddr)
22245 {
22246 off_t fpos;
22247 pagemap_elem_t buf[1];
22248 *vaddr = 1;
22249 GC_ASSERT(GC_page_size != 0);
22250 fpos = (off_t)((word)vaddr / GC_page_size * sizeof(pagemap_elem_t));
22251 if (lseek(pagemap_fd, fpos, SEEK_SET) == (off_t)(-1))
22252 return FALSE;
22253 if (PROC_READ(pagemap_fd, buf, sizeof(buf)) != (int)sizeof(buf))
22254 return FALSE;
22255 return (buf[0] & PM_SOFTDIRTY_MASK) != 0;
22256 }
22257#ifndef NO_SOFT_VDB_LINUX_VER_RUNTIME_CHECK
22258#include <sys/utsname.h>
22259#include <string.h>
22260 static GC_bool ensure_min_linux_ver(int major, int minor) {
22261 struct utsname info;
22262 int actual_major;
22263 int actual_minor = -1;
22264 if (uname(&info) == -1) {
22265 return FALSE;
22266 }
22267 if (strcmp(info.sysname, "Linux")) {
22268 WARN("Cannot ensure Linux version as running on other OS: %s\n",
22269 info.sysname);
22270 return FALSE;
22271 }
22272 actual_major = GC_parse_version(&actual_minor, info.release);
22273 return actual_major > major
22274 || (actual_major == major && actual_minor >= minor);
22275 }
22276#endif
22277#ifdef MPROTECT_VDB
22278 static GC_bool soft_dirty_init(void)
22279#else
22280 GC_INNER GC_bool GC_dirty_init(void)
22281#endif
22282 {
22283 GC_ASSERT(NULL == soft_vdb_buf);
22284#ifdef MPROTECT_VDB
22285 char * str = GETENV("GC_USE_GETWRITEWATCH");
22286#ifdef GC_PREFER_MPROTECT_VDB
22287 if (str == NULL || (*str == '0' && *(str + 1) == '\0'))
22288 return FALSE;
22289#else
22290 if (str != NULL && *str == '0' && *(str + 1) == '\0')
22291 return FALSE;
22292#endif
22293#endif
22294#ifndef NO_SOFT_VDB_LINUX_VER_RUNTIME_CHECK
22295 if (!ensure_min_linux_ver(3, 18)) {
22296 GC_COND_LOG_PRINTF(
22297 "Running on old kernel lacking correct soft-dirty bit support\n");
22298 return FALSE;
22299 }
22300#endif
22301 if (!soft_dirty_open_files())
22302 return FALSE;
22303 soft_vdb_buf = (pagemap_elem_t *)GC_scratch_alloc(VDB_BUF_SZ);
22304 if (NULL == soft_vdb_buf)
22305 ABORT("Insufficient space for /proc pagemap buffer");
22306 if (!detect_soft_dirty_supported((ptr_t)soft_vdb_buf)) {
22307 GC_COND_LOG_PRINTF("Soft-dirty bit is not supported by kernel\n");
22308 GC_scratch_recycle_no_gww(soft_vdb_buf, VDB_BUF_SZ);
22309 soft_vdb_buf = NULL;
22310 close(clear_refs_fd);
22311 clear_refs_fd = -1;
22312 close(pagemap_fd);
22313 return FALSE;
22314 }
22315 return TRUE;
22316 }
22317 static off_t pagemap_buf_fpos;
22318 static size_t pagemap_buf_len;
22319 static const pagemap_elem_t *pagemap_buffered_read(size_t *pres,
22320 off_t fpos, size_t len,
22321 off_t next_fpos_hint)
22322 {
22323 ssize_t res;
22324 size_t ofs;
22325 GC_ASSERT(len > 0);
22326 if (pagemap_buf_fpos <= fpos
22327 && fpos < pagemap_buf_fpos + (off_t)pagemap_buf_len) {
22328 ofs = (size_t)(fpos - pagemap_buf_fpos);
22329 res = (ssize_t)(pagemap_buf_fpos + pagemap_buf_len - fpos);
22330 } else {
22331 off_t aligned_pos = fpos & ~(GC_page_size < VDB_BUF_SZ
22332 ? GC_page_size-1 : VDB_BUF_SZ-1);
22333 for (;;) {
22334 size_t count;
22335 if ((0 == pagemap_buf_len
22336 || pagemap_buf_fpos + (off_t)pagemap_buf_len != aligned_pos)
22337 && lseek(pagemap_fd, aligned_pos, SEEK_SET) == (off_t)(-1))
22338 ABORT_ARG2("Failed to lseek /proc/self/pagemap",
22339 ": offset= %lu, errno= %d", (unsigned long)fpos, errno);
22340 ofs = (size_t)(fpos - aligned_pos);
22341 GC_ASSERT(ofs < VDB_BUF_SZ);
22342 if (next_fpos_hint > aligned_pos
22343 && next_fpos_hint - aligned_pos < VDB_BUF_SZ) {
22344 count = VDB_BUF_SZ;
22345 } else {
22346 count = len + ofs;
22347 if (count > VDB_BUF_SZ)
22348 count = VDB_BUF_SZ;
22349 }
22350 GC_ASSERT(count % sizeof(pagemap_elem_t) == 0);
22351 res = PROC_READ(pagemap_fd, soft_vdb_buf, count);
22352 if (res > (ssize_t)ofs)
22353 break;
22354 if (res <= 0)
22355 ABORT_ARG1("Failed to read /proc/self/pagemap",
22356 ": errno= %d", res < 0 ? errno : 0);
22357 aligned_pos = fpos;
22358 }
22359 pagemap_buf_fpos = aligned_pos;
22360 pagemap_buf_len = (size_t)res;
22361 res -= (ssize_t)ofs;
22362 }
22363 GC_ASSERT(ofs % sizeof(pagemap_elem_t) == 0);
22364 *pres = (size_t)res < len ? (size_t)res : len;
22365 return &soft_vdb_buf[ofs / sizeof(pagemap_elem_t)];
22366 }
22367 static void soft_set_grungy_pages(ptr_t vaddr , ptr_t limit,
22368 ptr_t next_start_hint)
22369 {
22370 GC_ASSERT(GC_page_size != 0);
22371 while ((word)vaddr < (word)limit) {
22372 size_t res;
22373 word limit_buf;
22374 const pagemap_elem_t *bufp = pagemap_buffered_read(&res,
22375 (off_t)((word)vaddr / GC_page_size * sizeof(pagemap_elem_t)),
22376 (size_t)((((word)limit - (word)vaddr + GC_page_size-1)
22377 / GC_page_size) * sizeof(pagemap_elem_t)),
22378 (off_t)((word)next_start_hint / GC_page_size
22379 * sizeof(pagemap_elem_t)));
22380 if (res % sizeof(pagemap_elem_t) != 0) {
22381 memset(GC_grungy_pages, 0xff, sizeof(page_hash_table));
22382 WARN("Incomplete read of pagemap, not multiple of entry size\n", 0);
22383 break;
22384 }
22385 limit_buf = ((word)vaddr & ~(GC_page_size-1))
22386 + (res / sizeof(pagemap_elem_t)) * GC_page_size;
22387 for (; (word)vaddr < limit_buf; vaddr += GC_page_size, bufp++)
22388 if ((*bufp & PM_SOFTDIRTY_MASK) != 0) {
22389 struct hblk * h;
22390 ptr_t next_vaddr = vaddr + GC_page_size;
22391#ifdef DEBUG_DIRTY_BITS
22392 GC_log_printf("dirty page at: %p\n", (void *)vaddr);
22393#endif
22394 for (h = (struct hblk *)vaddr; (word)h < (word)next_vaddr; h++) {
22395 word index = PHT_HASH(h);
22396 set_pht_entry_from_index(GC_grungy_pages, index);
22397 }
22398 }
22399 }
22400 }
22401 GC_INLINE void GC_soft_read_dirty(GC_bool output_unneeded)
22402 {
22403 ssize_t res;
22404#ifndef THREADS
22405 if (getpid() != saved_proc_pid
22406 && (-1 == clear_refs_fd
22407 || (close(clear_refs_fd), close(pagemap_fd),
22408 !soft_dirty_open_files()))) {
22409 if (!output_unneeded) {
22410 memset(GC_grungy_pages, 0xff, sizeof(page_hash_table));
22411#ifdef CHECKSUMS
22412 memset(GC_written_pages, 0xff, sizeof(page_hash_table));
22413#endif
22414 }
22415 return;
22416 }
22417#endif
22418 if (!output_unneeded) {
22419 word i;
22420 BZERO(GC_grungy_pages, sizeof(GC_grungy_pages));
22421 pagemap_buf_len = 0;
22422 for (i = 0; i != GC_n_heap_sects; ++i) {
22423 ptr_t vaddr = GC_heap_sects[i].hs_start;
22424 soft_set_grungy_pages(vaddr, vaddr + GC_heap_sects[i].hs_bytes,
22425 i < GC_n_heap_sects-1 ?
22426 GC_heap_sects[i+1].hs_start : NULL);
22427 }
22428#ifdef CHECKSUMS
22429 GC_or_pages(GC_written_pages, GC_grungy_pages);
22430#endif
22431#ifndef NO_VDB_FOR_STATIC_ROOTS
22432 for (i = 0; (int)i < n_root_sets; ++i) {
22433 soft_set_grungy_pages(GC_static_roots[i].r_start,
22434 GC_static_roots[i].r_end,
22435 (int)i < n_root_sets-1 ?
22436 GC_static_roots[i+1].r_start : NULL);
22437 }
22438#endif
22439 }
22440 res = write(clear_refs_fd, "4\n", 2);
22441 if (res != 2)
22442 ABORT_ARG1("Failed to write to /proc/self/clear_refs",
22443 ": errno= %d", res < 0 ? errno : 0);
22444 }
22445#endif
22446#ifdef PCR_VDB
22447#include "vd/PCR_VD.h"
22448#define NPAGES (32*1024)
22449PCR_VD_DB GC_grungy_bits[NPAGES];
22450STATIC ptr_t GC_vd_base = NULL;
22451GC_INNER GC_bool GC_dirty_init(void)
22452{
22453 GC_vd_base = GC_heap_sects[0].hs_start;
22454 if (GC_vd_base == 0) {
22455 ABORT("Bad initial heap segment");
22456 }
22457 if (PCR_VD_Start(HBLKSIZE, GC_vd_base, NPAGES*HBLKSIZE)
22458 != PCR_ERes_okay) {
22459 ABORT("Dirty bit initialization failed");
22460 }
22461 return TRUE;
22462}
22463#endif
22464#ifndef GC_DISABLE_INCREMENTAL
22465 GC_INNER GC_bool GC_manual_vdb = FALSE;
22466 GC_INNER void GC_dirty_inner(const void *p)
22467 {
22468 word index = PHT_HASH(p);
22469#if defined(MPROTECT_VDB)
22470 GC_ASSERT(GC_manual_vdb);
22471#endif
22472 async_set_pht_entry_from_index(GC_dirty_pages, index);
22473 }
22474 GC_INNER void GC_read_dirty(GC_bool output_unneeded)
22475 {
22476 if (GC_manual_vdb
22477#if defined(MPROTECT_VDB)
22478 || !GC_GWW_AVAILABLE()
22479#endif
22480 ) {
22481 if (!output_unneeded)
22482 BCOPY(( void *)GC_dirty_pages, GC_grungy_pages,
22483 sizeof(GC_dirty_pages));
22484 BZERO(( void *)GC_dirty_pages,
22485 sizeof(GC_dirty_pages));
22486#ifdef MPROTECT_VDB
22487 if (!GC_manual_vdb)
22488 GC_protect_heap();
22489#endif
22490 return;
22491 }
22492#ifdef GWW_VDB
22493 GC_gww_read_dirty(output_unneeded);
22494#elif defined(PROC_VDB)
22495 GC_proc_read_dirty(output_unneeded);
22496#elif defined(SOFT_VDB)
22497 GC_soft_read_dirty(output_unneeded);
22498#elif defined(PCR_VDB)
22499 {
22500 static int onhs = 0;
22501 int nhs = GC_n_heap_sects;
22502 for (; onhs < nhs; onhs++) {
22503 PCR_VD_WriteProtectEnable(
22504 GC_heap_sects[onhs].hs_start,
22505 GC_heap_sects[onhs].hs_bytes);
22506 }
22507 }
22508 if (PCR_VD_Clear(GC_vd_base, NPAGES*HBLKSIZE, GC_grungy_bits)
22509 != PCR_ERes_okay) {
22510 ABORT("Dirty bit read failed");
22511 }
22512#endif
22513 }
22514#if !defined(NO_VDB_FOR_STATIC_ROOTS) && !defined(PROC_VDB)
22515 GC_INNER GC_bool GC_is_vdb_for_static_roots(void)
22516 {
22517 if (GC_manual_vdb) return FALSE;
22518#if defined(MPROTECT_VDB)
22519 return GC_GWW_AVAILABLE();
22520#else
22521 GC_ASSERT(GC_incremental);
22522 return TRUE;
22523#endif
22524 }
22525#endif
22526 GC_INNER GC_bool GC_page_was_dirty(struct hblk *h)
22527 {
22528 word index;
22529#ifdef PCR_VDB
22530 if (!GC_manual_vdb) {
22531 if ((word)h < (word)GC_vd_base
22532 || (word)h >= (word)(GC_vd_base + NPAGES * HBLKSIZE)) {
22533 return TRUE;
22534 }
22535 return GC_grungy_bits[h-(struct hblk*)GC_vd_base] & PCR_VD_DB_dirtyBit;
22536 }
22537#elif defined(DEFAULT_VDB)
22538 if (!GC_manual_vdb)
22539 return TRUE;
22540#elif defined(PROC_VDB)
22541 if (GC_manual_vdb)
22542#endif
22543 {
22544 if (NULL == HDR(h))
22545 return TRUE;
22546 }
22547 index = PHT_HASH(h);
22548 return get_pht_entry_from_index(GC_grungy_pages, index);
22549 }
22550#if defined(CHECKSUMS) || defined(PROC_VDB)
22551 GC_INNER GC_bool GC_page_was_ever_dirty(struct hblk *h)
22552 {
22553#if defined(GWW_VDB) || defined(PROC_VDB) || defined(SOFT_VDB)
22554 word index;
22555#ifdef MPROTECT_VDB
22556 if (!GC_GWW_AVAILABLE())
22557 return TRUE;
22558#endif
22559#if defined(PROC_VDB)
22560 if (GC_manual_vdb)
22561#endif
22562 {
22563 if (NULL == HDR(h))
22564 return TRUE;
22565 }
22566 index = PHT_HASH(h);
22567 return get_pht_entry_from_index(GC_written_pages, index);
22568#else
22569 (void)h;
22570 return TRUE;
22571#endif
22572 }
22573#endif
22574 GC_INNER void GC_remove_protection(struct hblk *h, word nblocks,
22575 GC_bool is_ptrfree)
22576 {
22577#ifdef PCR_VDB
22578 (void)is_ptrfree;
22579 if (!GC_auto_incremental)
22580 return;
22581 PCR_VD_WriteProtectDisable(h, nblocks*HBLKSIZE);
22582 PCR_VD_WriteProtectEnable(h, nblocks*HBLKSIZE);
22583#elif defined(MPROTECT_VDB)
22584 struct hblk * h_trunc;
22585 struct hblk * h_end;
22586 struct hblk * current;
22587 if (!GC_auto_incremental || GC_GWW_AVAILABLE())
22588 return;
22589 GC_ASSERT(GC_page_size != 0);
22590 h_trunc = (struct hblk *)((word)h & ~(GC_page_size-1));
22591 h_end = (struct hblk *)(((word)(h + nblocks) + GC_page_size - 1)
22592 & ~(GC_page_size - 1));
22593 if (h_end == h_trunc + 1 &&
22594 get_pht_entry_from_index(GC_dirty_pages, PHT_HASH(h_trunc))) {
22595 return;
22596 }
22597 for (current = h_trunc; (word)current < (word)h_end; ++current) {
22598 word index = PHT_HASH(current);
22599 if (!is_ptrfree || (word)current < (word)h
22600 || (word)current >= (word)(h + nblocks)) {
22601 async_set_pht_entry_from_index(GC_dirty_pages, index);
22602 }
22603 }
22604 UNPROTECT(h_trunc, (ptr_t)h_end - (ptr_t)h_trunc);
22605#else
22606 (void)h; (void)nblocks; (void)is_ptrfree;
22607#endif
22608 }
22609#endif
22610#if defined(MPROTECT_VDB) && defined(DARWIN)
22611#include <mach/mach.h>
22612#include <mach/mach_error.h>
22613#include <mach/exception.h>
22614#include <mach/task.h>
22615#include <pthread.h>
22616EXTERN_C_BEGIN
22617extern boolean_t
22618exc_server(mach_msg_header_t *, mach_msg_header_t *);
22619extern kern_return_t
22620exception_raise(mach_port_t, mach_port_t, mach_port_t, exception_type_t,
22621 exception_data_t, mach_msg_type_number_t);
22622extern kern_return_t
22623exception_raise_state(mach_port_t, mach_port_t, mach_port_t, exception_type_t,
22624 exception_data_t, mach_msg_type_number_t,
22625 thread_state_flavor_t*, thread_state_t,
22626 mach_msg_type_number_t, thread_state_t,
22627 mach_msg_type_number_t*);
22628extern kern_return_t
22629exception_raise_state_identity(mach_port_t, mach_port_t, mach_port_t,
22630 exception_type_t, exception_data_t,
22631 mach_msg_type_number_t, thread_state_flavor_t*,
22632 thread_state_t, mach_msg_type_number_t,
22633 thread_state_t, mach_msg_type_number_t*);
22634GC_API_OSCALL kern_return_t
22635catch_exception_raise(mach_port_t exception_port, mach_port_t thread,
22636 mach_port_t task, exception_type_t exception,
22637 exception_data_t code,
22638 mach_msg_type_number_t code_count);
22639GC_API_OSCALL kern_return_t
22640catch_exception_raise_state(mach_port_name_t exception_port,
22641 int exception, exception_data_t code,
22642 mach_msg_type_number_t codeCnt, int flavor,
22643 thread_state_t old_state, int old_stateCnt,
22644 thread_state_t new_state, int new_stateCnt);
22645GC_API_OSCALL kern_return_t
22646catch_exception_raise_state_identity(mach_port_name_t exception_port,
22647 mach_port_t thread, mach_port_t task, int exception,
22648 exception_data_t code, mach_msg_type_number_t codeCnt,
22649 int flavor, thread_state_t old_state, int old_stateCnt,
22650 thread_state_t new_state, int new_stateCnt);
22651EXTERN_C_END
22652GC_API_OSCALL kern_return_t
22653catch_exception_raise_state(mach_port_name_t exception_port GC_ATTR_UNUSED,
22654 int exception GC_ATTR_UNUSED, exception_data_t code GC_ATTR_UNUSED,
22655 mach_msg_type_number_t codeCnt GC_ATTR_UNUSED, int flavor GC_ATTR_UNUSED,
22656 thread_state_t old_state GC_ATTR_UNUSED, int old_stateCnt GC_ATTR_UNUSED,
22657 thread_state_t new_state GC_ATTR_UNUSED, int new_stateCnt GC_ATTR_UNUSED)
22658{
22659 ABORT_RET("Unexpected catch_exception_raise_state invocation");
22660 return(KERN_INVALID_ARGUMENT);
22661}
22662GC_API_OSCALL kern_return_t
22663catch_exception_raise_state_identity(
22664 mach_port_name_t exception_port GC_ATTR_UNUSED,
22665 mach_port_t thread GC_ATTR_UNUSED, mach_port_t task GC_ATTR_UNUSED,
22666 int exception GC_ATTR_UNUSED, exception_data_t code GC_ATTR_UNUSED,
22667 mach_msg_type_number_t codeCnt GC_ATTR_UNUSED, int flavor GC_ATTR_UNUSED,
22668 thread_state_t old_state GC_ATTR_UNUSED, int old_stateCnt GC_ATTR_UNUSED,
22669 thread_state_t new_state GC_ATTR_UNUSED, int new_stateCnt GC_ATTR_UNUSED)
22670{
22671 ABORT_RET("Unexpected catch_exception_raise_state_identity invocation");
22672 return(KERN_INVALID_ARGUMENT);
22673}
22674#define MAX_EXCEPTION_PORTS 16
22675static struct {
22676 mach_msg_type_number_t count;
22677 exception_mask_t masks[MAX_EXCEPTION_PORTS];
22678 exception_handler_t ports[MAX_EXCEPTION_PORTS];
22679 exception_behavior_t behaviors[MAX_EXCEPTION_PORTS];
22680 thread_state_flavor_t flavors[MAX_EXCEPTION_PORTS];
22681} GC_old_exc_ports;
22682STATIC struct ports_s {
22683 void (*volatile os_callback[3])(void);
22684 mach_port_t exception;
22685#if defined(THREADS)
22686 mach_port_t reply;
22687#endif
22688} GC_ports = {
22689 {
22690 (void (*)(void))catch_exception_raise,
22691 (void (*)(void))catch_exception_raise_state,
22692 (void (*)(void))catch_exception_raise_state_identity
22693 },
22694#ifdef THREADS
22695 0,
22696#endif
22697 0
22698};
22699typedef struct {
22700 mach_msg_header_t head;
22701} GC_msg_t;
22702typedef enum {
22703 GC_MP_NORMAL,
22704 GC_MP_DISCARDING,
22705 GC_MP_STOPPED
22706} GC_mprotect_state_t;
22707#ifdef THREADS
22708#define ID_STOP 1
22709#define ID_RESUME 2
22710#define ID_ACK 3
22711 STATIC GC_mprotect_state_t GC_mprotect_state = GC_MP_NORMAL;
22712 STATIC void GC_mprotect_thread_notify(mach_msg_id_t id)
22713 {
22714 struct buf_s {
22715 GC_msg_t msg;
22716 mach_msg_trailer_t trailer;
22717 } buf;
22718 mach_msg_return_t r;
22719 buf.msg.head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
22720 buf.msg.head.msgh_size = sizeof(buf.msg);
22721 buf.msg.head.msgh_remote_port = GC_ports.exception;
22722 buf.msg.head.msgh_local_port = MACH_PORT_NULL;
22723 buf.msg.head.msgh_id = id;
22724 r = mach_msg(&buf.msg.head, MACH_SEND_MSG | MACH_RCV_MSG | MACH_RCV_LARGE,
22725 sizeof(buf.msg), sizeof(buf), GC_ports.reply,
22726 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
22727 if (r != MACH_MSG_SUCCESS)
22728 ABORT("mach_msg failed in GC_mprotect_thread_notify");
22729 if (buf.msg.head.msgh_id != ID_ACK)
22730 ABORT("Invalid ack in GC_mprotect_thread_notify");
22731 }
22732 STATIC void GC_mprotect_thread_reply(void)
22733 {
22734 GC_msg_t msg;
22735 mach_msg_return_t r;
22736 msg.head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0);
22737 msg.head.msgh_size = sizeof(msg);
22738 msg.head.msgh_remote_port = GC_ports.reply;
22739 msg.head.msgh_local_port = MACH_PORT_NULL;
22740 msg.head.msgh_id = ID_ACK;
22741 r = mach_msg(&msg.head, MACH_SEND_MSG, sizeof(msg), 0, MACH_PORT_NULL,
22742 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
22743 if (r != MACH_MSG_SUCCESS)
22744 ABORT("mach_msg failed in GC_mprotect_thread_reply");
22745 }
22746 GC_INNER void GC_mprotect_stop(void)
22747 {
22748 GC_mprotect_thread_notify(ID_STOP);
22749 }
22750 GC_INNER void GC_mprotect_resume(void)
22751 {
22752 GC_mprotect_thread_notify(ID_RESUME);
22753 }
22754#else
22755#define GC_mprotect_state GC_MP_NORMAL
22756#endif
22757struct mp_reply_s {
22758 mach_msg_header_t head;
22759 char data[256];
22760};
22761struct mp_msg_s {
22762 mach_msg_header_t head;
22763 mach_msg_body_t msgh_body;
22764 char data[1024];
22765};
22766STATIC void *GC_mprotect_thread(void *arg)
22767{
22768 mach_msg_return_t r;
22769 struct mp_reply_s reply;
22770 struct mp_msg_s msg;
22771 mach_msg_id_t id;
22772 if ((word)arg == GC_WORD_MAX) return 0;
22773#if defined(CPPCHECK)
22774 reply.data[0] = 0;
22775 msg.data[0] = 0;
22776#endif
22777#if defined(HAVE_PTHREAD_SETNAME_NP_WITHOUT_TID)
22778 (void)pthread_setname_np("GC-mprotect");
22779#endif
22780#if defined(THREADS) && !defined(GC_NO_THREADS_DISCOVERY)
22781 GC_darwin_register_mach_handler_thread(mach_thread_self());
22782#endif
22783 for(;;) {
22784 r = mach_msg(&msg.head, MACH_RCV_MSG | MACH_RCV_LARGE |
22785 (GC_mprotect_state == GC_MP_DISCARDING ? MACH_RCV_TIMEOUT : 0),
22786 0, sizeof(msg), GC_ports.exception,
22787 GC_mprotect_state == GC_MP_DISCARDING ? 0
22788 : MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
22789 id = r == MACH_MSG_SUCCESS ? msg.head.msgh_id : -1;
22790#if defined(THREADS)
22791 if(GC_mprotect_state == GC_MP_DISCARDING) {
22792 if(r == MACH_RCV_TIMED_OUT) {
22793 GC_mprotect_state = GC_MP_STOPPED;
22794 GC_mprotect_thread_reply();
22795 continue;
22796 }
22797 if(r == MACH_MSG_SUCCESS && (id == ID_STOP || id == ID_RESUME))
22798 ABORT("Out of order mprotect thread request");
22799 }
22800#endif
22801 if (r != MACH_MSG_SUCCESS) {
22802 ABORT_ARG2("mach_msg failed",
22803 ": errcode= %d (%s)", (int)r, mach_error_string(r));
22804 }
22805 switch(id) {
22806#if defined(THREADS)
22807 case ID_STOP:
22808 if(GC_mprotect_state != GC_MP_NORMAL)
22809 ABORT("Called mprotect_stop when state wasn't normal");
22810 GC_mprotect_state = GC_MP_DISCARDING;
22811 break;
22812 case ID_RESUME:
22813 if(GC_mprotect_state != GC_MP_STOPPED)
22814 ABORT("Called mprotect_resume when state wasn't stopped");
22815 GC_mprotect_state = GC_MP_NORMAL;
22816 GC_mprotect_thread_reply();
22817 break;
22818#endif
22819 default:
22820 if(!exc_server(&msg.head, &reply.head))
22821 ABORT("exc_server failed");
22822 r = mach_msg(&reply.head, MACH_SEND_MSG, reply.head.msgh_size, 0,
22823 MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
22824 MACH_PORT_NULL);
22825 if(r != MACH_MSG_SUCCESS) {
22826#ifdef BROKEN_EXCEPTION_HANDLING
22827 GC_err_printf("mach_msg failed with %d %s while sending "
22828 "exc reply\n", (int)r, mach_error_string(r));
22829#else
22830 ABORT("mach_msg failed while sending exception reply");
22831#endif
22832 }
22833 }
22834 }
22835}
22836#ifdef BROKEN_EXCEPTION_HANDLING
22837 STATIC int GC_sigbus_count = 0;
22838 STATIC void GC_darwin_sigbus(int num, siginfo_t *sip, void *context)
22839 {
22840 if (num != SIGBUS)
22841 ABORT("Got a non-sigbus signal in the sigbus handler");
22842 if (GC_sigbus_count >= 8) {
22843 ABORT("Got more than 8 SIGBUSs in a row!");
22844 } else {
22845 GC_sigbus_count++;
22846 WARN("Ignoring SIGBUS\n", 0);
22847 }
22848 }
22849#endif
22850GC_INNER GC_bool GC_dirty_init(void)
22851{
22852 kern_return_t r;
22853 mach_port_t me;
22854 pthread_t thread;
22855 pthread_attr_t attr;
22856 exception_mask_t mask;
22857#ifdef CAN_HANDLE_FORK
22858 if (GC_handle_fork) {
22859 WARN("Can't turn on GC incremental mode as fork()"
22860 " handling requested\n", 0);
22861 return FALSE;
22862 }
22863#endif
22864 GC_VERBOSE_LOG_PRINTF("Initializing mach/darwin mprotect"
22865 " virtual dirty bit implementation\n");
22866#ifdef BROKEN_EXCEPTION_HANDLING
22867 WARN("Enabling workarounds for various darwin "
22868 "exception handling bugs\n", 0);
22869#endif
22870 if (GC_page_size % HBLKSIZE != 0) {
22871 ABORT("Page size not multiple of HBLKSIZE");
22872 }
22873 GC_task_self = me = mach_task_self();
22874 r = mach_port_allocate(me, MACH_PORT_RIGHT_RECEIVE, &GC_ports.exception);
22875 if (r != KERN_SUCCESS)
22876 ABORT("mach_port_allocate failed (exception port)");
22877 r = mach_port_insert_right(me, GC_ports.exception, GC_ports.exception,
22878 MACH_MSG_TYPE_MAKE_SEND);
22879 if (r != KERN_SUCCESS)
22880 ABORT("mach_port_insert_right failed (exception port)");
22881#if defined(THREADS)
22882 r = mach_port_allocate(me, MACH_PORT_RIGHT_RECEIVE, &GC_ports.reply);
22883 if(r != KERN_SUCCESS)
22884 ABORT("mach_port_allocate failed (reply port)");
22885#endif
22886 mask = EXC_MASK_BAD_ACCESS;
22887 r = task_get_exception_ports(me, mask, GC_old_exc_ports.masks,
22888 &GC_old_exc_ports.count, GC_old_exc_ports.ports,
22889 GC_old_exc_ports.behaviors,
22890 GC_old_exc_ports.flavors);
22891 if (r != KERN_SUCCESS)
22892 ABORT("task_get_exception_ports failed");
22893 r = task_set_exception_ports(me, mask, GC_ports.exception, EXCEPTION_DEFAULT,
22894 GC_MACH_THREAD_STATE);
22895 if (r != KERN_SUCCESS)
22896 ABORT("task_set_exception_ports failed");
22897 if (pthread_attr_init(&attr) != 0)
22898 ABORT("pthread_attr_init failed");
22899 if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
22900 ABORT("pthread_attr_setdetachedstate failed");
22901#undef pthread_create
22902 if (pthread_create(&thread, &attr, GC_mprotect_thread, NULL) != 0)
22903 ABORT("pthread_create failed");
22904 (void)pthread_attr_destroy(&attr);
22905#ifdef BROKEN_EXCEPTION_HANDLING
22906 {
22907 struct sigaction sa, oldsa;
22908 sa.sa_handler = (SIG_HNDLR_PTR)GC_darwin_sigbus;
22909 sigemptyset(&sa.sa_mask);
22910 sa.sa_flags = SA_RESTART|SA_SIGINFO;
22911 if (sigaction(SIGBUS, &sa, &oldsa) < 0)
22912 ABORT("sigaction failed");
22913 if (oldsa.sa_handler != (SIG_HNDLR_PTR)(signed_word)SIG_DFL) {
22914 GC_VERBOSE_LOG_PRINTF("Replaced other SIGBUS handler\n");
22915 }
22916 }
22917#endif
22918#if defined(CPPCHECK)
22919 GC_noop1((word)GC_ports.os_callback[0]);
22920#endif
22921 return TRUE;
22922}
22923STATIC kern_return_t GC_forward_exception(mach_port_t thread, mach_port_t task,
22924 exception_type_t exception,
22925 exception_data_t data,
22926 mach_msg_type_number_t data_count)
22927{
22928 unsigned int i;
22929 kern_return_t r;
22930 mach_port_t port;
22931 exception_behavior_t behavior;
22932 thread_state_flavor_t flavor;
22933 thread_state_data_t thread_state;
22934 mach_msg_type_number_t thread_state_count = THREAD_STATE_MAX;
22935 for (i=0; i < GC_old_exc_ports.count; i++)
22936 if (GC_old_exc_ports.masks[i] & (1 << exception))
22937 break;
22938 if (i == GC_old_exc_ports.count)
22939 ABORT("No handler for exception!");
22940 port = GC_old_exc_ports.ports[i];
22941 behavior = GC_old_exc_ports.behaviors[i];
22942 flavor = GC_old_exc_ports.flavors[i];
22943 if (behavior == EXCEPTION_STATE || behavior == EXCEPTION_STATE_IDENTITY) {
22944 r = thread_get_state(thread, flavor, thread_state, &thread_state_count);
22945 if(r != KERN_SUCCESS)
22946 ABORT("thread_get_state failed in forward_exception");
22947 }
22948 switch(behavior) {
22949 case EXCEPTION_STATE:
22950 r = exception_raise_state(port, thread, task, exception, data, data_count,
22951 &flavor, thread_state, thread_state_count,
22952 thread_state, &thread_state_count);
22953 break;
22954 case EXCEPTION_STATE_IDENTITY:
22955 r = exception_raise_state_identity(port, thread, task, exception, data,
22956 data_count, &flavor, thread_state,
22957 thread_state_count, thread_state,
22958 &thread_state_count);
22959 break;
22960 default:
22961 r = exception_raise(port, thread, task, exception, data, data_count);
22962 }
22963 if (behavior == EXCEPTION_STATE || behavior == EXCEPTION_STATE_IDENTITY) {
22964 r = thread_set_state(thread, flavor, thread_state, thread_state_count);
22965 if (r != KERN_SUCCESS)
22966 ABORT("thread_set_state failed in forward_exception");
22967 }
22968 return r;
22969}
22970#define FWD() GC_forward_exception(thread, task, exception, code, code_count)
22971#ifdef ARM32
22972#define DARWIN_EXC_STATE ARM_EXCEPTION_STATE
22973#define DARWIN_EXC_STATE_COUNT ARM_EXCEPTION_STATE_COUNT
22974#define DARWIN_EXC_STATE_T arm_exception_state_t
22975#define DARWIN_EXC_STATE_DAR THREAD_FLD_NAME(far)
22976#elif defined(AARCH64)
22977#define DARWIN_EXC_STATE ARM_EXCEPTION_STATE64
22978#define DARWIN_EXC_STATE_COUNT ARM_EXCEPTION_STATE64_COUNT
22979#define DARWIN_EXC_STATE_T arm_exception_state64_t
22980#define DARWIN_EXC_STATE_DAR THREAD_FLD_NAME(far)
22981#elif defined(POWERPC)
22982#if CPP_WORDSZ == 32
22983#define DARWIN_EXC_STATE PPC_EXCEPTION_STATE
22984#define DARWIN_EXC_STATE_COUNT PPC_EXCEPTION_STATE_COUNT
22985#define DARWIN_EXC_STATE_T ppc_exception_state_t
22986#else
22987#define DARWIN_EXC_STATE PPC_EXCEPTION_STATE64
22988#define DARWIN_EXC_STATE_COUNT PPC_EXCEPTION_STATE64_COUNT
22989#define DARWIN_EXC_STATE_T ppc_exception_state64_t
22990#endif
22991#define DARWIN_EXC_STATE_DAR THREAD_FLD_NAME(dar)
22992#elif defined(I386) || defined(X86_64)
22993#if CPP_WORDSZ == 32
22994#if defined(i386_EXCEPTION_STATE_COUNT) \
22995 && !defined(x86_EXCEPTION_STATE32_COUNT)
22996#define DARWIN_EXC_STATE i386_EXCEPTION_STATE
22997#define DARWIN_EXC_STATE_COUNT i386_EXCEPTION_STATE_COUNT
22998#define DARWIN_EXC_STATE_T i386_exception_state_t
22999#else
23000#define DARWIN_EXC_STATE x86_EXCEPTION_STATE32
23001#define DARWIN_EXC_STATE_COUNT x86_EXCEPTION_STATE32_COUNT
23002#define DARWIN_EXC_STATE_T x86_exception_state32_t
23003#endif
23004#else
23005#define DARWIN_EXC_STATE x86_EXCEPTION_STATE64
23006#define DARWIN_EXC_STATE_COUNT x86_EXCEPTION_STATE64_COUNT
23007#define DARWIN_EXC_STATE_T x86_exception_state64_t
23008#endif
23009#define DARWIN_EXC_STATE_DAR THREAD_FLD_NAME(faultvaddr)
23010#elif !defined(CPPCHECK)
23011#error FIXME for non-arm/ppc/x86 darwin
23012#endif
23013GC_API_OSCALL kern_return_t
23014catch_exception_raise(mach_port_t exception_port GC_ATTR_UNUSED,
23015 mach_port_t thread, mach_port_t task GC_ATTR_UNUSED,
23016 exception_type_t exception, exception_data_t code,
23017 mach_msg_type_number_t code_count GC_ATTR_UNUSED)
23018{
23019 kern_return_t r;
23020 char *addr;
23021 thread_state_flavor_t flavor = DARWIN_EXC_STATE;
23022 mach_msg_type_number_t exc_state_count = DARWIN_EXC_STATE_COUNT;
23023 DARWIN_EXC_STATE_T exc_state;
23024 if (exception != EXC_BAD_ACCESS || code[0] != KERN_PROTECTION_FAILURE) {
23025#ifdef DEBUG_EXCEPTION_HANDLING
23026 GC_log_printf("Exception: 0x%x Code: 0x%x 0x%x in catch...\n",
23027 exception, code_count > 0 ? code[0] : -1,
23028 code_count > 1 ? code[1] : -1);
23029#endif
23030 return FWD();
23031 }
23032 r = thread_get_state(thread, flavor, (natural_t*)&exc_state,
23033 &exc_state_count);
23034 if(r != KERN_SUCCESS) {
23035#ifdef BROKEN_EXCEPTION_HANDLING
23036 GC_err_printf("thread_get_state failed in catch_exception_raise\n");
23037 return KERN_SUCCESS;
23038#else
23039 ABORT("thread_get_state failed in catch_exception_raise");
23040#endif
23041 }
23042 addr = (char*) exc_state.DARWIN_EXC_STATE_DAR;
23043 if (!is_header_found_async(addr)) {
23044#ifdef BROKEN_EXCEPTION_HANDLING
23045 static char *last_fault;
23046 static int last_fault_count;
23047 if(addr != last_fault) {
23048 last_fault = addr;
23049 last_fault_count = 0;
23050 }
23051 if(++last_fault_count < 32) {
23052 if(last_fault_count == 1)
23053 WARN("Ignoring KERN_PROTECTION_FAILURE at %p\n", addr);
23054 return KERN_SUCCESS;
23055 }
23056 GC_err_printf("Unexpected KERN_PROTECTION_FAILURE at %p; aborting...\n",
23057 (void *)addr);
23058 EXIT();
23059#else
23060 return FWD();
23061#endif
23062 }
23063#ifdef BROKEN_EXCEPTION_HANDLING
23064 GC_sigbus_count = 0;
23065#endif
23066 GC_ASSERT(GC_page_size != 0);
23067 if (GC_mprotect_state == GC_MP_NORMAL) {
23068 struct hblk * h = (struct hblk*)((word)addr & ~(GC_page_size-1));
23069 size_t i;
23070 UNPROTECT(h, GC_page_size);
23071 for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
23072 word index = PHT_HASH(h+i);
23073 async_set_pht_entry_from_index(GC_dirty_pages, index);
23074 }
23075 } else if (GC_mprotect_state == GC_MP_DISCARDING) {
23076 } else {
23077 GC_err_printf("KERN_PROTECTION_FAILURE while world is stopped\n");
23078 return FWD();
23079 }
23080 return KERN_SUCCESS;
23081}
23082#undef FWD
23083#ifndef NO_DESC_CATCH_EXCEPTION_RAISE
23084 __asm__(".desc _catch_exception_raise, 0x10");
23085 __asm__(".desc _catch_exception_raise_state, 0x10");
23086 __asm__(".desc _catch_exception_raise_state_identity, 0x10");
23087#endif
23088#endif
23089#ifndef HAVE_INCREMENTAL_PROTECTION_NEEDS
23090 GC_API int GC_CALL GC_incremental_protection_needs(void)
23091 {
23092 GC_ASSERT(GC_is_initialized);
23093 return GC_PROTECTS_NONE;
23094 }
23095#endif
23096#ifdef ECOS
23097#undef sbrk
23098#endif
23099GC_API void GC_CALL GC_set_pages_executable(int value)
23100{
23101 GC_ASSERT(!GC_is_initialized);
23102 GC_pages_executable = (GC_bool)(value != 0);
23103}
23104GC_API int GC_CALL GC_get_pages_executable(void)
23105{
23106#ifdef IGNORE_PAGES_EXECUTABLE
23107 return 1;
23108#else
23109 return (int)GC_pages_executable;
23110#endif
23111}
23112#if defined(I386) && defined(LINUX) && defined(SAVE_CALL_CHAIN)
23113#include <features.h>
23114 struct frame {
23115 struct frame *fr_savfp;
23116 long fr_savpc;
23117#if NARGS > 0
23118 long fr_arg[NARGS];
23119#endif
23120 };
23121#endif
23122#if defined(SPARC)
23123#if defined(LINUX)
23124#include <features.h>
23125#if defined(SAVE_CALL_CHAIN)
23126 struct frame {
23127 long fr_local[8];
23128 long fr_arg[6];
23129 struct frame *fr_savfp;
23130 long fr_savpc;
23131#ifndef __arch64__
23132 char *fr_stret;
23133#endif
23134 long fr_argd[6];
23135 long fr_argx[0];
23136 };
23137#endif
23138#elif defined (DRSNX)
23139#include <sys/sparc/frame.h>
23140#elif defined(OPENBSD)
23141#include <frame.h>
23142#elif defined(FREEBSD) || defined(NETBSD)
23143#include <machine/frame.h>
23144#else
23145#include <sys/frame.h>
23146#endif
23147#if NARGS > 6
23148#error We only know how to get the first 6 arguments
23149#endif
23150#endif
23151#ifdef NEED_CALLINFO
23152#ifdef LINUX
23153#include <unistd.h>
23154#endif
23155#endif
23156#if defined(GC_HAVE_BUILTIN_BACKTRACE)
23157#ifdef _MSC_VER
23158#ifndef GC_MSVC_DBG_H
23159#define GC_MSVC_DBG_H
23160#include <stdlib.h>
23161#ifdef __cplusplus
23162 extern "C" {
23163#endif
23164#if !MSVC_DBG_DLL
23165#define MSVC_DBG_EXPORT
23166#elif MSVC_DBG_BUILD
23167#define MSVC_DBG_EXPORT __declspec(dllexport)
23168#else
23169#define MSVC_DBG_EXPORT __declspec(dllimport)
23170#endif
23171#ifndef MAX_SYM_NAME
23172#define MAX_SYM_NAME 2000
23173#endif
23174typedef void* HANDLE;
23175typedef struct _CONTEXT CONTEXT;
23176MSVC_DBG_EXPORT size_t GetStackFrames(size_t skip, void* frames[], size_t maxFrames);
23177MSVC_DBG_EXPORT size_t GetStackFramesFromContext(HANDLE hProcess, HANDLE hThread, CONTEXT* context, size_t skip, void* frames[], size_t maxFrames);
23178MSVC_DBG_EXPORT size_t GetModuleNameFromAddress(void* address, char* moduleName, size_t size);
23179MSVC_DBG_EXPORT size_t GetModuleNameFromStack(size_t skip, char* moduleName, size_t size);
23180MSVC_DBG_EXPORT size_t GetSymbolNameFromAddress(void* address, char* symbolName, size_t size, size_t* offsetBytes);
23181MSVC_DBG_EXPORT size_t GetSymbolNameFromStack(size_t skip, char* symbolName, size_t size, size_t* offsetBytes);
23182MSVC_DBG_EXPORT size_t GetFileLineFromAddress(void* address, char* fileName, size_t size, size_t* lineNumber, size_t* offsetBytes);
23183MSVC_DBG_EXPORT size_t GetFileLineFromStack(size_t skip, char* fileName, size_t size, size_t* lineNumber, size_t* offsetBytes);
23184MSVC_DBG_EXPORT size_t GetDescriptionFromAddress(void* address, const char* format, char* description, size_t size);
23185MSVC_DBG_EXPORT size_t GetDescriptionFromStack(void*const frames[], size_t count, const char* format, char* description[], size_t size);
23186MSVC_DBG_EXPORT int backtrace(void* addresses[], int count);
23187MSVC_DBG_EXPORT char** backtrace_symbols(void*const addresses[], int count);
23188#ifdef __cplusplus
23189 }
23190#endif
23191#endif
23192#else
23193#include <execinfo.h>
23194#endif
23195#endif
23196#ifdef SAVE_CALL_CHAIN
23197#if NARGS == 0 && NFRAMES % 2 == 0 \
23198 && defined(GC_HAVE_BUILTIN_BACKTRACE)
23199#ifdef REDIRECT_MALLOC
23200#ifdef THREADS
23201 __thread
23202#endif
23203 GC_bool GC_in_save_callers = FALSE;
23204#endif
23205GC_INNER void GC_save_callers(struct callinfo info[NFRAMES])
23206{
23207 void * tmp_info[NFRAMES + 1];
23208 int npcs, i;
23209#define IGNORE_FRAMES 1
23210#ifdef REDIRECT_MALLOC
23211 if (GC_in_save_callers) {
23212 info[0].ci_pc = (word)(&GC_save_callers);
23213 for (i = 1; i < NFRAMES; ++i) info[i].ci_pc = 0;
23214 return;
23215 }
23216 GC_in_save_callers = TRUE;
23217#endif
23218 GC_ASSERT(I_HOLD_LOCK());
23219 GC_STATIC_ASSERT(sizeof(struct callinfo) == sizeof(void *));
23220 npcs = backtrace((void **)tmp_info, NFRAMES + IGNORE_FRAMES);
23221 if (npcs > IGNORE_FRAMES)
23222 BCOPY(&tmp_info[IGNORE_FRAMES], info,
23223 (npcs - IGNORE_FRAMES) * sizeof(void *));
23224 for (i = npcs - IGNORE_FRAMES; i < NFRAMES; ++i) info[i].ci_pc = 0;
23225#ifdef REDIRECT_MALLOC
23226 GC_in_save_callers = FALSE;
23227#endif
23228}
23229#else
23230#if (defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD)) && defined(SPARC)
23231#define FR_SAVFP fr_fp
23232#define FR_SAVPC fr_pc
23233#else
23234#define FR_SAVFP fr_savfp
23235#define FR_SAVPC fr_savpc
23236#endif
23237#if defined(SPARC) && (defined(__arch64__) || defined(__sparcv9))
23238#define BIAS 2047
23239#else
23240#define BIAS 0
23241#endif
23242GC_INNER void GC_save_callers(struct callinfo info[NFRAMES])
23243{
23244 struct frame *frame;
23245 struct frame *fp;
23246 int nframes = 0;
23247#ifdef I386
23248 asm("movl %%ebp,%0" : "=r"(frame));
23249 fp = frame;
23250#else
23251 frame = (struct frame *)GC_save_regs_in_stack();
23252 fp = (struct frame *)((long) frame -> FR_SAVFP + BIAS);
23253#endif
23254 for (; !((word)fp HOTTER_THAN (word)frame)
23255#ifndef THREADS
23256 && !((word)GC_stackbottom HOTTER_THAN (word)fp)
23257#elif defined(STACK_GROWS_UP)
23258 && fp != NULL
23259#endif
23260 && nframes < NFRAMES;
23261 fp = (struct frame *)((long) fp -> FR_SAVFP + BIAS), nframes++) {
23262#if NARGS > 0
23263 int i;
23264#endif
23265 info[nframes].ci_pc = fp->FR_SAVPC;
23266#if NARGS > 0
23267 for (i = 0; i < NARGS; i++) {
23268 info[nframes].ci_arg[i] = ~(fp->fr_arg[i]);
23269 }
23270#endif
23271 }
23272 if (nframes < NFRAMES) info[nframes].ci_pc = 0;
23273}
23274#endif
23275#endif
23276#ifdef NEED_CALLINFO
23277GC_INNER void GC_print_callers(struct callinfo info[NFRAMES])
23278{
23279 int i;
23280 static int reentry_count = 0;
23281 DCL_LOCK_STATE;
23282 LOCK();
23283 ++reentry_count;
23284 UNLOCK();
23285#if NFRAMES == 1
23286 GC_err_printf("\tCaller at allocation:\n");
23287#else
23288 GC_err_printf("\tCall chain at allocation:\n");
23289#endif
23290 for (i = 0; i < NFRAMES; i++) {
23291#if defined(LINUX) && !defined(SMALL_CONFIG)
23292 GC_bool stop = FALSE;
23293#endif
23294 if (0 == info[i].ci_pc)
23295 break;
23296#if NARGS > 0
23297 {
23298 int j;
23299 GC_err_printf("\t\targs: ");
23300 for (j = 0; j < NARGS; j++) {
23301 if (j != 0) GC_err_printf(", ");
23302 GC_err_printf("%d (0x%X)", ~(info[i].ci_arg[j]),
23303 ~(info[i].ci_arg[j]));
23304 }
23305 GC_err_printf("\n");
23306 }
23307#endif
23308 if (reentry_count > 1) {
23309 GC_err_printf("\t\t##PC##= 0x%lx\n",
23310 (unsigned long)info[i].ci_pc);
23311 continue;
23312 }
23313 {
23314 char buf[40];
23315 char *name;
23316#if defined(GC_HAVE_BUILTIN_BACKTRACE) \
23317 && !defined(GC_BACKTRACE_SYMBOLS_BROKEN)
23318 char **sym_name =
23319 backtrace_symbols((void **)(&(info[i].ci_pc)), 1);
23320 if (sym_name != NULL) {
23321 name = sym_name[0];
23322 } else
23323#endif
23324 {
23325 (void)snprintf(buf, sizeof(buf), "##PC##= 0x%lx",
23326 (unsigned long)info[i].ci_pc);
23327 buf[sizeof(buf) - 1] = '\0';
23328 name = buf;
23329 }
23330#if defined(LINUX) && !defined(SMALL_CONFIG)
23331 do {
23332 FILE *pipe;
23333#define EXE_SZ 100
23334 static char exe_name[EXE_SZ];
23335#define CMD_SZ 200
23336 char cmd_buf[CMD_SZ];
23337#define RESULT_SZ 200
23338 static char result_buf[RESULT_SZ];
23339 size_t result_len;
23340 char *old_preload;
23341#define PRELOAD_SZ 200
23342 char preload_buf[PRELOAD_SZ];
23343 static GC_bool found_exe_name = FALSE;
23344 static GC_bool will_fail = FALSE;
23345 if (will_fail)
23346 break;
23347 if (!found_exe_name) {
23348 int ret_code = readlink("/proc/self/exe", exe_name, EXE_SZ);
23349 if (ret_code < 0 || ret_code >= EXE_SZ
23350 || exe_name[0] != '/') {
23351 will_fail = TRUE;
23352 break;
23353 }
23354 exe_name[ret_code] = '\0';
23355 found_exe_name = TRUE;
23356 }
23357 (void)snprintf(cmd_buf, sizeof(cmd_buf),
23358 "/usr/bin/addr2line -f -e %s 0x%lx",
23359 exe_name, (unsigned long)info[i].ci_pc);
23360 cmd_buf[sizeof(cmd_buf) - 1] = '\0';
23361 old_preload = GETENV("LD_PRELOAD");
23362 if (0 != old_preload) {
23363 size_t old_len = strlen(old_preload);
23364 if (old_len >= PRELOAD_SZ) {
23365 will_fail = TRUE;
23366 break;
23367 }
23368 BCOPY(old_preload, preload_buf, old_len + 1);
23369 unsetenv ("LD_PRELOAD");
23370 }
23371 pipe = popen(cmd_buf, "r");
23372 if (0 != old_preload
23373 && 0 != setenv ("LD_PRELOAD", preload_buf, 0)) {
23374 WARN("Failed to reset LD_PRELOAD\n", 0);
23375 }
23376 if (NULL == pipe) {
23377 will_fail = TRUE;
23378 break;
23379 }
23380 result_len = fread(result_buf, 1, RESULT_SZ - 1, pipe);
23381 (void)pclose(pipe);
23382 if (0 == result_len) {
23383 will_fail = TRUE;
23384 break;
23385 }
23386 if (result_buf[result_len - 1] == '\n') --result_len;
23387 result_buf[result_len] = 0;
23388 if (result_buf[0] == '?'
23389 || (result_buf[result_len-2] == ':'
23390 && result_buf[result_len-1] == '0'))
23391 break;
23392 {
23393 char * nl = strchr(result_buf, '\n');
23394 if (nl != NULL
23395 && (word)nl < (word)(result_buf + result_len)) {
23396 *nl = ':';
23397 }
23398 if (strncmp(result_buf, "main",
23399 nl != NULL
23400 ? (size_t)((word)nl
23401 - COVERT_DATAFLOW(result_buf))
23402 : result_len) == 0) {
23403 stop = TRUE;
23404 }
23405 }
23406 if (result_len < RESULT_SZ - 25) {
23407 (void)snprintf(&result_buf[result_len],
23408 sizeof(result_buf) - result_len,
23409 " [0x%lx]", (unsigned long)info[i].ci_pc);
23410 result_buf[sizeof(result_buf) - 1] = '\0';
23411 }
23412#if defined(CPPCHECK)
23413 GC_noop1((unsigned char)name[0]);
23414#endif
23415 name = result_buf;
23416 } while (0);
23417#endif
23418 GC_err_printf("\t\t%s\n", name);
23419#if defined(GC_HAVE_BUILTIN_BACKTRACE) \
23420 && !defined(GC_BACKTRACE_SYMBOLS_BROKEN)
23421 if (sym_name != NULL)
23422 free(sym_name);
23423#endif
23424 }
23425#if defined(LINUX) && !defined(SMALL_CONFIG)
23426 if (stop)
23427 break;
23428#endif
23429 }
23430 LOCK();
23431 --reentry_count;
23432 UNLOCK();
23433}
23434#endif
23435#if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG)
23436 void GC_print_address_map(void)
23437 {
23438 const char *maps = GC_get_maps();
23439 GC_err_printf("---------- Begin address map ----------\n");
23440 GC_err_puts(maps);
23441 GC_err_printf("---------- End address map ----------\n");
23442 }
23443#endif
23444#if defined(THREAD_LOCAL_ALLOC)
23445#ifndef THREADS
23446#error "invalid config - THREAD_LOCAL_ALLOC requires GC_THREADS"
23447#endif
23448#ifndef GC_THREAD_LOCAL_ALLOC_H
23449#define GC_THREAD_LOCAL_ALLOC_H
23450#ifdef THREAD_LOCAL_ALLOC
23451#if defined(USE_HPUX_TLS)
23452#error USE_HPUX_TLS macro was replaced by USE_COMPILER_TLS
23453#endif
23454#include <stdlib.h>
23455EXTERN_C_BEGIN
23456#if !defined(USE_PTHREAD_SPECIFIC) && !defined(USE_WIN32_SPECIFIC) \
23457 && !defined(USE_WIN32_COMPILER_TLS) && !defined(USE_COMPILER_TLS) \
23458 && !defined(USE_CUSTOM_SPECIFIC)
23459#if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
23460#if defined(CYGWIN32) && GC_GNUC_PREREQ(4, 0)
23461#if defined(__clang__)
23462#define USE_PTHREAD_SPECIFIC
23463#else
23464#define USE_COMPILER_TLS
23465#endif
23466#elif defined(__GNUC__) || defined(MSWINCE)
23467#define USE_WIN32_SPECIFIC
23468#else
23469#define USE_WIN32_COMPILER_TLS
23470#endif
23471#elif (defined(LINUX) && !defined(ARM32) && !defined(AVR32) \
23472 && GC_GNUC_PREREQ(3, 3) \
23473 && !(defined(__clang__) && defined(HOST_ANDROID))) \
23474 || (defined(FREEBSD) \
23475 || (defined(NETBSD) && __NetBSD_Version__ >= 600000000 ) \
23476 && (GC_GNUC_PREREQ(4, 4) || GC_CLANG_PREREQ(3, 9))) \
23477 || (defined(HOST_ANDROID) && defined(ARM32) \
23478 && (GC_GNUC_PREREQ(4, 6) || GC_CLANG_PREREQ_FULL(3, 8, 256229)))
23479#define USE_COMPILER_TLS
23480#elif defined(GC_DGUX386_THREADS) || defined(GC_OSF1_THREADS) \
23481 || defined(GC_AIX_THREADS) || defined(GC_DARWIN_THREADS) \
23482 || defined(GC_FREEBSD_THREADS) || defined(GC_NETBSD_THREADS) \
23483 || defined(GC_LINUX_THREADS) || defined(GC_HAIKU_THREADS) \
23484 || defined(GC_RTEMS_PTHREADS)
23485#define USE_PTHREAD_SPECIFIC
23486#elif defined(GC_HPUX_THREADS)
23487#ifdef __GNUC__
23488#define USE_PTHREAD_SPECIFIC
23489#else
23490#define USE_COMPILER_TLS
23491#endif
23492#else
23493#define USE_CUSTOM_SPECIFIC
23494#endif
23495#endif
23496#ifndef THREAD_FREELISTS_KINDS
23497#ifdef ENABLE_DISCLAIM
23498#define THREAD_FREELISTS_KINDS (NORMAL+2)
23499#else
23500#define THREAD_FREELISTS_KINDS (NORMAL+1)
23501#endif
23502#endif
23503typedef struct thread_local_freelists {
23504 void * _freelists[THREAD_FREELISTS_KINDS][TINY_FREELISTS];
23505#define ptrfree_freelists _freelists[PTRFREE]
23506#define normal_freelists _freelists[NORMAL]
23507#ifdef GC_GCJ_SUPPORT
23508 void * gcj_freelists[TINY_FREELISTS];
23509#define ERROR_FL ((void *)GC_WORD_MAX)
23510#endif
23511#define DIRECT_GRANULES (HBLKSIZE/GRANULE_BYTES)
23512} *GC_tlfs;
23513#if defined(USE_PTHREAD_SPECIFIC)
23514#define GC_getspecific pthread_getspecific
23515#define GC_setspecific pthread_setspecific
23516#define GC_key_create pthread_key_create
23517#define GC_remove_specific(key) pthread_setspecific(key, NULL)
23518#define GC_remove_specific_after_fork(key, t) (void)0
23519 typedef pthread_key_t GC_key_t;
23520#elif defined(USE_COMPILER_TLS) || defined(USE_WIN32_COMPILER_TLS)
23521#define GC_getspecific(x) (x)
23522#define GC_setspecific(key, v) ((key) = (v), 0)
23523#define GC_key_create(key, d) 0
23524#define GC_remove_specific(key)
23525#define GC_remove_specific_after_fork(key, t) (void)0
23526 typedef void * GC_key_t;
23527#elif defined(USE_WIN32_SPECIFIC)
23528#define GC_getspecific TlsGetValue
23529#define GC_setspecific(key, v) !TlsSetValue(key, v)
23530#ifndef TLS_OUT_OF_INDEXES
23531#define TLS_OUT_OF_INDEXES (DWORD)0xFFFFFFFF
23532#endif
23533#define GC_key_create(key, d) \
23534 ((d) != 0 || (*(key) = TlsAlloc()) == TLS_OUT_OF_INDEXES ? -1 : 0)
23535#define GC_remove_specific(key)
23536#define GC_remove_specific_after_fork(key, t) (void)0
23537 typedef DWORD GC_key_t;
23538#elif defined(USE_CUSTOM_SPECIFIC)
23539 EXTERN_C_END
23540#ifndef GC_SPECIFIC_H
23541#define GC_SPECIFIC_H
23542#include <errno.h>
23543EXTERN_C_BEGIN
23544#define MALLOC_CLEAR(n) GC_INTERNAL_MALLOC(n, NORMAL)
23545#define TS_CACHE_SIZE 1024
23546#define CACHE_HASH(n) ((((n) >> 8) ^ (n)) & (TS_CACHE_SIZE - 1))
23547#define TS_HASH_SIZE 1024
23548#define HASH(p) \
23549 ((unsigned)((((word)(p)) >> 8) ^ (word)(p)) & (TS_HASH_SIZE - 1))
23550#ifdef GC_ASSERTIONS
23551 typedef GC_hidden_pointer ts_entry_value_t;
23552#define TS_HIDE_VALUE(p) GC_HIDE_POINTER(p)
23553#define TS_REVEAL_PTR(p) GC_REVEAL_POINTER(p)
23554#else
23555 typedef void * ts_entry_value_t;
23556#define TS_HIDE_VALUE(p) (p)
23557#define TS_REVEAL_PTR(p) (p)
23558#endif
23559typedef struct thread_specific_entry {
23560 volatile AO_t qtid;
23561 ts_entry_value_t value;
23562 struct thread_specific_entry *next;
23563 pthread_t thread;
23564} tse;
23565#define quick_thread_id() (((word)GC_approx_sp()) >> 12)
23566#define INVALID_QTID ((word)0)
23567#define INVALID_THREADID ((pthread_t)0)
23568union ptse_ao_u {
23569 tse *p;
23570 volatile AO_t ao;
23571};
23572typedef struct thread_specific_data {
23573 tse * volatile cache[TS_CACHE_SIZE];
23574 union ptse_ao_u hash[TS_HASH_SIZE];
23575 pthread_mutex_t lock;
23576} tsd;
23577typedef tsd * GC_key_t;
23578#define GC_key_create(key, d) GC_key_create_inner(key)
23579GC_INNER int GC_key_create_inner(tsd ** key_ptr);
23580GC_INNER int GC_setspecific(tsd * key, void * value);
23581#define GC_remove_specific(key) \
23582 GC_remove_specific_after_fork(key, pthread_self())
23583GC_INNER void GC_remove_specific_after_fork(tsd * key, pthread_t t);
23584GC_INNER void * GC_slow_getspecific(tsd * key, word qtid,
23585 tse * volatile * cache_entry);
23586GC_INLINE void * GC_getspecific(tsd * key)
23587{
23588 word qtid = quick_thread_id();
23589 tse * volatile * entry_ptr = &key->cache[CACHE_HASH(qtid)];
23590 tse * entry = *entry_ptr;
23591 GC_ASSERT(qtid != INVALID_QTID);
23592 if (EXPECT(entry -> qtid == qtid, TRUE)) {
23593 GC_ASSERT(entry -> thread == pthread_self());
23594 return TS_REVEAL_PTR(entry -> value);
23595 }
23596 return GC_slow_getspecific(key, qtid, entry_ptr);
23597}
23598EXTERN_C_END
23599#endif
23600 EXTERN_C_BEGIN
23601#else
23602#error implement me
23603#endif
23604GC_INNER void GC_init_thread_local(GC_tlfs p);
23605GC_INNER void GC_destroy_thread_local(GC_tlfs p);
23606GC_INNER void GC_mark_thread_local_fls_for(GC_tlfs p);
23607#ifdef GC_ASSERTIONS
23608 GC_bool GC_is_thread_tsd_valid(void *tsd);
23609 void GC_check_tls_for(GC_tlfs p);
23610#if defined(USE_CUSTOM_SPECIFIC)
23611 void GC_check_tsd_marks(tsd *key);
23612#endif
23613#endif
23614#ifndef GC_ATTR_TLS_FAST
23615#define GC_ATTR_TLS_FAST
23616#endif
23617extern
23618#if defined(USE_COMPILER_TLS)
23619 __thread GC_ATTR_TLS_FAST
23620#elif defined(USE_WIN32_COMPILER_TLS)
23621 __declspec(thread) GC_ATTR_TLS_FAST
23622#endif
23623 GC_key_t GC_thread_key;
23624EXTERN_C_END
23625#endif
23626#endif
23627#include <stdlib.h>
23628#if defined(USE_COMPILER_TLS)
23629 __thread GC_ATTR_TLS_FAST
23630#elif defined(USE_WIN32_COMPILER_TLS)
23631 __declspec(thread) GC_ATTR_TLS_FAST
23632#endif
23633GC_key_t GC_thread_key;
23634static GC_bool keys_initialized;
23635static void return_single_freelist(void *fl, void **gfl)
23636{
23637 if (*gfl == 0) {
23638 *gfl = fl;
23639 } else {
23640 void *q, **qptr;
23641 GC_ASSERT(GC_size(fl) == GC_size(*gfl));
23642 qptr = &(obj_link(fl));
23643 while ((word)(q = *qptr) >= HBLKSIZE)
23644 qptr = &(obj_link(q));
23645 GC_ASSERT(0 == q);
23646 *qptr = *gfl;
23647 *gfl = fl;
23648 }
23649}
23650static void return_freelists(void **fl, void **gfl)
23651{
23652 int i;
23653 for (i = 1; i < TINY_FREELISTS; ++i) {
23654 if ((word)(fl[i]) >= HBLKSIZE) {
23655 return_single_freelist(fl[i], &gfl[i]);
23656 }
23657 fl[i] = (ptr_t)HBLKSIZE;
23658 }
23659#ifdef GC_GCJ_SUPPORT
23660 if (fl[0] == ERROR_FL) return;
23661#endif
23662 if ((word)(fl[0]) >= HBLKSIZE) {
23663 return_single_freelist(fl[0], &gfl[1]);
23664 }
23665}
23666#ifdef USE_PTHREAD_SPECIFIC
23667 static void reset_thread_key(void* v) {
23668 pthread_setspecific(GC_thread_key, v);
23669 }
23670#else
23671#define reset_thread_key 0
23672#endif
23673GC_INNER void GC_init_thread_local(GC_tlfs p)
23674{
23675 int i, j, res;
23676 GC_ASSERT(I_HOLD_LOCK());
23677 if (!EXPECT(keys_initialized, TRUE)) {
23678 GC_ASSERT((word)&GC_thread_key % sizeof(word) == 0);
23679 res = GC_key_create(&GC_thread_key, reset_thread_key);
23680 if (COVERT_DATAFLOW(res) != 0) {
23681 ABORT("Failed to create key for local allocator");
23682 }
23683 keys_initialized = TRUE;
23684 }
23685 res = GC_setspecific(GC_thread_key, p);
23686 if (COVERT_DATAFLOW(res) != 0) {
23687 ABORT("Failed to set thread specific allocation pointers");
23688 }
23689 for (j = 0; j < TINY_FREELISTS; ++j) {
23690 for (i = 0; i < THREAD_FREELISTS_KINDS; ++i) {
23691 p -> _freelists[i][j] = (void *)(word)1;
23692 }
23693#ifdef GC_GCJ_SUPPORT
23694 p -> gcj_freelists[j] = (void *)(word)1;
23695#endif
23696 }
23697#ifdef GC_GCJ_SUPPORT
23698 p -> gcj_freelists[0] = ERROR_FL;
23699#endif
23700}
23701GC_INNER void GC_destroy_thread_local(GC_tlfs p)
23702{
23703 int k;
23704 GC_STATIC_ASSERT(THREAD_FREELISTS_KINDS <= MAXOBJKINDS);
23705 for (k = 0; k < THREAD_FREELISTS_KINDS; ++k) {
23706 if (k == (int)GC_n_kinds)
23707 break;
23708 return_freelists(p -> _freelists[k], GC_obj_kinds[k].ok_freelist);
23709 }
23710#ifdef GC_GCJ_SUPPORT
23711 return_freelists(p -> gcj_freelists, (void **)GC_gcjobjfreelist);
23712#endif
23713}
23714GC_API GC_ATTR_MALLOC void * GC_CALL GC_malloc_kind(size_t bytes, int kind)
23715{
23716 size_t granules;
23717 void *tsd;
23718 void *result;
23719#if MAXOBJKINDS > THREAD_FREELISTS_KINDS
23720 if (EXPECT(kind >= THREAD_FREELISTS_KINDS, FALSE)) {
23721 return GC_malloc_kind_global(bytes, kind);
23722 }
23723#endif
23724#if !defined(USE_PTHREAD_SPECIFIC) && !defined(USE_WIN32_SPECIFIC)
23725 {
23726 GC_key_t k = GC_thread_key;
23727 if (EXPECT(0 == k, FALSE)) {
23728 return GC_malloc_kind_global(bytes, kind);
23729 }
23730 tsd = GC_getspecific(k);
23731 }
23732#else
23733 if (!EXPECT(keys_initialized, TRUE))
23734 return GC_malloc_kind_global(bytes, kind);
23735 tsd = GC_getspecific(GC_thread_key);
23736#endif
23737#if !defined(USE_COMPILER_TLS) && !defined(USE_WIN32_COMPILER_TLS)
23738 if (EXPECT(0 == tsd, FALSE)) {
23739 return GC_malloc_kind_global(bytes, kind);
23740 }
23741#endif
23742 GC_ASSERT(GC_is_initialized);
23743 GC_ASSERT(GC_is_thread_tsd_valid(tsd));
23744 granules = ROUNDED_UP_GRANULES(bytes);
23745#if defined(CPPCHECK)
23746#define MALLOC_KIND_PTRFREE_INIT (void*)1
23747#else
23748#define MALLOC_KIND_PTRFREE_INIT NULL
23749#endif
23750 GC_FAST_MALLOC_GRANS(result, granules,
23751 ((GC_tlfs)tsd) -> _freelists[kind], DIRECT_GRANULES,
23752 kind, GC_malloc_kind_global(bytes, kind),
23753 (void)(kind == PTRFREE ? MALLOC_KIND_PTRFREE_INIT
23754 : (obj_link(result) = 0)));
23755#ifdef LOG_ALLOCS
23756 GC_log_printf("GC_malloc_kind(%lu, %d) returned %p, recent GC #%lu\n",
23757 (unsigned long)bytes, kind, result,
23758 (unsigned long)GC_gc_no);
23759#endif
23760 return result;
23761}
23762#ifdef GC_GCJ_SUPPORT
23763GC_API GC_ATTR_MALLOC void * GC_CALL GC_gcj_malloc(size_t bytes,
23764 void * ptr_to_struct_containing_descr)
23765{
23766 if (EXPECT(GC_incremental, FALSE)) {
23767 return GC_core_gcj_malloc(bytes, ptr_to_struct_containing_descr);
23768 } else {
23769 size_t granules = ROUNDED_UP_GRANULES(bytes);
23770 void *result;
23771 void **tiny_fl;
23772 GC_ASSERT(GC_gcjobjfreelist != NULL);
23773 tiny_fl = ((GC_tlfs)GC_getspecific(GC_thread_key))->gcj_freelists;
23774 GC_FAST_MALLOC_GRANS(result, granules, tiny_fl, DIRECT_GRANULES,
23775 GC_gcj_kind,
23776 GC_core_gcj_malloc(bytes,
23777 ptr_to_struct_containing_descr),
23778 {AO_compiler_barrier();
23779 *(void **)result = ptr_to_struct_containing_descr;});
23780 return result;
23781 }
23782}
23783#endif
23784GC_INNER void GC_mark_thread_local_fls_for(GC_tlfs p)
23785{
23786 ptr_t q;
23787 int i, j;
23788 for (j = 0; j < TINY_FREELISTS; ++j) {
23789 for (i = 0; i < THREAD_FREELISTS_KINDS; ++i) {
23790 q = (ptr_t)AO_load((volatile AO_t *)&p->_freelists[i][j]);
23791 if ((word)q > HBLKSIZE)
23792 GC_set_fl_marks(q);
23793 }
23794#ifdef GC_GCJ_SUPPORT
23795 if (EXPECT(j > 0, TRUE)) {
23796 q = (ptr_t)AO_load((volatile AO_t *)&p->gcj_freelists[j]);
23797 if ((word)q > HBLKSIZE)
23798 GC_set_fl_marks(q);
23799 }
23800#endif
23801 }
23802}
23803#if defined(GC_ASSERTIONS)
23804 void GC_check_tls_for(GC_tlfs p)
23805 {
23806 int i, j;
23807 for (j = 1; j < TINY_FREELISTS; ++j) {
23808 for (i = 0; i < THREAD_FREELISTS_KINDS; ++i) {
23809 GC_check_fl_marks(&p->_freelists[i][j]);
23810 }
23811#ifdef GC_GCJ_SUPPORT
23812 GC_check_fl_marks(&p->gcj_freelists[j]);
23813#endif
23814 }
23815 }
23816#endif
23817#endif
23818#ifndef GC_PTHREAD_SUPPORT_H
23819#define GC_PTHREAD_SUPPORT_H
23820#if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS)
23821#if defined(GC_DARWIN_THREADS)
23822#else
23823#ifndef GC_PTHREAD_STOP_WORLD_H
23824#define GC_PTHREAD_STOP_WORLD_H
23825EXTERN_C_BEGIN
23826struct thread_stop_info {
23827#if !defined(GC_OPENBSD_UTHREADS) && !defined(NACL) \
23828 && !defined(PLATFORM_STOP_WORLD) && !defined(SN_TARGET_PSP2)
23829 volatile AO_t last_stop_count;
23830#endif
23831 ptr_t stack_ptr;
23832#ifdef NACL
23833#ifdef ARM32
23834#define NACL_GC_REG_STORAGE_SIZE 9
23835#else
23836#define NACL_GC_REG_STORAGE_SIZE 20
23837#endif
23838 ptr_t reg_storage[NACL_GC_REG_STORAGE_SIZE];
23839#elif defined(PLATFORM_HAVE_GC_REG_STORAGE_SIZE)
23840 word registers[PLATFORM_GC_REG_STORAGE_SIZE];
23841#endif
23842};
23843GC_INNER void GC_stop_init(void);
23844EXTERN_C_END
23845#endif
23846#endif
23847#ifdef THREAD_LOCAL_ALLOC
23848#endif
23849#ifdef THREAD_SANITIZER
23850#endif
23851EXTERN_C_BEGIN
23852typedef struct GC_Thread_Rep {
23853#ifdef THREAD_SANITIZER
23854 char dummy[sizeof(oh)];
23855#endif
23856 struct GC_Thread_Rep * next;
23857 pthread_t id;
23858#ifdef USE_TKILL_ON_ANDROID
23859 pid_t kernel_id;
23860#endif
23861 struct thread_stop_info stop_info;
23862#if defined(GC_ENABLE_SUSPEND_THREAD) && !defined(GC_DARWIN_THREADS) \
23863 && !defined(GC_OPENBSD_UTHREADS) && !defined(NACL)
23864 volatile AO_t suspended_ext;
23865#endif
23866 unsigned char flags;
23867#define FINISHED 1
23868#define DETACHED 2
23869#define MAIN_THREAD 4
23870#define DISABLED_GC 0x10
23871 unsigned char thread_blocked;
23872 unsigned short finalizer_skipped;
23873 unsigned char finalizer_nested;
23874 ptr_t stack_end;
23875 ptr_t altstack;
23876 word altstack_size;
23877 ptr_t stack;
23878 word stack_size;
23879#if defined(GC_DARWIN_THREADS) && !defined(DARWIN_DONT_PARSE_STACK)
23880 ptr_t topOfStack;
23881#endif
23882#ifdef IA64
23883 ptr_t backing_store_end;
23884 ptr_t backing_store_ptr;
23885#endif
23886 struct GC_traced_stack_sect_s *traced_stack_sect;
23887 void * status;
23888#ifdef THREAD_LOCAL_ALLOC
23889 struct thread_local_freelists tlfs GC_ATTR_WORD_ALIGNED;
23890#endif
23891} * GC_thread;
23892#ifndef THREAD_TABLE_SZ
23893#define THREAD_TABLE_SZ 256
23894#endif
23895#if CPP_WORDSZ == 64
23896#define THREAD_TABLE_INDEX(id) \
23897 (int)(((((NUMERIC_THREAD_ID(id) >> 8) ^ NUMERIC_THREAD_ID(id)) >> 16) \
23898 ^ ((NUMERIC_THREAD_ID(id) >> 8) ^ NUMERIC_THREAD_ID(id))) \
23899 % THREAD_TABLE_SZ)
23900#else
23901#define THREAD_TABLE_INDEX(id) \
23902 (int)(((NUMERIC_THREAD_ID(id) >> 16) \
23903 ^ (NUMERIC_THREAD_ID(id) >> 8) \
23904 ^ NUMERIC_THREAD_ID(id)) % THREAD_TABLE_SZ)
23905#endif
23906GC_EXTERN volatile GC_thread GC_threads[THREAD_TABLE_SZ];
23907GC_EXTERN GC_bool GC_thr_initialized;
23908GC_INNER GC_thread GC_lookup_thread(pthread_t id);
23909#ifdef NACL
23910 GC_EXTERN __thread GC_thread GC_nacl_gc_thread_self;
23911 GC_INNER void GC_nacl_initialize_gc_thread(void);
23912 GC_INNER void GC_nacl_shutdown_gc_thread(void);
23913#endif
23914#ifdef GC_EXPLICIT_SIGNALS_UNBLOCK
23915 GC_INNER void GC_unblock_gc_signals(void);
23916#endif
23917#ifdef GC_PTHREAD_START_STANDALONE
23918#define GC_INNER_PTHRSTART
23919#else
23920#define GC_INNER_PTHRSTART GC_INNER
23921#endif
23922GC_INNER_PTHRSTART void * GC_CALLBACK GC_inner_start_routine(
23923 struct GC_stack_base *sb, void *arg);
23924GC_INNER_PTHRSTART GC_thread GC_start_rtn_prepare_thread(
23925 void *(**pstart)(void *),
23926 void **pstart_arg,
23927 struct GC_stack_base *sb, void *arg);
23928GC_INNER_PTHRSTART void GC_thread_exit_proc(void *);
23929EXTERN_C_END
23930#endif
23931#endif
23932#if defined(GC_DARWIN_THREADS)
23933#include <sys/sysctl.h>
23934#include <mach/machine.h>
23935#include <CoreFoundation/CoreFoundation.h>
23936#ifdef POWERPC
23937#if CPP_WORDSZ == 32
23938#define PPC_RED_ZONE_SIZE 224
23939#elif CPP_WORDSZ == 64
23940#define PPC_RED_ZONE_SIZE 320
23941#endif
23942#endif
23943#ifndef DARWIN_DONT_PARSE_STACK
23944typedef struct StackFrame {
23945 unsigned long savedSP;
23946 unsigned long savedCR;
23947 unsigned long savedLR;
23948 unsigned long reserved[2];
23949 unsigned long savedRTOC;
23950} StackFrame;
23951GC_INNER ptr_t GC_FindTopOfStack(unsigned long stack_start)
23952{
23953 StackFrame *frame = (StackFrame *)stack_start;
23954 if (stack_start == 0) {
23955#ifdef POWERPC
23956#if CPP_WORDSZ == 32
23957 __asm__ __volatile__ ("lwz %0,0(r1)" : "=r" (frame));
23958#else
23959 __asm__ __volatile__ ("ld %0,0(r1)" : "=r" (frame));
23960#endif
23961#elif defined(ARM32)
23962 volatile ptr_t sp_reg;
23963 __asm__ __volatile__ ("mov %0, r7\n" : "=r" (sp_reg));
23964 frame = (StackFrame *)sp_reg;
23965#elif defined(AARCH64)
23966 volatile ptr_t sp_reg;
23967 __asm__ __volatile__ ("mov %0, x29\n" : "=r" (sp_reg));
23968 frame = (StackFrame *)sp_reg;
23969#else
23970#if defined(CPPCHECK)
23971 GC_noop1((word)&frame);
23972#endif
23973 ABORT("GC_FindTopOfStack(0) is not implemented");
23974#endif
23975 }
23976#ifdef DEBUG_THREADS_EXTRA
23977 GC_log_printf("FindTopOfStack start at sp= %p\n", (void *)frame);
23978#endif
23979 while (frame->savedSP != 0) {
23980 frame = (StackFrame*)frame->savedSP;
23981 if ((frame->savedLR & ~0x3) == 0 || (frame->savedLR & ~0x3) == ~0x3UL)
23982 break;
23983 }
23984#ifdef DEBUG_THREADS_EXTRA
23985 GC_log_printf("FindTopOfStack finish at sp= %p\n", (void *)frame);
23986#endif
23987 return (ptr_t)frame;
23988}
23989#endif
23990#ifdef GC_NO_THREADS_DISCOVERY
23991#define GC_query_task_threads FALSE
23992#elif defined(GC_DISCOVER_TASK_THREADS)
23993#define GC_query_task_threads TRUE
23994#else
23995 STATIC GC_bool GC_query_task_threads = FALSE;
23996#endif
23997GC_API void GC_CALL GC_use_threads_discovery(void)
23998{
23999#if defined(GC_NO_THREADS_DISCOVERY) || defined(DARWIN_DONT_PARSE_STACK)
24000 ABORT("Darwin task-threads-based stop and push unsupported");
24001#else
24002#ifndef GC_ALWAYS_MULTITHREADED
24003 GC_ASSERT(!GC_need_to_lock);
24004#endif
24005#ifndef GC_DISCOVER_TASK_THREADS
24006 GC_query_task_threads = TRUE;
24007#endif
24008 GC_init_parallel();
24009#endif
24010}
24011#ifndef kCFCoreFoundationVersionNumber_iOS_8_0
24012#define kCFCoreFoundationVersionNumber_iOS_8_0 1140.1
24013#endif
24014STATIC ptr_t GC_stack_range_for(ptr_t *phi, thread_act_t thread, GC_thread p,
24015 GC_bool thread_blocked, mach_port_t my_thread,
24016 ptr_t *paltstack_lo,
24017 ptr_t *paltstack_hi GC_ATTR_UNUSED)
24018{
24019 ptr_t lo;
24020 if (thread == my_thread) {
24021 GC_ASSERT(!thread_blocked);
24022 lo = GC_approx_sp();
24023#ifndef DARWIN_DONT_PARSE_STACK
24024 *phi = GC_FindTopOfStack(0);
24025#endif
24026 } else if (thread_blocked) {
24027#if defined(CPPCHECK)
24028 if (NULL == p) ABORT("Invalid GC_thread passed to GC_stack_range_for");
24029#endif
24030 lo = p->stop_info.stack_ptr;
24031#ifndef DARWIN_DONT_PARSE_STACK
24032 *phi = p->topOfStack;
24033#endif
24034 } else {
24035 kern_return_t kern_result;
24036 GC_THREAD_STATE_T state;
24037#if defined(ARM32) && defined(ARM_THREAD_STATE32)
24038 size_t size;
24039 static cpu_type_t cputype = 0;
24040 if (cputype == 0) {
24041 sysctlbyname("hw.cputype", &cputype, &size, NULL, 0);
24042 }
24043 if (cputype == CPU_TYPE_ARM64
24044 || kCFCoreFoundationVersionNumber
24045 >= kCFCoreFoundationVersionNumber_iOS_8_0) {
24046 arm_unified_thread_state_t unified_state;
24047 mach_msg_type_number_t unified_thread_state_count
24048 = ARM_UNIFIED_THREAD_STATE_COUNT;
24049#if defined(CPPCHECK)
24050#define GC_ARM_UNIFIED_THREAD_STATE 1
24051#else
24052#define GC_ARM_UNIFIED_THREAD_STATE ARM_UNIFIED_THREAD_STATE
24053#endif
24054 kern_result = thread_get_state(thread, GC_ARM_UNIFIED_THREAD_STATE,
24055 (natural_t *)&unified_state,
24056 &unified_thread_state_count);
24057#if !defined(CPPCHECK)
24058 if (unified_state.ash.flavor != ARM_THREAD_STATE32) {
24059 ABORT("unified_state flavor should be ARM_THREAD_STATE32");
24060 }
24061#endif
24062 state = unified_state;
24063 } else
24064#endif
24065 {
24066 mach_msg_type_number_t thread_state_count = GC_MACH_THREAD_STATE_COUNT;
24067 do {
24068 kern_result = thread_get_state(thread, GC_MACH_THREAD_STATE,
24069 (natural_t *)&state,
24070 &thread_state_count);
24071 } while (kern_result == KERN_ABORTED);
24072 }
24073#ifdef DEBUG_THREADS
24074 GC_log_printf("thread_get_state returns %d\n", kern_result);
24075#endif
24076 if (kern_result != KERN_SUCCESS)
24077 ABORT("thread_get_state failed");
24078#if defined(I386)
24079 lo = (ptr_t)state.THREAD_FLD(esp);
24080#ifndef DARWIN_DONT_PARSE_STACK
24081 *phi = GC_FindTopOfStack(state.THREAD_FLD(esp));
24082#endif
24083 GC_push_one(state.THREAD_FLD(eax));
24084 GC_push_one(state.THREAD_FLD(ebx));
24085 GC_push_one(state.THREAD_FLD(ecx));
24086 GC_push_one(state.THREAD_FLD(edx));
24087 GC_push_one(state.THREAD_FLD(edi));
24088 GC_push_one(state.THREAD_FLD(esi));
24089 GC_push_one(state.THREAD_FLD(ebp));
24090#elif defined(X86_64)
24091 lo = (ptr_t)state.THREAD_FLD(rsp);
24092#ifndef DARWIN_DONT_PARSE_STACK
24093 *phi = GC_FindTopOfStack(state.THREAD_FLD(rsp));
24094#endif
24095 GC_push_one(state.THREAD_FLD(rax));
24096 GC_push_one(state.THREAD_FLD(rbx));
24097 GC_push_one(state.THREAD_FLD(rcx));
24098 GC_push_one(state.THREAD_FLD(rdx));
24099 GC_push_one(state.THREAD_FLD(rdi));
24100 GC_push_one(state.THREAD_FLD(rsi));
24101 GC_push_one(state.THREAD_FLD(rbp));
24102 GC_push_one(state.THREAD_FLD(r8));
24103 GC_push_one(state.THREAD_FLD(r9));
24104 GC_push_one(state.THREAD_FLD(r10));
24105 GC_push_one(state.THREAD_FLD(r11));
24106 GC_push_one(state.THREAD_FLD(r12));
24107 GC_push_one(state.THREAD_FLD(r13));
24108 GC_push_one(state.THREAD_FLD(r14));
24109 GC_push_one(state.THREAD_FLD(r15));
24110#elif defined(POWERPC)
24111 lo = (ptr_t)(state.THREAD_FLD(r1) - PPC_RED_ZONE_SIZE);
24112#ifndef DARWIN_DONT_PARSE_STACK
24113 *phi = GC_FindTopOfStack(state.THREAD_FLD(r1));
24114#endif
24115 GC_push_one(state.THREAD_FLD(r0));
24116 GC_push_one(state.THREAD_FLD(r2));
24117 GC_push_one(state.THREAD_FLD(r3));
24118 GC_push_one(state.THREAD_FLD(r4));
24119 GC_push_one(state.THREAD_FLD(r5));
24120 GC_push_one(state.THREAD_FLD(r6));
24121 GC_push_one(state.THREAD_FLD(r7));
24122 GC_push_one(state.THREAD_FLD(r8));
24123 GC_push_one(state.THREAD_FLD(r9));
24124 GC_push_one(state.THREAD_FLD(r10));
24125 GC_push_one(state.THREAD_FLD(r11));
24126 GC_push_one(state.THREAD_FLD(r12));
24127 GC_push_one(state.THREAD_FLD(r13));
24128 GC_push_one(state.THREAD_FLD(r14));
24129 GC_push_one(state.THREAD_FLD(r15));
24130 GC_push_one(state.THREAD_FLD(r16));
24131 GC_push_one(state.THREAD_FLD(r17));
24132 GC_push_one(state.THREAD_FLD(r18));
24133 GC_push_one(state.THREAD_FLD(r19));
24134 GC_push_one(state.THREAD_FLD(r20));
24135 GC_push_one(state.THREAD_FLD(r21));
24136 GC_push_one(state.THREAD_FLD(r22));
24137 GC_push_one(state.THREAD_FLD(r23));
24138 GC_push_one(state.THREAD_FLD(r24));
24139 GC_push_one(state.THREAD_FLD(r25));
24140 GC_push_one(state.THREAD_FLD(r26));
24141 GC_push_one(state.THREAD_FLD(r27));
24142 GC_push_one(state.THREAD_FLD(r28));
24143 GC_push_one(state.THREAD_FLD(r29));
24144 GC_push_one(state.THREAD_FLD(r30));
24145 GC_push_one(state.THREAD_FLD(r31));
24146#elif defined(ARM32)
24147 lo = (ptr_t)state.THREAD_FLD(sp);
24148#ifndef DARWIN_DONT_PARSE_STACK
24149 *phi = GC_FindTopOfStack(state.THREAD_FLD(r[7]));
24150#endif
24151 {
24152 int j;
24153 for (j = 0; j < 7; j++)
24154 GC_push_one(state.THREAD_FLD(r[j]));
24155 j++;
24156 for (; j <= 12; j++)
24157 GC_push_one(state.THREAD_FLD(r[j]));
24158 }
24159 GC_push_one(state.THREAD_FLD(lr));
24160#elif defined(AARCH64)
24161 lo = (ptr_t)state.THREAD_FLD(sp);
24162#ifndef DARWIN_DONT_PARSE_STACK
24163 *phi = GC_FindTopOfStack(state.THREAD_FLD(fp));
24164#endif
24165 {
24166 int j;
24167 for (j = 0; j <= 28; j++) {
24168 GC_push_one(state.THREAD_FLD(x[j]));
24169 }
24170 }
24171 GC_push_one(state.THREAD_FLD(lr));
24172#elif defined(CPPCHECK)
24173 lo = NULL;
24174#else
24175#error FIXME for non-arm/ppc/x86 architectures
24176#endif
24177 }
24178#ifdef DARWIN_DONT_PARSE_STACK
24179 *phi = (p->flags & MAIN_THREAD) != 0 ? GC_stackbottom : p->stack_end;
24180#endif
24181#ifdef DARWIN_DONT_PARSE_STACK
24182 if (p->altstack != NULL && (word)p->altstack <= (word)lo
24183 && (word)lo <= (word)p->altstack + p->altstack_size) {
24184 *paltstack_lo = lo;
24185 *paltstack_hi = p->altstack + p->altstack_size;
24186 lo = p->stack;
24187 *phi = p->stack + p->stack_size;
24188 } else
24189#endif
24190 {
24191 *paltstack_lo = NULL;
24192 }
24193#ifdef DEBUG_THREADS
24194 GC_log_printf("Darwin: Stack for thread %p is [%p,%p)\n",
24195 (void *)(word)thread, (void *)lo, (void *)(*phi));
24196#endif
24197 return lo;
24198}
24199GC_INNER void GC_push_all_stacks(void)
24200{
24201 ptr_t hi, altstack_lo, altstack_hi;
24202 task_t my_task = current_task();
24203 mach_port_t my_thread = mach_thread_self();
24204 GC_bool found_me = FALSE;
24205 int nthreads = 0;
24206 word total_size = 0;
24207 mach_msg_type_number_t listcount = (mach_msg_type_number_t)THREAD_TABLE_SZ;
24208 if (!EXPECT(GC_thr_initialized, TRUE))
24209 GC_thr_init();
24210#ifndef DARWIN_DONT_PARSE_STACK
24211 if (GC_query_task_threads) {
24212 int i;
24213 kern_return_t kern_result;
24214 thread_act_array_t act_list = 0;
24215 kern_result = task_threads(my_task, &act_list, &listcount);
24216 if (kern_result != KERN_SUCCESS)
24217 ABORT("task_threads failed");
24218 for (i = 0; i < (int)listcount; i++) {
24219 thread_act_t thread = act_list[i];
24220 ptr_t lo = GC_stack_range_for(&hi, thread, NULL, FALSE, my_thread,
24221 &altstack_lo, &altstack_hi);
24222 if (lo) {
24223 GC_ASSERT((word)lo <= (word)hi);
24224 total_size += hi - lo;
24225 GC_push_all_stack(lo, hi);
24226 }
24227 nthreads++;
24228 if (thread == my_thread)
24229 found_me = TRUE;
24230 mach_port_deallocate(my_task, thread);
24231 }
24232 vm_deallocate(my_task, (vm_address_t)act_list,
24233 sizeof(thread_t) * listcount);
24234 } else
24235#endif
24236 {
24237 int i;
24238 for (i = 0; i < (int)listcount; i++) {
24239 GC_thread p;
24240 for (p = GC_threads[i]; p != NULL; p = p->next)
24241 if ((p->flags & FINISHED) == 0) {
24242 thread_act_t thread = (thread_act_t)p->stop_info.mach_thread;
24243 ptr_t lo = GC_stack_range_for(&hi, thread, p,
24244 (GC_bool)p->thread_blocked,
24245 my_thread, &altstack_lo,
24246 &altstack_hi);
24247 if (lo) {
24248 GC_ASSERT((word)lo <= (word)hi);
24249 total_size += hi - lo;
24250 GC_push_all_stack_sections(lo, hi, p->traced_stack_sect);
24251 }
24252 if (altstack_lo) {
24253 total_size += altstack_hi - altstack_lo;
24254 GC_push_all_stack(altstack_lo, altstack_hi);
24255 }
24256 nthreads++;
24257 if (thread == my_thread)
24258 found_me = TRUE;
24259 }
24260 }
24261 }
24262 mach_port_deallocate(my_task, my_thread);
24263 GC_VERBOSE_LOG_PRINTF("Pushed %d thread stacks\n", nthreads);
24264 if (!found_me && !GC_in_thread_creation)
24265 ABORT("Collecting from unknown thread");
24266 GC_total_stacksize = total_size;
24267}
24268#ifndef GC_NO_THREADS_DISCOVERY
24269#ifdef MPROTECT_VDB
24270 STATIC mach_port_t GC_mach_handler_thread = 0;
24271 STATIC GC_bool GC_use_mach_handler_thread = FALSE;
24272 GC_INNER void GC_darwin_register_mach_handler_thread(mach_port_t thread)
24273 {
24274 GC_mach_handler_thread = thread;
24275 GC_use_mach_handler_thread = TRUE;
24276 }
24277#endif
24278#ifndef GC_MAX_MACH_THREADS
24279#define GC_MAX_MACH_THREADS THREAD_TABLE_SZ
24280#endif
24281 struct GC_mach_thread {
24282 thread_act_t thread;
24283 GC_bool suspended;
24284 };
24285 struct GC_mach_thread GC_mach_threads[GC_MAX_MACH_THREADS];
24286 STATIC int GC_mach_threads_count = 0;
24287STATIC GC_bool GC_suspend_thread_list(thread_act_array_t act_list, int count,
24288 thread_act_array_t old_list,
24289 int old_count, task_t my_task,
24290 mach_port_t my_thread)
24291{
24292 int i;
24293 int j = -1;
24294 GC_bool changed = FALSE;
24295 for (i = 0; i < count; i++) {
24296 thread_act_t thread = act_list[i];
24297 GC_bool found;
24298 kern_return_t kern_result;
24299 if (thread == my_thread
24300#ifdef MPROTECT_VDB
24301 || (GC_mach_handler_thread == thread && GC_use_mach_handler_thread)
24302#endif
24303#ifdef PARALLEL_MARK
24304 || GC_is_mach_marker(thread)
24305#endif
24306 ) {
24307 mach_port_deallocate(my_task, thread);
24308 continue;
24309 }
24310 found = FALSE;
24311 {
24312 int last_found = j;
24313 while (++j < old_count)
24314 if (old_list[j] == thread) {
24315 found = TRUE;
24316 break;
24317 }
24318 if (!found) {
24319 for (j = 0; j < last_found; j++)
24320 if (old_list[j] == thread) {
24321 found = TRUE;
24322 break;
24323 }
24324 }
24325 }
24326 if (found) {
24327 mach_port_deallocate(my_task, thread);
24328 continue;
24329 }
24330 if (GC_mach_threads_count == GC_MAX_MACH_THREADS)
24331 ABORT("Too many threads");
24332 GC_mach_threads[GC_mach_threads_count].thread = thread;
24333 GC_mach_threads[GC_mach_threads_count].suspended = FALSE;
24334 changed = TRUE;
24335#ifdef DEBUG_THREADS
24336 GC_log_printf("Suspending %p\n", (void *)(word)thread);
24337#endif
24338 GC_acquire_dirty_lock();
24339 do {
24340 kern_result = thread_suspend(thread);
24341 } while (kern_result == KERN_ABORTED);
24342 GC_release_dirty_lock();
24343 if (kern_result != KERN_SUCCESS) {
24344 GC_mach_threads[GC_mach_threads_count].suspended = FALSE;
24345 } else {
24346 GC_mach_threads[GC_mach_threads_count].suspended = TRUE;
24347 if (GC_on_thread_event)
24348 GC_on_thread_event(GC_EVENT_THREAD_SUSPENDED, (void *)(word)thread);
24349 }
24350 GC_mach_threads_count++;
24351 }
24352 return changed;
24353}
24354#endif
24355GC_INNER void GC_stop_world(void)
24356{
24357 task_t my_task = current_task();
24358 mach_port_t my_thread = mach_thread_self();
24359 kern_return_t kern_result;
24360#ifdef DEBUG_THREADS
24361 GC_log_printf("Stopping the world from thread %p\n",
24362 (void *)(word)my_thread);
24363#endif
24364#ifdef PARALLEL_MARK
24365 if (GC_parallel) {
24366 GC_acquire_mark_lock();
24367 GC_ASSERT(GC_fl_builder_count == 0);
24368 }
24369#endif
24370 if (GC_query_task_threads) {
24371#ifndef GC_NO_THREADS_DISCOVERY
24372 GC_bool changed;
24373 thread_act_array_t act_list, prev_list;
24374 mach_msg_type_number_t listcount, prevcount;
24375 GC_mach_threads_count = 0;
24376 changed = TRUE;
24377 prev_list = NULL;
24378 prevcount = 0;
24379 do {
24380 kern_result = task_threads(my_task, &act_list, &listcount);
24381 if (kern_result == KERN_SUCCESS) {
24382 changed = GC_suspend_thread_list(act_list, listcount, prev_list,
24383 prevcount, my_task, my_thread);
24384 if (prev_list != NULL) {
24385 vm_deallocate(my_task, (vm_address_t)prev_list,
24386 sizeof(thread_t) * prevcount);
24387 }
24388 prev_list = act_list;
24389 prevcount = listcount;
24390 }
24391 } while (changed);
24392 GC_ASSERT(prev_list != 0);
24393 vm_deallocate(my_task, (vm_address_t)act_list,
24394 sizeof(thread_t) * listcount);
24395#endif
24396 } else {
24397 unsigned i;
24398 for (i = 0; i < THREAD_TABLE_SZ; i++) {
24399 GC_thread p;
24400 for (p = GC_threads[i]; p != NULL; p = p->next) {
24401 if ((p->flags & FINISHED) == 0 && !p->thread_blocked &&
24402 p->stop_info.mach_thread != my_thread) {
24403 GC_acquire_dirty_lock();
24404 do {
24405 kern_result = thread_suspend(p->stop_info.mach_thread);
24406 } while (kern_result == KERN_ABORTED);
24407 GC_release_dirty_lock();
24408 if (kern_result != KERN_SUCCESS)
24409 ABORT("thread_suspend failed");
24410 if (GC_on_thread_event)
24411 GC_on_thread_event(GC_EVENT_THREAD_SUSPENDED,
24412 (void *)(word)p->stop_info.mach_thread);
24413 }
24414 }
24415 }
24416 }
24417#ifdef MPROTECT_VDB
24418 if (GC_auto_incremental) {
24419 GC_mprotect_stop();
24420 }
24421#endif
24422#ifdef PARALLEL_MARK
24423 if (GC_parallel)
24424 GC_release_mark_lock();
24425#endif
24426#ifdef DEBUG_THREADS
24427 GC_log_printf("World stopped from %p\n", (void *)(word)my_thread);
24428#endif
24429 mach_port_deallocate(my_task, my_thread);
24430}
24431GC_INLINE void GC_thread_resume(thread_act_t thread)
24432{
24433 kern_return_t kern_result;
24434#if defined(DEBUG_THREADS) || defined(GC_ASSERTIONS)
24435 struct thread_basic_info info;
24436 mach_msg_type_number_t outCount = THREAD_BASIC_INFO_COUNT;
24437#if defined(CPPCHECK) && defined(DEBUG_THREADS)
24438 info.run_state = 0;
24439#endif
24440 kern_result = thread_info(thread, THREAD_BASIC_INFO,
24441 (thread_info_t)&info, &outCount);
24442 if (kern_result != KERN_SUCCESS)
24443 ABORT("thread_info failed");
24444#endif
24445#ifdef DEBUG_THREADS
24446 GC_log_printf("Resuming thread %p with state %d\n", (void *)(word)thread,
24447 info.run_state);
24448#endif
24449 kern_result = thread_resume(thread);
24450 if (kern_result != KERN_SUCCESS) {
24451 WARN("thread_resume(%p) failed: mach port invalid\n", thread);
24452 } else if (GC_on_thread_event) {
24453 GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED, (void *)(word)thread);
24454 }
24455}
24456GC_INNER void GC_start_world(void)
24457{
24458 task_t my_task = current_task();
24459#ifdef DEBUG_THREADS
24460 GC_log_printf("World starting\n");
24461#endif
24462#ifdef MPROTECT_VDB
24463 if (GC_auto_incremental) {
24464 GC_mprotect_resume();
24465 }
24466#endif
24467 if (GC_query_task_threads) {
24468#ifndef GC_NO_THREADS_DISCOVERY
24469 int i, j;
24470 kern_return_t kern_result;
24471 thread_act_array_t act_list;
24472 mach_msg_type_number_t listcount;
24473 kern_result = task_threads(my_task, &act_list, &listcount);
24474 if (kern_result != KERN_SUCCESS)
24475 ABORT("task_threads failed");
24476 j = (int)listcount;
24477 for (i = 0; i < GC_mach_threads_count; i++) {
24478 thread_act_t thread = GC_mach_threads[i].thread;
24479 if (GC_mach_threads[i].suspended) {
24480 int last_found = j;
24481 while (++j < (int)listcount) {
24482 if (act_list[j] == thread)
24483 break;
24484 }
24485 if (j >= (int)listcount) {
24486 for (j = 0; j < last_found; j++) {
24487 if (act_list[j] == thread)
24488 break;
24489 }
24490 }
24491 if (j != last_found) {
24492 GC_thread_resume(thread);
24493 }
24494 } else {
24495#ifdef DEBUG_THREADS
24496 GC_log_printf("Not resuming thread %p as it is not suspended\n",
24497 (void *)(word)thread);
24498#endif
24499 }
24500 mach_port_deallocate(my_task, thread);
24501 }
24502 for (i = 0; i < (int)listcount; i++)
24503 mach_port_deallocate(my_task, act_list[i]);
24504 vm_deallocate(my_task, (vm_address_t)act_list,
24505 sizeof(thread_t) * listcount);
24506#endif
24507 } else {
24508 int i;
24509 mach_port_t my_thread = mach_thread_self();
24510 for (i = 0; i < THREAD_TABLE_SZ; i++) {
24511 GC_thread p;
24512 for (p = GC_threads[i]; p != NULL; p = p->next) {
24513 if ((p->flags & FINISHED) == 0 && !p->thread_blocked &&
24514 p->stop_info.mach_thread != my_thread)
24515 GC_thread_resume(p->stop_info.mach_thread);
24516 }
24517 }
24518 mach_port_deallocate(my_task, my_thread);
24519 }
24520#ifdef DEBUG_THREADS
24521 GC_log_printf("World started\n");
24522#endif
24523}
24524#endif
24525#if !defined(MACOS) && !defined(GC_NO_TYPES) && !defined(SN_TARGET_PSP2) \
24526 && !defined(_WIN32_WCE) && !defined(__CC_ARM)
24527#include <sys/types.h>
24528#endif
24529#undef GC_MUST_RESTORE_REDEFINED_DLOPEN
24530#if defined(GC_PTHREADS) && !defined(GC_NO_DLOPEN) \
24531 && !defined(GC_NO_THREAD_REDIRECTS) && !defined(GC_USE_LD_WRAP)
24532#undef dlopen
24533#define GC_MUST_RESTORE_REDEFINED_DLOPEN
24534#endif
24535STATIC GC_has_static_roots_func GC_has_static_roots = 0;
24536#if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE) \
24537 || defined(CYGWIN32)) && !defined(PCR)
24538#if !defined(DARWIN) && !defined(SCO_ELF) && !defined(SOLARISDL) \
24539 && !defined(AIX) && !defined(DGUX) && !defined(IRIX5) && !defined(HPUX) \
24540 && !defined(CYGWIN32) && !defined(MSWIN32) && !defined(MSWINCE) \
24541 && !(defined(ALPHA) && defined(OSF1)) \
24542 && !(defined(FREEBSD) && defined(__ELF__)) \
24543 && !(defined(LINUX) && defined(__ELF__)) \
24544 && !(defined(NETBSD) && defined(__ELF__)) \
24545 && !(defined(OPENBSD) && (defined(__ELF__) || defined(M68K))) \
24546 && !defined(HAIKU) && !defined(HURD) && !defined(NACL) \
24547 && !defined(CPPCHECK)
24548#error We only know how to find data segments of dynamic libraries for above.
24549#error Additional SVR4 variants might not be too hard to add.
24550#endif
24551#include <stdio.h>
24552#ifdef SOLARISDL
24553#include <sys/elf.h>
24554#include <dlfcn.h>
24555#include <link.h>
24556#endif
24557#if defined(NETBSD)
24558#include <sys/param.h>
24559#include <dlfcn.h>
24560#include <machine/elf_machdep.h>
24561#define ELFSIZE ARCH_ELFSIZE
24562#endif
24563#if defined(OPENBSD)
24564#include <sys/param.h>
24565#if (OpenBSD >= 200519) && !defined(HAVE_DL_ITERATE_PHDR)
24566#define HAVE_DL_ITERATE_PHDR
24567#endif
24568#endif
24569#if defined(SCO_ELF) || defined(DGUX) || defined(HURD) || defined(NACL) \
24570 || (defined(__ELF__) && (defined(LINUX) || defined(FREEBSD) \
24571 || defined(NETBSD) || defined(OPENBSD)))
24572#include <stddef.h>
24573#if !defined(OPENBSD) && !defined(HOST_ANDROID)
24574#include <elf.h>
24575#endif
24576#ifdef HOST_ANDROID
24577#ifdef BIONIC_ELFDATA_REDEF_BUG
24578#include <asm/elf.h>
24579#include <linux/elf-em.h>
24580#undef ELF_DATA
24581#undef EM_ALPHA
24582#endif
24583#include <link.h>
24584#if !defined(GC_DONT_DEFINE_LINK_MAP) && !(__ANDROID_API__ >= 21)
24585 struct link_map {
24586 uintptr_t l_addr;
24587 char* l_name;
24588 uintptr_t l_ld;
24589 struct link_map* l_next;
24590 struct link_map* l_prev;
24591 };
24592 struct r_debug {
24593 int32_t r_version;
24594 struct link_map* r_map;
24595 void (*r_brk)(void);
24596 int32_t r_state;
24597 uintptr_t r_ldbase;
24598 };
24599#endif
24600#else
24601 EXTERN_C_BEGIN
24602#include <link.h>
24603 EXTERN_C_END
24604#endif
24605#endif
24606#ifndef ElfW
24607#if defined(FREEBSD)
24608#if __ELF_WORD_SIZE == 32
24609#define ElfW(type) Elf32_##type
24610#else
24611#define ElfW(type) Elf64_##type
24612#endif
24613#elif defined(NETBSD) || defined(OPENBSD)
24614#if ELFSIZE == 32
24615#define ElfW(type) Elf32_##type
24616#elif ELFSIZE == 64
24617#define ElfW(type) Elf64_##type
24618#else
24619#error Missing ELFSIZE define
24620#endif
24621#else
24622#if !defined(ELF_CLASS) || ELF_CLASS == ELFCLASS32
24623#define ElfW(type) Elf32_##type
24624#else
24625#define ElfW(type) Elf64_##type
24626#endif
24627#endif
24628#endif
24629#if defined(SOLARISDL) && !defined(USE_PROC_FOR_LIBRARIES)
24630 EXTERN_C_BEGIN
24631 extern ElfW(Dyn) _DYNAMIC;
24632 EXTERN_C_END
24633 STATIC struct link_map *
24634 GC_FirstDLOpenedLinkMap(void)
24635 {
24636 ElfW(Dyn) *dp;
24637 static struct link_map * cachedResult = 0;
24638 static ElfW(Dyn) *dynStructureAddr = 0;
24639#ifdef SUNOS53_SHARED_LIB
24640 if( dynStructureAddr == 0 ) {
24641 void* startupSyms = dlopen(0, RTLD_LAZY);
24642 dynStructureAddr = (ElfW(Dyn)*)(word)dlsym(startupSyms, "_DYNAMIC");
24643 }
24644#else
24645 dynStructureAddr = &_DYNAMIC;
24646#endif
24647 if (0 == COVERT_DATAFLOW(dynStructureAddr)) {
24648 return(0);
24649 }
24650 if (cachedResult == 0) {
24651 int tag;
24652 for( dp = ((ElfW(Dyn) *)(&_DYNAMIC)); (tag = dp->d_tag) != 0; dp++ ) {
24653 if (tag == DT_DEBUG) {
24654 struct r_debug *rd = (struct r_debug *)dp->d_un.d_ptr;
24655 if (rd != NULL) {
24656 struct link_map *lm = rd->r_map;
24657 if (lm != NULL)
24658 cachedResult = lm->l_next;
24659 }
24660 break;
24661 }
24662 }
24663 }
24664 return cachedResult;
24665 }
24666#endif
24667#ifdef GC_MUST_RESTORE_REDEFINED_DLOPEN
24668#define dlopen GC_dlopen
24669#endif
24670#if defined(SOLARISDL)
24671#if !defined(PCR) && !defined(GC_SOLARIS_THREADS) && defined(THREADS) \
24672 && !defined(CPPCHECK)
24673#error Fix mutual exclusion with dlopen
24674#endif
24675#ifndef USE_PROC_FOR_LIBRARIES
24676GC_INNER void GC_register_dynamic_libraries(void)
24677{
24678 struct link_map *lm;
24679 for (lm = GC_FirstDLOpenedLinkMap(); lm != 0; lm = lm->l_next) {
24680 ElfW(Ehdr) * e;
24681 ElfW(Phdr) * p;
24682 unsigned long offset;
24683 char * start;
24684 int i;
24685 e = (ElfW(Ehdr) *) lm->l_addr;
24686 p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff));
24687 offset = ((unsigned long)(lm->l_addr));
24688 for( i = 0; i < (int)e->e_phnum; i++, p++ ) {
24689 switch( p->p_type ) {
24690 case PT_LOAD:
24691 {
24692 if( !(p->p_flags & PF_W) ) break;
24693 start = ((char *)(p->p_vaddr)) + offset;
24694 GC_add_roots_inner(start, start + p->p_memsz, TRUE);
24695 }
24696 break;
24697 default:
24698 break;
24699 }
24700 }
24701 }
24702}
24703#endif
24704#endif
24705#if defined(SCO_ELF) || defined(DGUX) || defined(HURD) || defined(NACL) \
24706 || (defined(__ELF__) && (defined(LINUX) || defined(FREEBSD) \
24707 || defined(NETBSD) || defined(OPENBSD)))
24708#ifdef USE_PROC_FOR_LIBRARIES
24709#include <string.h>
24710#include <sys/stat.h>
24711#include <fcntl.h>
24712#include <unistd.h>
24713#define MAPS_BUF_SIZE (32*1024)
24714static void sort_heap_sects(struct HeapSect *base, size_t number_of_elements)
24715{
24716 signed_word n = (signed_word)number_of_elements;
24717 signed_word nsorted = 1;
24718 while (nsorted < n) {
24719 signed_word i;
24720 while (nsorted < n &&
24721 (word)base[nsorted-1].hs_start < (word)base[nsorted].hs_start)
24722 ++nsorted;
24723 if (nsorted == n) break;
24724 GC_ASSERT((word)base[nsorted-1].hs_start > (word)base[nsorted].hs_start);
24725 i = nsorted - 1;
24726 while (i >= 0 && (word)base[i].hs_start > (word)base[i+1].hs_start) {
24727 struct HeapSect tmp = base[i];
24728 base[i] = base[i+1];
24729 base[i+1] = tmp;
24730 --i;
24731 }
24732 GC_ASSERT((word)base[nsorted-1].hs_start < (word)base[nsorted].hs_start);
24733 ++nsorted;
24734 }
24735}
24736STATIC void GC_register_map_entries(const char *maps)
24737{
24738 const char *prot;
24739 ptr_t start, end;
24740 unsigned int maj_dev;
24741 ptr_t least_ha, greatest_ha;
24742 unsigned i;
24743 GC_ASSERT(I_HOLD_LOCK());
24744 sort_heap_sects(GC_our_memory, GC_n_memory);
24745 least_ha = GC_our_memory[0].hs_start;
24746 greatest_ha = GC_our_memory[GC_n_memory-1].hs_start
24747 + GC_our_memory[GC_n_memory-1].hs_bytes;
24748 for (;;) {
24749 maps = GC_parse_map_entry(maps, &start, &end, &prot, &maj_dev, 0);
24750 if (NULL == maps) break;
24751 if (prot[1] == 'w') {
24752 if ((word)start <= (word)GC_stackbottom
24753 && (word)end >= (word)GC_stackbottom) {
24754 continue;
24755 }
24756#ifdef THREADS
24757 if (GC_segment_is_thread_stack(start, end)) continue;
24758#endif
24759 if ((word)end <= (word)least_ha
24760 || (word)start >= (word)greatest_ha) {
24761 GC_add_roots_inner(start, end, TRUE);
24762 continue;
24763 }
24764 i = 0;
24765 while ((word)(GC_our_memory[i].hs_start
24766 + GC_our_memory[i].hs_bytes) < (word)start)
24767 ++i;
24768 GC_ASSERT(i < GC_n_memory);
24769 if ((word)GC_our_memory[i].hs_start <= (word)start) {
24770 start = GC_our_memory[i].hs_start
24771 + GC_our_memory[i].hs_bytes;
24772 ++i;
24773 }
24774 while (i < GC_n_memory
24775 && (word)GC_our_memory[i].hs_start < (word)end
24776 && (word)start < (word)end) {
24777 if ((word)start < (word)GC_our_memory[i].hs_start)
24778 GC_add_roots_inner(start,
24779 GC_our_memory[i].hs_start, TRUE);
24780 start = GC_our_memory[i].hs_start
24781 + GC_our_memory[i].hs_bytes;
24782 ++i;
24783 }
24784 if ((word)start < (word)end)
24785 GC_add_roots_inner(start, end, TRUE);
24786 } else if (prot[0] == '-' && prot[1] == '-' && prot[2] == '-') {
24787 GC_remove_roots_subregion(start, end);
24788 }
24789 }
24790}
24791GC_INNER void GC_register_dynamic_libraries(void)
24792{
24793 GC_register_map_entries(GC_get_maps());
24794}
24795GC_INNER GC_bool GC_register_main_static_data(void)
24796{
24797 return FALSE;
24798}
24799#define HAVE_REGISTER_MAIN_STATIC_DATA
24800#else
24801#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) \
24802 || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG)) \
24803 || defined(HOST_ANDROID)
24804#ifndef HAVE_DL_ITERATE_PHDR
24805#define HAVE_DL_ITERATE_PHDR
24806#endif
24807#ifdef HOST_ANDROID
24808 EXTERN_C_BEGIN
24809 extern int dl_iterate_phdr(int (*cb)(struct dl_phdr_info *,
24810 size_t, void *),
24811 void *data);
24812 EXTERN_C_END
24813#endif
24814#endif
24815#if defined(__DragonFly__) || defined(__FreeBSD_kernel__) \
24816 || (defined(FREEBSD) && __FreeBSD__ >= 7)
24817#ifndef HAVE_DL_ITERATE_PHDR
24818#define HAVE_DL_ITERATE_PHDR
24819#endif
24820#define DL_ITERATE_PHDR_STRONG
24821#elif defined(HAVE_DL_ITERATE_PHDR)
24822 EXTERN_C_BEGIN
24823#pragma weak dl_iterate_phdr
24824 EXTERN_C_END
24825#endif
24826#if defined(HAVE_DL_ITERATE_PHDR)
24827#ifdef PT_GNU_RELRO
24828#define MAX_LOAD_SEGS MAX_ROOT_SETS
24829 static struct load_segment {
24830 ptr_t start;
24831 ptr_t end;
24832 ptr_t start2;
24833 ptr_t end2;
24834 } load_segs[MAX_LOAD_SEGS];
24835 static int n_load_segs;
24836 static GC_bool load_segs_overflow;
24837#endif
24838STATIC int GC_register_dynlib_callback(struct dl_phdr_info * info,
24839 size_t size, void * ptr)
24840{
24841 const ElfW(Phdr) * p;
24842 ptr_t start, end;
24843 int i;
24844 if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
24845 + sizeof (info->dlpi_phnum))
24846 return -1;
24847 p = info->dlpi_phdr;
24848 for (i = 0; i < (int)info->dlpi_phnum; i++, p++) {
24849 if (p->p_type == PT_LOAD) {
24850 GC_has_static_roots_func callback = GC_has_static_roots;
24851 if ((p->p_flags & PF_W) == 0) continue;
24852 start = (ptr_t)p->p_vaddr + info->dlpi_addr;
24853 end = start + p->p_memsz;
24854 if (callback != 0 && !callback(info->dlpi_name, start, p->p_memsz))
24855 continue;
24856#ifdef PT_GNU_RELRO
24857#if CPP_WORDSZ == 64
24858 start = (ptr_t)((word)start & ~(word)(sizeof(word) - 1));
24859#endif
24860 if (n_load_segs >= MAX_LOAD_SEGS) {
24861 if (!load_segs_overflow) {
24862 WARN("Too many PT_LOAD segments;"
24863 " registering as roots directly...\n", 0);
24864 load_segs_overflow = TRUE;
24865 }
24866 GC_add_roots_inner(start, end, TRUE);
24867 } else {
24868 load_segs[n_load_segs].start = start;
24869 load_segs[n_load_segs].end = end;
24870 load_segs[n_load_segs].start2 = 0;
24871 load_segs[n_load_segs].end2 = 0;
24872 ++n_load_segs;
24873 }
24874#else
24875 GC_add_roots_inner(start, end, TRUE);
24876#endif
24877 }
24878 }
24879#ifdef PT_GNU_RELRO
24880 p = info->dlpi_phdr;
24881 for (i = 0; i < (int)info->dlpi_phnum; i++, p++) {
24882 if (p->p_type == PT_GNU_RELRO) {
24883 int j;
24884 start = (ptr_t)p->p_vaddr + info->dlpi_addr;
24885 end = start + p->p_memsz;
24886 for (j = n_load_segs; --j >= 0; ) {
24887 if ((word)start >= (word)load_segs[j].start
24888 && (word)start < (word)load_segs[j].end) {
24889 if (load_segs[j].start2 != 0) {
24890 WARN("More than one GNU_RELRO segment per load one\n",0);
24891 } else {
24892 GC_ASSERT((word)end <=
24893 (((word)load_segs[j].end + GC_page_size - 1) &
24894 ~(GC_page_size - 1)));
24895 load_segs[j].end2 = load_segs[j].end;
24896 load_segs[j].end = start;
24897 load_segs[j].start2 = end;
24898 }
24899 break;
24900 }
24901 if (0 == j && 0 == GC_has_static_roots)
24902 WARN("Failed to find PT_GNU_RELRO segment"
24903 " inside PT_LOAD region\n", 0);
24904 }
24905 }
24906 }
24907#endif
24908 *(int *)ptr = 1;
24909 return 0;
24910}
24911GC_INNER GC_bool GC_register_main_static_data(void)
24912{
24913#ifdef DL_ITERATE_PHDR_STRONG
24914 return FALSE;
24915#else
24916 return 0 == COVERT_DATAFLOW(dl_iterate_phdr);
24917#endif
24918}
24919STATIC GC_bool GC_register_dynamic_libraries_dl_iterate_phdr(void)
24920{
24921 int did_something;
24922 if (GC_register_main_static_data())
24923 return FALSE;
24924#ifdef PT_GNU_RELRO
24925 {
24926 static GC_bool excluded_segs = FALSE;
24927 n_load_segs = 0;
24928 load_segs_overflow = FALSE;
24929 if (!EXPECT(excluded_segs, TRUE)) {
24930 GC_exclude_static_roots_inner((ptr_t)load_segs,
24931 (ptr_t)load_segs + sizeof(load_segs));
24932 excluded_segs = TRUE;
24933 }
24934 }
24935#endif
24936 did_something = 0;
24937 dl_iterate_phdr(GC_register_dynlib_callback, &did_something);
24938 if (did_something) {
24939#ifdef PT_GNU_RELRO
24940 int i;
24941 for (i = 0; i < n_load_segs; ++i) {
24942 if ((word)load_segs[i].end > (word)load_segs[i].start) {
24943 GC_add_roots_inner(load_segs[i].start, load_segs[i].end, TRUE);
24944 }
24945 if ((word)load_segs[i].end2 > (word)load_segs[i].start2) {
24946 GC_add_roots_inner(load_segs[i].start2, load_segs[i].end2, TRUE);
24947 }
24948 }
24949#endif
24950 } else {
24951 ptr_t datastart, dataend;
24952#ifdef DATASTART_IS_FUNC
24953 static ptr_t datastart_cached = (ptr_t)GC_WORD_MAX;
24954 if (datastart_cached == (ptr_t)GC_WORD_MAX) {
24955 datastart_cached = DATASTART;
24956 }
24957 datastart = datastart_cached;
24958#else
24959 datastart = DATASTART;
24960#endif
24961#ifdef DATAEND_IS_FUNC
24962 {
24963 static ptr_t dataend_cached = 0;
24964 if (dataend_cached == 0) {
24965 dataend_cached = DATAEND;
24966 }
24967 dataend = dataend_cached;
24968 }
24969#else
24970 dataend = DATAEND;
24971#endif
24972 if (NULL == *(char * volatile *)&datastart
24973 || (word)datastart > (word)dataend)
24974 ABORT_ARG2("Wrong DATASTART/END pair",
24975 ": %p .. %p", (void *)datastart, (void *)dataend);
24976 GC_add_roots_inner(datastart, dataend, TRUE);
24977#ifdef GC_HAVE_DATAREGION2
24978 if ((word)DATASTART2 - 1U >= (word)DATAEND2) {
24979 ABORT_ARG2("Wrong DATASTART/END2 pair",
24980 ": %p .. %p", (void *)DATASTART2, (void *)DATAEND2);
24981 }
24982 GC_add_roots_inner(DATASTART2, DATAEND2, TRUE);
24983#endif
24984 }
24985 return TRUE;
24986}
24987#define HAVE_REGISTER_MAIN_STATIC_DATA
24988#else
24989#if defined(NETBSD) || defined(OPENBSD)
24990#include <sys/exec_elf.h>
24991#ifndef DT_DEBUG
24992#define DT_DEBUG 21
24993#endif
24994#ifndef PT_LOAD
24995#define PT_LOAD 1
24996#endif
24997#ifndef PF_W
24998#define PF_W 2
24999#endif
25000#elif !defined(HOST_ANDROID)
25001#include <elf.h>
25002#endif
25003#ifndef HOST_ANDROID
25004#include <link.h>
25005#endif
25006#endif
25007EXTERN_C_BEGIN
25008#ifdef __GNUC__
25009#pragma weak _DYNAMIC
25010#endif
25011extern ElfW(Dyn) _DYNAMIC[];
25012EXTERN_C_END
25013STATIC struct link_map *
25014GC_FirstDLOpenedLinkMap(void)
25015{
25016 static struct link_map *cachedResult = 0;
25017 if (0 == COVERT_DATAFLOW(_DYNAMIC)) {
25018 return(0);
25019 }
25020 if( cachedResult == 0 ) {
25021#if defined(NETBSD) && defined(RTLD_DI_LINKMAP)
25022#if defined(CPPCHECK)
25023#define GC_RTLD_DI_LINKMAP 2
25024#else
25025#define GC_RTLD_DI_LINKMAP RTLD_DI_LINKMAP
25026#endif
25027 struct link_map *lm = NULL;
25028 if (!dlinfo(RTLD_SELF, GC_RTLD_DI_LINKMAP, &lm) && lm != NULL) {
25029 while (lm->l_prev != NULL) {
25030 lm = lm->l_prev;
25031 }
25032 cachedResult = lm->l_next;
25033 }
25034#else
25035 ElfW(Dyn) *dp;
25036 int tag;
25037 for( dp = _DYNAMIC; (tag = dp->d_tag) != 0; dp++ ) {
25038 if (tag == DT_DEBUG) {
25039 struct r_debug *rd = (struct r_debug *)dp->d_un.d_ptr;
25040 if (rd != NULL) {
25041 struct link_map *lm = rd->r_map;
25042 if (lm != NULL)
25043 cachedResult = lm->l_next;
25044 }
25045 break;
25046 }
25047 }
25048#endif
25049 }
25050 return cachedResult;
25051}
25052GC_INNER void GC_register_dynamic_libraries(void)
25053{
25054 struct link_map *lm;
25055#ifdef HAVE_DL_ITERATE_PHDR
25056 if (GC_register_dynamic_libraries_dl_iterate_phdr()) {
25057 return;
25058 }
25059#endif
25060 for (lm = GC_FirstDLOpenedLinkMap(); lm != 0; lm = lm->l_next)
25061 {
25062 ElfW(Ehdr) * e;
25063 ElfW(Phdr) * p;
25064 unsigned long offset;
25065 char * start;
25066 int i;
25067 e = (ElfW(Ehdr) *) lm->l_addr;
25068#ifdef HOST_ANDROID
25069 if (e == NULL)
25070 continue;
25071#endif
25072 p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff));
25073 offset = ((unsigned long)(lm->l_addr));
25074 for( i = 0; i < (int)e->e_phnum; i++, p++ ) {
25075 switch( p->p_type ) {
25076 case PT_LOAD:
25077 {
25078 if( !(p->p_flags & PF_W) ) break;
25079 start = ((char *)(p->p_vaddr)) + offset;
25080 GC_add_roots_inner(start, start + p->p_memsz, TRUE);
25081 }
25082 break;
25083 default:
25084 break;
25085 }
25086 }
25087 }
25088}
25089#endif
25090#endif
25091#if defined(IRIX5) || (defined(USE_PROC_FOR_LIBRARIES) && !defined(LINUX))
25092#include <sys/procfs.h>
25093#include <sys/stat.h>
25094#include <fcntl.h>
25095#include <elf.h>
25096#include <errno.h>
25097#include <signal.h>
25098#ifndef _sigargs
25099#define IRIX6
25100#endif
25101GC_INNER void GC_register_dynamic_libraries(void)
25102{
25103 static int fd = -1;
25104 char buf[30];
25105 static prmap_t * addr_map = 0;
25106 static int current_sz = 0;
25107 int needed_sz = 0;
25108 int i;
25109 long flags;
25110 ptr_t start;
25111 ptr_t limit;
25112 ptr_t heap_start = HEAP_START;
25113 ptr_t heap_end = heap_start;
25114#ifdef SOLARISDL
25115#define MA_PHYS 0
25116#endif
25117 if (fd < 0) {
25118 (void)snprintf(buf, sizeof(buf), "/proc/%ld", (long)getpid());
25119 buf[sizeof(buf) - 1] = '\0';
25120 fd = open(buf, O_RDONLY);
25121 if (fd < 0) {
25122 ABORT("/proc open failed");
25123 }
25124 }
25125 if (ioctl(fd, PIOCNMAP, &needed_sz) < 0) {
25126 ABORT_ARG2("/proc PIOCNMAP ioctl failed",
25127 ": fd= %d, errno= %d", fd, errno);
25128 }
25129 if (needed_sz >= current_sz) {
25130 GC_scratch_recycle_no_gww(addr_map,
25131 (size_t)current_sz * sizeof(prmap_t));
25132 current_sz = needed_sz * 2 + 1;
25133 addr_map = (prmap_t *)GC_scratch_alloc(
25134 (size_t)current_sz * sizeof(prmap_t));
25135 if (addr_map == NULL)
25136 ABORT("Insufficient memory for address map");
25137 }
25138 if (ioctl(fd, PIOCMAP, addr_map) < 0) {
25139 ABORT_ARG3("/proc PIOCMAP ioctl failed",
25140 ": errcode= %d, needed_sz= %d, addr_map= %p",
25141 errno, needed_sz, (void *)addr_map);
25142 }
25143 if (GC_n_heap_sects > 0) {
25144 heap_end = GC_heap_sects[GC_n_heap_sects-1].hs_start
25145 + GC_heap_sects[GC_n_heap_sects-1].hs_bytes;
25146 if ((word)heap_end < (word)GC_scratch_last_end_ptr)
25147 heap_end = GC_scratch_last_end_ptr;
25148 }
25149 for (i = 0; i < needed_sz; i++) {
25150 flags = addr_map[i].pr_mflags;
25151 if ((flags & (MA_BREAK | MA_STACK | MA_PHYS
25152 | MA_FETCHOP | MA_NOTCACHED)) != 0) goto irrelevant;
25153 if ((flags & (MA_READ | MA_WRITE)) != (MA_READ | MA_WRITE))
25154 goto irrelevant;
25155 start = (ptr_t)(addr_map[i].pr_vaddr);
25156 if (GC_roots_present(start)) goto irrelevant;
25157 if ((word)start < (word)heap_end && (word)start >= (word)heap_start)
25158 goto irrelevant;
25159 limit = start + addr_map[i].pr_size;
25160#ifndef IRIX6
25161 if (addr_map[i].pr_off == 0 && strncmp(start, ELFMAG, 4) == 0) {
25162 caddr_t arg;
25163 int obj;
25164#define MAP_IRR_SZ 10
25165 static ptr_t map_irr[MAP_IRR_SZ];
25166 static int n_irr = 0;
25167 struct stat buf;
25168 int j;
25169 for (j = 0; j < n_irr; j++) {
25170 if (map_irr[j] == start) goto irrelevant;
25171 }
25172 arg = (caddr_t)start;
25173 obj = ioctl(fd, PIOCOPENM, &arg);
25174 if (obj >= 0) {
25175 fstat(obj, &buf);
25176 close(obj);
25177 if ((buf.st_mode & 0111) != 0) {
25178 if (n_irr < MAP_IRR_SZ) {
25179 map_irr[n_irr++] = start;
25180 }
25181 goto irrelevant;
25182 }
25183 }
25184 }
25185#endif
25186 GC_add_roots_inner(start, limit, TRUE);
25187 irrelevant: ;
25188 }
25189 if (close(fd) < 0) ABORT("Couldn't close /proc file");
25190 fd = -1;
25191}
25192#endif
25193#if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
25194#include <stdlib.h>
25195 STATIC void GC_cond_add_roots(char *base, char * limit)
25196 {
25197#ifdef GC_WIN32_THREADS
25198 char * curr_base = base;
25199 char * next_stack_lo;
25200 char * next_stack_hi;
25201 if (base == limit) return;
25202 for(;;) {
25203 GC_get_next_stack(curr_base, limit, &next_stack_lo, &next_stack_hi);
25204 if ((word)next_stack_lo >= (word)limit) break;
25205 if ((word)next_stack_lo > (word)curr_base)
25206 GC_add_roots_inner(curr_base, next_stack_lo, TRUE);
25207 curr_base = next_stack_hi;
25208 }
25209 if ((word)curr_base < (word)limit)
25210 GC_add_roots_inner(curr_base, limit, TRUE);
25211#else
25212 char * stack_top
25213 = (char *)((word)GC_approx_sp() &
25214 ~(word)(GC_sysinfo.dwAllocationGranularity - 1));
25215 if (base == limit) return;
25216 if ((word)limit > (word)stack_top
25217 && (word)base < (word)GC_stackbottom) {
25218 return;
25219 }
25220 GC_add_roots_inner(base, limit, TRUE);
25221#endif
25222 }
25223#ifdef DYNAMIC_LOADING
25224 GC_INNER GC_bool GC_register_main_static_data(void)
25225 {
25226#if defined(MSWINCE) || defined(CYGWIN32)
25227 return FALSE;
25228#else
25229 return GC_no_win32_dlls;
25230#endif
25231 }
25232#define HAVE_REGISTER_MAIN_STATIC_DATA
25233#endif
25234#ifdef DEBUG_VIRTUALQUERY
25235 void GC_dump_meminfo(MEMORY_BASIC_INFORMATION *buf)
25236 {
25237 GC_printf("BaseAddress= 0x%lx, AllocationBase= 0x%lx,"
25238 " RegionSize= 0x%lx(%lu)\n",
25239 buf -> BaseAddress, buf -> AllocationBase,
25240 buf -> RegionSize, buf -> RegionSize);
25241 GC_printf("\tAllocationProtect= 0x%lx, State= 0x%lx, Protect= 0x%lx, "
25242 "Type= 0x%lx\n", buf -> AllocationProtect, buf -> State,
25243 buf -> Protect, buf -> Type);
25244 }
25245#endif
25246#if defined(MSWINCE) || defined(CYGWIN32)
25247#define GC_wnt TRUE
25248#endif
25249 GC_INNER void GC_register_dynamic_libraries(void)
25250 {
25251 MEMORY_BASIC_INFORMATION buf;
25252 DWORD protect;
25253 LPVOID p;
25254 char * base;
25255 char * limit, * new_limit;
25256#ifdef MSWIN32
25257 if (GC_no_win32_dlls) return;
25258#endif
25259 p = GC_sysinfo.lpMinimumApplicationAddress;
25260 base = limit = (char *)p;
25261 while ((word)p < (word)GC_sysinfo.lpMaximumApplicationAddress) {
25262 size_t result = VirtualQuery(p, &buf, sizeof(buf));
25263#ifdef MSWINCE
25264 if (result == 0) {
25265 new_limit = (char *)
25266 (((DWORD) p + GC_sysinfo.dwAllocationGranularity)
25267 & ~(GC_sysinfo.dwAllocationGranularity-1));
25268 } else
25269#endif
25270 {
25271 if (result != sizeof(buf)) {
25272 ABORT("Weird VirtualQuery result");
25273 }
25274 new_limit = (char *)p + buf.RegionSize;
25275 protect = buf.Protect;
25276 if (buf.State == MEM_COMMIT
25277 && (protect == PAGE_EXECUTE_READWRITE
25278 || protect == PAGE_EXECUTE_WRITECOPY
25279 || protect == PAGE_READWRITE
25280 || protect == PAGE_WRITECOPY)
25281 && (buf.Type == MEM_IMAGE
25282#ifdef GC_REGISTER_MEM_PRIVATE
25283 || (protect == PAGE_READWRITE && buf.Type == MEM_PRIVATE)
25284#else
25285 || (!GC_wnt && buf.Type == MEM_PRIVATE)
25286#endif
25287 )
25288 && !GC_is_heap_base(buf.AllocationBase)) {
25289#ifdef DEBUG_VIRTUALQUERY
25290 GC_dump_meminfo(&buf);
25291#endif
25292 if ((char *)p != limit) {
25293 GC_cond_add_roots(base, limit);
25294 base = (char *)p;
25295 }
25296 limit = new_limit;
25297 }
25298 }
25299 if ((word)p > (word)new_limit ) break;
25300 p = (LPVOID)new_limit;
25301 }
25302 GC_cond_add_roots(base, limit);
25303 }
25304#endif
25305#if defined(ALPHA) && defined(OSF1)
25306#include <loader.h>
25307EXTERN_C_BEGIN
25308extern char *sys_errlist[];
25309extern int sys_nerr;
25310extern int errno;
25311EXTERN_C_END
25312GC_INNER void GC_register_dynamic_libraries(void)
25313{
25314 ldr_module_t moduleid = LDR_NULL_MODULE;
25315 ldr_process_t mypid = ldr_my_process();
25316 while (TRUE) {
25317 ldr_module_info_t moduleinfo;
25318 size_t modulereturnsize;
25319 ldr_region_t region;
25320 ldr_region_info_t regioninfo;
25321 size_t regionreturnsize;
25322 int status = ldr_next_module(mypid, &moduleid);
25323 if (moduleid == LDR_NULL_MODULE)
25324 break;
25325 if (status != 0) {
25326 ABORT_ARG3("ldr_next_module failed",
25327 ": status= %d, errcode= %d (%s)", status, errno,
25328 errno < sys_nerr ? sys_errlist[errno] : "");
25329 }
25330 status = ldr_inq_module(mypid, moduleid, &moduleinfo,
25331 sizeof(moduleinfo), &modulereturnsize);
25332 if (status != 0 )
25333 ABORT("ldr_inq_module failed");
25334 if (moduleinfo.lmi_flags & LDR_MAIN)
25335 continue;
25336#ifdef DL_VERBOSE
25337 GC_log_printf("---Module---\n");
25338 GC_log_printf("Module ID: %ld\n", moduleinfo.lmi_modid);
25339 GC_log_printf("Count of regions: %d\n", moduleinfo.lmi_nregion);
25340 GC_log_printf("Flags for module: %016lx\n", moduleinfo.lmi_flags);
25341 GC_log_printf("Module pathname: \"%s\"\n", moduleinfo.lmi_name);
25342#endif
25343 for (region = 0; region < moduleinfo.lmi_nregion; region++) {
25344 status = ldr_inq_region(mypid, moduleid, region, ®ioninfo,
25345 sizeof(regioninfo), ®ionreturnsize);
25346 if (status != 0 )
25347 ABORT("ldr_inq_region failed");
25348 if (! (regioninfo.lri_prot & LDR_W))
25349 continue;
25350#ifdef DL_VERBOSE
25351 GC_log_printf("--- Region ---\n");
25352 GC_log_printf("Region number: %ld\n", regioninfo.lri_region_no);
25353 GC_log_printf("Protection flags: %016x\n", regioninfo.lri_prot);
25354 GC_log_printf("Virtual address: %p\n", regioninfo.lri_vaddr);
25355 GC_log_printf("Mapped address: %p\n", regioninfo.lri_mapaddr);
25356 GC_log_printf("Region size: %ld\n", regioninfo.lri_size);
25357 GC_log_printf("Region name: \"%s\"\n", regioninfo.lri_name);
25358#endif
25359 GC_add_roots_inner((char *)regioninfo.lri_mapaddr,
25360 (char *)regioninfo.lri_mapaddr + regioninfo.lri_size,
25361 TRUE);
25362 }
25363 }
25364}
25365#endif
25366#if defined(HPUX)
25367#include <errno.h>
25368#include <dl.h>
25369EXTERN_C_BEGIN
25370extern char *sys_errlist[];
25371extern int sys_nerr;
25372EXTERN_C_END
25373GC_INNER void GC_register_dynamic_libraries(void)
25374{
25375 int index = 1;
25376 while (TRUE) {
25377 struct shl_descriptor *shl_desc;
25378 int status = shl_get(index, &shl_desc);
25379 if (status != 0) {
25380#ifdef GC_HPUX_THREADS
25381 break;
25382#else
25383 if (errno == EINVAL) {
25384 break;
25385 } else {
25386 ABORT_ARG3("shl_get failed",
25387 ": status= %d, errcode= %d (%s)", status, errno,
25388 errno < sys_nerr ? sys_errlist[errno] : "");
25389 }
25390#endif
25391 }
25392#ifdef DL_VERBOSE
25393 GC_log_printf("---Shared library---\n");
25394 GC_log_printf("filename= \"%s\"\n", shl_desc->filename);
25395 GC_log_printf("index= %d\n", index);
25396 GC_log_printf("handle= %08x\n", (unsigned long) shl_desc->handle);
25397 GC_log_printf("text seg.start= %08x\n", shl_desc->tstart);
25398 GC_log_printf("text seg.end= %08x\n", shl_desc->tend);
25399 GC_log_printf("data seg.start= %08x\n", shl_desc->dstart);
25400 GC_log_printf("data seg.end= %08x\n", shl_desc->dend);
25401 GC_log_printf("ref.count= %lu\n", shl_desc->ref_count);
25402#endif
25403 GC_add_roots_inner((char *) shl_desc->dstart,
25404 (char *) shl_desc->dend, TRUE);
25405 index++;
25406 }
25407}
25408#endif
25409#ifdef AIX
25410#include <alloca.h>
25411#include <sys/ldr.h>
25412#include <sys/errno.h>
25413 GC_INNER void GC_register_dynamic_libraries(void)
25414 {
25415 int ldibuflen = 8192;
25416 for (;;) {
25417 int len;
25418 struct ld_info *ldi;
25419#if defined(CPPCHECK)
25420 char ldibuf[ldibuflen];
25421#else
25422 char *ldibuf = alloca(ldibuflen);
25423#endif
25424 len = loadquery(L_GETINFO, ldibuf, ldibuflen);
25425 if (len < 0) {
25426 if (errno != ENOMEM) {
25427 ABORT("loadquery failed");
25428 }
25429 ldibuflen *= 2;
25430 continue;
25431 }
25432 ldi = (struct ld_info *)ldibuf;
25433 while (ldi) {
25434 len = ldi->ldinfo_next;
25435 GC_add_roots_inner(
25436 ldi->ldinfo_dataorg,
25437 (ptr_t)(unsigned long)ldi->ldinfo_dataorg
25438 + ldi->ldinfo_datasize,
25439 TRUE);
25440 ldi = len ? (struct ld_info *)((char *)ldi + len) : 0;
25441 }
25442 break;
25443 }
25444 }
25445#endif
25446#ifdef DARWIN
25447#ifndef __private_extern__
25448#define __private_extern__ extern
25449#include <mach-o/dyld.h>
25450#undef __private_extern__
25451#else
25452#include <mach-o/dyld.h>
25453#endif
25454#include <mach-o/getsect.h>
25455STATIC const struct dyld_sections_s {
25456 const char *seg;
25457 const char *sect;
25458} GC_dyld_sections[] = {
25459 { SEG_DATA, SECT_DATA },
25460 { SEG_DATA, "__static_data" },
25461 { SEG_DATA, SECT_BSS },
25462 { SEG_DATA, SECT_COMMON },
25463 { SEG_DATA, "__zobj_data" },
25464 { SEG_DATA, "__zobj_bss" }
25465};
25466STATIC const char * const GC_dyld_add_sect_fmts[] = {
25467 "__bss%u",
25468 "__pu_bss%u",
25469 "__zo_bss%u",
25470 "__zo_pu_bss%u"
25471};
25472#ifndef L2_MAX_OFILE_ALIGNMENT
25473#define L2_MAX_OFILE_ALIGNMENT 15
25474#endif
25475STATIC const char *GC_dyld_name_for_hdr(const struct GC_MACH_HEADER *hdr)
25476{
25477 unsigned long i, c;
25478 c = _dyld_image_count();
25479 for (i = 0; i < c; i++)
25480 if ((const struct GC_MACH_HEADER *)_dyld_get_image_header(i) == hdr)
25481 return _dyld_get_image_name(i);
25482 return NULL;
25483}
25484STATIC void GC_dyld_image_add(const struct GC_MACH_HEADER *hdr,
25485 intptr_t slide)
25486{
25487 unsigned long start, end;
25488 unsigned i, j;
25489 const struct GC_MACH_SECTION *sec;
25490 const char *name;
25491 GC_has_static_roots_func callback = GC_has_static_roots;
25492 DCL_LOCK_STATE;
25493 if (GC_no_dls) return;
25494#ifdef DARWIN_DEBUG
25495 name = GC_dyld_name_for_hdr(hdr);
25496#else
25497 name = callback != 0 ? GC_dyld_name_for_hdr(hdr) : NULL;
25498#endif
25499 for (i = 0; i < sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]); i++) {
25500 sec = GC_GETSECTBYNAME(hdr, GC_dyld_sections[i].seg,
25501 GC_dyld_sections[i].sect);
25502 if (sec == NULL || sec->size < sizeof(word))
25503 continue;
25504 start = slide + sec->addr;
25505 end = start + sec->size;
25506 LOCK();
25507 if (callback == 0 || callback(name, (void*)start, (size_t)sec->size)) {
25508#ifdef DARWIN_DEBUG
25509 GC_log_printf(
25510 "Adding section __DATA,%s at %p-%p (%lu bytes) from image %s\n",
25511 GC_dyld_sections[i].sect, (void*)start, (void*)end,
25512 (unsigned long)sec->size, name);
25513#endif
25514 GC_add_roots_inner((ptr_t)start, (ptr_t)end, FALSE);
25515 }
25516 UNLOCK();
25517 }
25518 for (j = 0; j < sizeof(GC_dyld_add_sect_fmts) / sizeof(char *); j++) {
25519 const char *fmt = GC_dyld_add_sect_fmts[j];
25520 for (i = 0; i <= L2_MAX_OFILE_ALIGNMENT; i++) {
25521 char secnam[16];
25522 (void)snprintf(secnam, sizeof(secnam), fmt, (unsigned)i);
25523 secnam[sizeof(secnam) - 1] = '\0';
25524 sec = GC_GETSECTBYNAME(hdr, SEG_DATA, secnam);
25525 if (sec == NULL || sec->size == 0)
25526 continue;
25527 start = slide + sec->addr;
25528 end = start + sec->size;
25529#ifdef DARWIN_DEBUG
25530 GC_log_printf("Adding on-demand section __DATA,%s at"
25531 " %p-%p (%lu bytes) from image %s\n",
25532 secnam, (void*)start, (void*)end,
25533 (unsigned long)sec->size, name);
25534#endif
25535 GC_add_roots((char*)start, (char*)end);
25536 }
25537 }
25538#if defined(DARWIN_DEBUG) && !defined(NO_DEBUGGING)
25539 LOCK();
25540 GC_print_static_roots();
25541 UNLOCK();
25542#endif
25543}
25544STATIC void GC_dyld_image_remove(const struct GC_MACH_HEADER *hdr,
25545 intptr_t slide)
25546{
25547 unsigned long start, end;
25548 unsigned i, j;
25549 const struct GC_MACH_SECTION *sec;
25550#if defined(DARWIN_DEBUG) && !defined(NO_DEBUGGING)
25551 DCL_LOCK_STATE;
25552#endif
25553 for (i = 0; i < sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]); i++) {
25554 sec = GC_GETSECTBYNAME(hdr, GC_dyld_sections[i].seg,
25555 GC_dyld_sections[i].sect);
25556 if (sec == NULL || sec->size == 0)
25557 continue;
25558 start = slide + sec->addr;
25559 end = start + sec->size;
25560#ifdef DARWIN_DEBUG
25561 GC_log_printf(
25562 "Removing section __DATA,%s at %p-%p (%lu bytes) from image %s\n",
25563 GC_dyld_sections[i].sect, (void*)start, (void*)end,
25564 (unsigned long)sec->size, GC_dyld_name_for_hdr(hdr));
25565#endif
25566 GC_remove_roots((char*)start, (char*)end);
25567 }
25568 for (j = 0; j < sizeof(GC_dyld_add_sect_fmts) / sizeof(char *); j++) {
25569 const char *fmt = GC_dyld_add_sect_fmts[j];
25570 for (i = 0; i <= L2_MAX_OFILE_ALIGNMENT; i++) {
25571 char secnam[16];
25572 (void)snprintf(secnam, sizeof(secnam), fmt, (unsigned)i);
25573 secnam[sizeof(secnam) - 1] = '\0';
25574 sec = GC_GETSECTBYNAME(hdr, SEG_DATA, secnam);
25575 if (sec == NULL || sec->size == 0)
25576 continue;
25577 start = slide + sec->addr;
25578 end = start + sec->size;
25579#ifdef DARWIN_DEBUG
25580 GC_log_printf("Removing on-demand section __DATA,%s at"
25581 " %p-%p (%lu bytes) from image %s\n", secnam,
25582 (void*)start, (void*)end, (unsigned long)sec->size,
25583 GC_dyld_name_for_hdr(hdr));
25584#endif
25585 GC_remove_roots((char*)start, (char*)end);
25586 }
25587 }
25588#if defined(DARWIN_DEBUG) && !defined(NO_DEBUGGING)
25589 LOCK();
25590 GC_print_static_roots();
25591 UNLOCK();
25592#endif
25593}
25594GC_INNER void GC_register_dynamic_libraries(void)
25595{
25596}
25597GC_INNER void GC_init_dyld(void)
25598{
25599 static GC_bool initialized = FALSE;
25600 if (initialized) return;
25601#ifdef DARWIN_DEBUG
25602 GC_log_printf("Registering dyld callbacks...\n");
25603#endif
25604 _dyld_register_func_for_add_image(
25605 (void (*)(const struct mach_header*, intptr_t))GC_dyld_image_add);
25606 _dyld_register_func_for_remove_image(
25607 (void (*)(const struct mach_header*, intptr_t))GC_dyld_image_remove);
25608 initialized = TRUE;
25609#ifdef NO_DYLD_BIND_FULLY_IMAGE
25610#else
25611 if (GC_no_dls) return;
25612 if (GETENV("DYLD_BIND_AT_LAUNCH") == 0) {
25613#ifdef DARWIN_DEBUG
25614 GC_log_printf("Forcing full bind of GC code...\n");
25615#endif
25616 if (!_dyld_bind_fully_image_containing_address(
25617 (unsigned long *)GC_malloc))
25618 ABORT("_dyld_bind_fully_image_containing_address failed");
25619 }
25620#endif
25621}
25622#define HAVE_REGISTER_MAIN_STATIC_DATA
25623GC_INNER GC_bool GC_register_main_static_data(void)
25624{
25625 return FALSE;
25626}
25627#endif
25628#if defined(HAIKU)
25629#include <kernel/image.h>
25630 GC_INNER void GC_register_dynamic_libraries(void)
25631 {
25632 image_info info;
25633 int32 cookie = 0;
25634 while (get_next_image_info(0, &cookie, &info) == B_OK) {
25635 ptr_t data = (ptr_t)info.data;
25636 GC_add_roots_inner(data, data + info.data_size, TRUE);
25637 }
25638 }
25639#endif
25640#elif defined(PCR)
25641 GC_INNER void GC_register_dynamic_libraries(void)
25642 {
25643 PCR_IL_LoadedFile * p = PCR_IL_GetLastLoadedFile();
25644 PCR_IL_LoadedSegment * q;
25645 while (p != NIL && !(p -> lf_commitPoint)) {
25646 p = p -> lf_prev;
25647 }
25648 for (; p != NIL; p = p -> lf_prev) {
25649 for (q = p -> lf_ls; q != NIL; q = q -> ls_next) {
25650 if ((q -> ls_flags & PCR_IL_SegFlags_Traced_MASK)
25651 == PCR_IL_SegFlags_Traced_on) {
25652 GC_add_roots_inner((ptr_t)q->ls_addr,
25653 (ptr_t)q->ls_addr + q->ls_bytes, TRUE);
25654 }
25655 }
25656 }
25657 }
25658#endif
25659#if !defined(HAVE_REGISTER_MAIN_STATIC_DATA) && defined(DYNAMIC_LOADING)
25660 GC_INNER GC_bool GC_register_main_static_data(void)
25661 {
25662 return TRUE;
25663 }
25664#endif
25665GC_API void GC_CALL GC_register_has_static_roots_callback(
25666 GC_has_static_roots_func callback)
25667{
25668 GC_has_static_roots = callback;
25669}
25670#if defined(GC_PTHREADS) && !defined(GC_NO_DLOPEN)
25671#undef GC_MUST_RESTORE_REDEFINED_DLOPEN
25672#if defined(dlopen) && !defined(GC_USE_LD_WRAP)
25673#undef dlopen
25674#define GC_MUST_RESTORE_REDEFINED_DLOPEN
25675#endif
25676#ifndef USE_PROC_FOR_LIBRARIES
25677 static void disable_gc_for_dlopen(void)
25678 {
25679 DCL_LOCK_STATE;
25680 LOCK();
25681 while (GC_incremental && GC_collection_in_progress()) {
25682 ENTER_GC();
25683 GC_collect_a_little_inner(1000);
25684 EXIT_GC();
25685 }
25686 ++GC_dont_gc;
25687 UNLOCK();
25688 }
25689#endif
25690#ifdef GC_USE_LD_WRAP
25691#define WRAP_DLFUNC(f) __wrap_##f
25692#define REAL_DLFUNC(f) __real_##f
25693 void * REAL_DLFUNC(dlopen)(const char *, int);
25694#else
25695#define WRAP_DLFUNC(f) GC_##f
25696#define REAL_DLFUNC(f) f
25697#endif
25698GC_API void * WRAP_DLFUNC(dlopen)(const char *path, int mode)
25699{
25700 void * result;
25701#ifndef USE_PROC_FOR_LIBRARIES
25702 disable_gc_for_dlopen();
25703#endif
25704 result = REAL_DLFUNC(dlopen)(path, mode);
25705#ifndef USE_PROC_FOR_LIBRARIES
25706 GC_enable();
25707#endif
25708 return(result);
25709}
25710#ifdef GC_USE_LD_WRAP
25711 GC_API void *GC_dlopen(const char *path, int mode)
25712 {
25713 return dlopen(path, mode);
25714 }
25715#endif
25716#ifdef GC_MUST_RESTORE_REDEFINED_DLOPEN
25717#define dlopen GC_dlopen
25718#endif
25719#endif
25720#if !defined(PLATFORM_MACH_DEP)
25721#if !defined(PLATFORM_MACH_DEP) && !defined(SN_TARGET_PSP2)
25722#include <stdio.h>
25723#ifdef AMIGA
25724#ifndef __GNUC__
25725#include <dos.h>
25726#else
25727#include <machine/reg.h>
25728#endif
25729#endif
25730#if defined(MACOS) && defined(__MWERKS__)
25731#if defined(POWERPC)
25732#define NONVOLATILE_GPR_COUNT 19
25733 struct ppc_registers {
25734 unsigned long gprs[NONVOLATILE_GPR_COUNT];
25735 };
25736 typedef struct ppc_registers ppc_registers;
25737#if defined(CPPCHECK)
25738 void getRegisters(ppc_registers* regs);
25739#else
25740 asm static void getRegisters(register ppc_registers* regs)
25741 {
25742 stmw r13,regs->gprs
25743 blr
25744 }
25745#endif
25746 static void PushMacRegisters(void)
25747 {
25748 ppc_registers regs;
25749 int i;
25750 getRegisters(®s);
25751 for (i = 0; i < NONVOLATILE_GPR_COUNT; i++)
25752 GC_push_one(regs.gprs[i]);
25753 }
25754#else
25755 asm static void PushMacRegisters(void)
25756 {
25757 sub.w #4,sp
25758 move.l a2,(sp)
25759 jsr GC_push_one
25760 move.l a3,(sp)
25761 jsr GC_push_one
25762 move.l a4,(sp)
25763 jsr GC_push_one
25764#if !__option(a6frames)
25765 move.l a6,(sp)
25766 jsr GC_push_one
25767#endif
25768 move.l d2,(sp)
25769 jsr GC_push_one
25770 move.l d3,(sp)
25771 jsr GC_push_one
25772 move.l d4,(sp)
25773 jsr GC_push_one
25774 move.l d5,(sp)
25775 jsr GC_push_one
25776 move.l d6,(sp)
25777 jsr GC_push_one
25778 move.l d7,(sp)
25779 jsr GC_push_one
25780 add.w #4,sp
25781 rts
25782 }
25783#endif
25784#endif
25785#if defined(SPARC) || defined(IA64)
25786 GC_INNER ptr_t GC_save_regs_ret_val = NULL;
25787#endif
25788#undef HAVE_PUSH_REGS
25789#if defined(USE_ASM_PUSH_REGS)
25790#define HAVE_PUSH_REGS
25791#else
25792#ifdef STACK_NOT_SCANNED
25793 void GC_push_regs(void)
25794 {
25795 }
25796#define HAVE_PUSH_REGS
25797#elif defined(M68K) && defined(AMIGA)
25798 void GC_push_regs(void)
25799 {
25800#ifdef __GNUC__
25801 asm("subq.w &0x4,%sp");
25802 asm("mov.l %a2,(%sp)"); asm("jsr _GC_push_one");
25803 asm("mov.l %a3,(%sp)"); asm("jsr _GC_push_one");
25804 asm("mov.l %a4,(%sp)"); asm("jsr _GC_push_one");
25805 asm("mov.l %a5,(%sp)"); asm("jsr _GC_push_one");
25806 asm("mov.l %a6,(%sp)"); asm("jsr _GC_push_one");
25807 asm("mov.l %d2,(%sp)"); asm("jsr _GC_push_one");
25808 asm("mov.l %d3,(%sp)"); asm("jsr _GC_push_one");
25809 asm("mov.l %d4,(%sp)"); asm("jsr _GC_push_one");
25810 asm("mov.l %d5,(%sp)"); asm("jsr _GC_push_one");
25811 asm("mov.l %d6,(%sp)"); asm("jsr _GC_push_one");
25812 asm("mov.l %d7,(%sp)"); asm("jsr _GC_push_one");
25813 asm("addq.w &0x4,%sp");
25814#else
25815 GC_push_one(getreg(REG_A2));
25816 GC_push_one(getreg(REG_A3));
25817#ifndef __SASC
25818 GC_push_one(getreg(REG_A4));
25819#endif
25820 GC_push_one(getreg(REG_A5));
25821 GC_push_one(getreg(REG_A6));
25822 GC_push_one(getreg(REG_D2));
25823 GC_push_one(getreg(REG_D3));
25824 GC_push_one(getreg(REG_D4));
25825 GC_push_one(getreg(REG_D5));
25826 GC_push_one(getreg(REG_D6));
25827 GC_push_one(getreg(REG_D7));
25828#endif
25829 }
25830#define HAVE_PUSH_REGS
25831#elif defined(MACOS)
25832#if defined(M68K) && defined(THINK_C) && !defined(CPPCHECK)
25833#define PushMacReg(reg) \
25834 move.l reg,(sp) \
25835 jsr GC_push_one
25836 void GC_push_regs(void)
25837 {
25838 asm {
25839 sub.w #4,sp ; reserve space for one parameter.
25840 PushMacReg(a2);
25841 PushMacReg(a3);
25842 PushMacReg(a4);
25843 ; skip a5 (globals), a6 (frame pointer), and a7 (stack pointer)
25844 PushMacReg(d2);
25845 PushMacReg(d3);
25846 PushMacReg(d4);
25847 PushMacReg(d5);
25848 PushMacReg(d6);
25849 PushMacReg(d7);
25850 add.w #4,sp ; fix stack.
25851 }
25852 }
25853#define HAVE_PUSH_REGS
25854#undef PushMacReg
25855#elif defined(__MWERKS__)
25856 void GC_push_regs(void)
25857 {
25858 PushMacRegisters();
25859 }
25860#define HAVE_PUSH_REGS
25861#endif
25862#endif
25863#endif
25864#if defined(HAVE_PUSH_REGS) && defined(THREADS)
25865#error GC_push_regs cannot be used with threads
25866#undef HAVE_PUSH_REGS
25867#endif
25868#if !defined(HAVE_PUSH_REGS) && defined(UNIX_LIKE)
25869#include <signal.h>
25870#ifndef NO_GETCONTEXT
25871#if defined(DARWIN) \
25872 && (MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 )
25873#include <sys/ucontext.h>
25874#else
25875#include <ucontext.h>
25876#endif
25877#ifdef GETCONTEXT_FPU_EXCMASK_BUG
25878#include <fenv.h>
25879#endif
25880#endif
25881#endif
25882GC_ATTR_NO_SANITIZE_ADDR
25883GC_INNER void GC_with_callee_saves_pushed(void (*fn)(ptr_t, void *),
25884 volatile ptr_t arg)
25885{
25886 volatile int dummy;
25887 volatile ptr_t context = 0;
25888#if defined(HAVE_PUSH_REGS)
25889 GC_push_regs();
25890#elif defined(EMSCRIPTEN)
25891#else
25892#if defined(UNIX_LIKE) && !defined(NO_GETCONTEXT)
25893 static signed char getcontext_works = 0;
25894 ucontext_t ctxt;
25895#ifdef GETCONTEXT_FPU_EXCMASK_BUG
25896#ifdef X86_64
25897 unsigned short old_fcw;
25898#if defined(CPPCHECK)
25899 GC_noop1((word)&old_fcw);
25900#endif
25901 __asm__ __volatile__ ("fstcw %0" : "=m" (*&old_fcw));
25902#else
25903 int except_mask = fegetexcept();
25904#endif
25905#endif
25906 if (getcontext_works >= 0) {
25907 if (getcontext(&ctxt) < 0) {
25908 WARN("getcontext failed:"
25909 " using another register retrieval method...\n", 0);
25910 } else {
25911 context = (ptr_t)&ctxt;
25912 }
25913 if (EXPECT(0 == getcontext_works, FALSE))
25914 getcontext_works = context != NULL ? 1 : -1;
25915 }
25916#ifdef GETCONTEXT_FPU_EXCMASK_BUG
25917#ifdef X86_64
25918 __asm__ __volatile__ ("fldcw %0" : : "m" (*&old_fcw));
25919 {
25920 unsigned mxcsr;
25921 __asm__ __volatile__ ("stmxcsr %0" : "=m" (*&mxcsr));
25922 mxcsr = (mxcsr & ~(FE_ALL_EXCEPT << 7)) |
25923 ((old_fcw & FE_ALL_EXCEPT) << 7);
25924 __asm__ __volatile__ ("ldmxcsr %0" : : "m" (*&mxcsr));
25925 }
25926#else
25927 if (feenableexcept(except_mask) < 0)
25928 ABORT("feenableexcept failed");
25929#endif
25930#endif
25931#if defined(SPARC) || defined(IA64)
25932 GC_save_regs_ret_val = GC_save_regs_in_stack();
25933#endif
25934 if (NULL == context)
25935#endif
25936 {
25937#if defined(HAVE_BUILTIN_UNWIND_INIT)
25938 __builtin_unwind_init();
25939#elif defined(NO_CRT) && defined(MSWIN32)
25940 CONTEXT ctx;
25941 RtlCaptureContext(&ctx);
25942#else
25943 jmp_buf regs;
25944 word * i = (word *)®s;
25945 ptr_t lim = (ptr_t)(®s) + sizeof(regs);
25946 for (; (word)i < (word)lim; i++) {
25947 *i = 0;
25948 }
25949#if defined(MSWIN32) || defined(MSWINCE) || defined(UTS4) \
25950 || defined(OS2) || defined(CX_UX) || defined(__CC_ARM) \
25951 || defined(LINUX) || defined(EWS4800) || defined(RTEMS)
25952 (void) setjmp(regs);
25953#else
25954 (void) _setjmp(regs);
25955#endif
25956#endif
25957 }
25958#endif
25959 fn(arg, ( void *)context);
25960 GC_noop1(COVERT_DATAFLOW(&dummy));
25961}
25962#endif
25963#endif
25964#if !defined(PLATFORM_STOP_WORLD)
25965#if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS) && \
25966 !defined(GC_DARWIN_THREADS) && !defined(PLATFORM_STOP_WORLD) \
25967 && !defined(SN_TARGET_PSP2)
25968#ifdef NACL
25969#include <unistd.h>
25970#include <sys/time.h>
25971 STATIC int GC_nacl_num_gc_threads = 0;
25972 STATIC __thread int GC_nacl_thread_idx = -1;
25973 STATIC volatile int GC_nacl_park_threads_now = 0;
25974 STATIC volatile pthread_t GC_nacl_thread_parker = -1;
25975 GC_INNER __thread GC_thread GC_nacl_gc_thread_self = NULL;
25976 volatile int GC_nacl_thread_parked[MAX_NACL_GC_THREADS];
25977 int GC_nacl_thread_used[MAX_NACL_GC_THREADS];
25978#elif defined(GC_OPENBSD_UTHREADS)
25979#include <pthread_np.h>
25980#else
25981#include <signal.h>
25982#include <semaphore.h>
25983#include <errno.h>
25984#include <time.h>
25985#include <unistd.h>
25986#if (!defined(AO_HAVE_load_acquire) || !defined(AO_HAVE_store_release)) \
25987 && !defined(CPPCHECK)
25988#error AO_load_acquire and/or AO_store_release are missing;
25989#error please define AO_REQUIRE_CAS manually
25990#endif
25991#undef pthread_sigmask
25992#ifdef GC_ENABLE_SUSPEND_THREAD
25993 static void *GC_CALLBACK suspend_self_inner(void *client_data);
25994#endif
25995#ifdef DEBUG_THREADS
25996#ifndef NSIG
25997#if defined(MAXSIG)
25998#define NSIG (MAXSIG+1)
25999#elif defined(_NSIG)
26000#define NSIG _NSIG
26001#elif defined(__SIGRTMAX)
26002#define NSIG (__SIGRTMAX+1)
26003#else
26004#error define NSIG
26005#endif
26006#endif
26007 void GC_print_sig_mask(void)
26008 {
26009 sigset_t blocked;
26010 int i;
26011 if (pthread_sigmask(SIG_BLOCK, NULL, &blocked) != 0)
26012 ABORT("pthread_sigmask failed");
26013 for (i = 1; i < NSIG; i++) {
26014 if (sigismember(&blocked, i))
26015 GC_printf("Signal blocked: %d\n", i);
26016 }
26017 }
26018#endif
26019STATIC void GC_remove_allowed_signals(sigset_t *set)
26020{
26021 if (sigdelset(set, SIGINT) != 0
26022 || sigdelset(set, SIGQUIT) != 0
26023 || sigdelset(set, SIGABRT) != 0
26024 || sigdelset(set, SIGTERM) != 0) {
26025 ABORT("sigdelset failed");
26026 }
26027#ifdef MPROTECT_VDB
26028 if (sigdelset(set, SIGSEGV) != 0
26029#ifdef HAVE_SIGBUS
26030 || sigdelset(set, SIGBUS) != 0
26031#endif
26032 ) {
26033 ABORT("sigdelset failed");
26034 }
26035#endif
26036}
26037static sigset_t suspend_handler_mask;
26038#define THREAD_RESTARTED 0x1
26039STATIC volatile AO_t GC_stop_count = 0;
26040STATIC volatile AO_t GC_world_is_stopped = FALSE;
26041#ifndef NO_RETRY_SIGNALS
26042 STATIC GC_bool GC_retry_signals = TRUE;
26043#else
26044 STATIC GC_bool GC_retry_signals = FALSE;
26045#endif
26046#ifndef SIG_THR_RESTART
26047#if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS) \
26048 || defined(GC_NETBSD_THREADS) || defined(GC_USESIGRT_SIGNALS)
26049#if defined(_SIGRTMIN) && !defined(CPPCHECK)
26050#define SIG_THR_RESTART _SIGRTMIN + 5
26051#else
26052#define SIG_THR_RESTART SIGRTMIN + 5
26053#endif
26054#else
26055#define SIG_THR_RESTART SIGXCPU
26056#endif
26057#endif
26058#define SIGNAL_UNSET (-1)
26059STATIC int GC_sig_suspend = SIGNAL_UNSET;
26060STATIC int GC_sig_thr_restart = SIGNAL_UNSET;
26061GC_API void GC_CALL GC_set_suspend_signal(int sig)
26062{
26063 if (GC_is_initialized) return;
26064 GC_sig_suspend = sig;
26065}
26066GC_API void GC_CALL GC_set_thr_restart_signal(int sig)
26067{
26068 if (GC_is_initialized) return;
26069 GC_sig_thr_restart = sig;
26070}
26071GC_API int GC_CALL GC_get_suspend_signal(void)
26072{
26073 return GC_sig_suspend != SIGNAL_UNSET ? GC_sig_suspend : SIG_SUSPEND;
26074}
26075GC_API int GC_CALL GC_get_thr_restart_signal(void)
26076{
26077 return GC_sig_thr_restart != SIGNAL_UNSET
26078 ? GC_sig_thr_restart : SIG_THR_RESTART;
26079}
26080#if defined(GC_EXPLICIT_SIGNALS_UNBLOCK) \
26081 || !defined(NO_SIGNALS_UNBLOCK_IN_MAIN)
26082 GC_INNER void GC_unblock_gc_signals(void)
26083 {
26084 sigset_t set;
26085 sigemptyset(&set);
26086 GC_ASSERT(GC_sig_suspend != SIGNAL_UNSET);
26087 GC_ASSERT(GC_sig_thr_restart != SIGNAL_UNSET);
26088 sigaddset(&set, GC_sig_suspend);
26089 sigaddset(&set, GC_sig_thr_restart);
26090 if (pthread_sigmask(SIG_UNBLOCK, &set, NULL) != 0)
26091 ABORT("pthread_sigmask failed");
26092 }
26093#endif
26094STATIC sem_t GC_suspend_ack_sem;
26095STATIC void GC_suspend_handler_inner(ptr_t dummy, void *context);
26096#ifndef NO_SA_SIGACTION
26097 STATIC void GC_suspend_handler(int sig, siginfo_t * info GC_ATTR_UNUSED,
26098 void * context GC_ATTR_UNUSED)
26099#else
26100 STATIC void GC_suspend_handler(int sig)
26101#endif
26102{
26103 int old_errno = errno;
26104 if (sig != GC_sig_suspend) {
26105#if defined(GC_FREEBSD_THREADS)
26106 if (0 == sig) return;
26107#endif
26108 ABORT("Bad signal in suspend_handler");
26109 }
26110#if defined(IA64) || defined(HP_PA) || defined(M68K)
26111 GC_with_callee_saves_pushed(GC_suspend_handler_inner, NULL);
26112#else
26113 {
26114#ifdef NO_SA_SIGACTION
26115 void *context = 0;
26116#endif
26117 GC_suspend_handler_inner(NULL, context);
26118 }
26119#endif
26120 errno = old_errno;
26121}
26122#ifdef BASE_ATOMIC_OPS_EMULATED
26123#define ao_load_acquire_async(p) (*(p))
26124#define ao_load_async(p) ao_load_acquire_async(p)
26125#define ao_store_release_async(p, v) (void)(*(p) = (v))
26126#define ao_store_async(p, v) ao_store_release_async(p, v)
26127#else
26128#define ao_load_acquire_async(p) AO_load_acquire(p)
26129#define ao_load_async(p) AO_load(p)
26130#define ao_store_release_async(p, v) AO_store_release(p, v)
26131#define ao_store_async(p, v) AO_store(p, v)
26132#endif
26133#ifdef THREAD_SANITIZER
26134 GC_ATTR_NO_SANITIZE_THREAD
26135 static GC_thread GC_lookup_thread_async(pthread_t id)
26136 {
26137 GC_thread p = GC_threads[THREAD_TABLE_INDEX(id)];
26138 while (p != NULL && !THREAD_EQUAL(p->id, id))
26139 p = p->next;
26140 return p;
26141 }
26142#else
26143#define GC_lookup_thread_async GC_lookup_thread
26144#endif
26145GC_INLINE void GC_store_stack_ptr(GC_thread me)
26146{
26147#ifdef SPARC
26148 ao_store_async((volatile AO_t *)&me->stop_info.stack_ptr,
26149 (AO_t)GC_save_regs_in_stack());
26150#else
26151#ifdef IA64
26152 me -> backing_store_ptr = GC_save_regs_in_stack();
26153#endif
26154 ao_store_async((volatile AO_t *)&me->stop_info.stack_ptr,
26155 (AO_t)GC_approx_sp());
26156#endif
26157}
26158STATIC void GC_suspend_handler_inner(ptr_t dummy GC_ATTR_UNUSED,
26159 void * context GC_ATTR_UNUSED)
26160{
26161 pthread_t self = pthread_self();
26162 GC_thread me;
26163 IF_CANCEL(int cancel_state;)
26164 AO_t my_stop_count = ao_load_acquire_async(&GC_stop_count);
26165 DISABLE_CANCEL(cancel_state);
26166#ifdef DEBUG_THREADS
26167 GC_log_printf("Suspending %p\n", (void *)self);
26168#endif
26169 GC_ASSERT(((word)my_stop_count & THREAD_RESTARTED) == 0);
26170 me = GC_lookup_thread_async(self);
26171#ifdef GC_ENABLE_SUSPEND_THREAD
26172 if (ao_load_async(&me->suspended_ext)) {
26173 GC_store_stack_ptr(me);
26174 sem_post(&GC_suspend_ack_sem);
26175 suspend_self_inner(me);
26176#ifdef DEBUG_THREADS
26177 GC_log_printf("Continuing %p on GC_resume_thread\n", (void *)self);
26178#endif
26179 RESTORE_CANCEL(cancel_state);
26180 return;
26181 }
26182#endif
26183 if (((word)me->stop_info.last_stop_count & ~(word)THREAD_RESTARTED)
26184 == (word)my_stop_count) {
26185 if (!GC_retry_signals) {
26186 WARN("Duplicate suspend signal in thread %p\n", self);
26187 }
26188 RESTORE_CANCEL(cancel_state);
26189 return;
26190 }
26191 GC_store_stack_ptr(me);
26192#ifdef THREAD_SANITIZER
26193 {
26194 sigset_t set;
26195 sigemptyset(&set);
26196 GC_ASSERT(GC_sig_suspend != SIGNAL_UNSET);
26197 GC_ASSERT(GC_sig_thr_restart != SIGNAL_UNSET);
26198 sigaddset(&set, GC_sig_suspend);
26199 sigaddset(&set, GC_sig_thr_restart);
26200 if (pthread_sigmask(SIG_UNBLOCK, &set, NULL) != 0)
26201 ABORT("pthread_sigmask failed in suspend handler");
26202 }
26203#endif
26204 sem_post(&GC_suspend_ack_sem);
26205 ao_store_release_async(&me->stop_info.last_stop_count, my_stop_count);
26206 do {
26207 sigsuspend (&suspend_handler_mask);
26208 } while (ao_load_acquire_async(&GC_world_is_stopped)
26209 && ao_load_async(&GC_stop_count) == my_stop_count);
26210#ifdef DEBUG_THREADS
26211 GC_log_printf("Continuing %p\n", (void *)self);
26212#endif
26213#ifndef GC_NETBSD_THREADS_WORKAROUND
26214 if (GC_retry_signals)
26215#endif
26216 {
26217 sem_post(&GC_suspend_ack_sem);
26218#ifdef GC_NETBSD_THREADS_WORKAROUND
26219 if (GC_retry_signals)
26220#endif
26221 {
26222 ao_store_release_async(&me->stop_info.last_stop_count,
26223 (AO_t)((word)my_stop_count | THREAD_RESTARTED));
26224 }
26225 }
26226 RESTORE_CANCEL(cancel_state);
26227}
26228static void suspend_restart_barrier(int n_live_threads)
26229{
26230 int i;
26231 for (i = 0; i < n_live_threads; i++) {
26232 while (0 != sem_wait(&GC_suspend_ack_sem)) {
26233 if (errno != EINTR)
26234 ABORT("sem_wait failed");
26235 }
26236 }
26237#ifdef GC_ASSERTIONS
26238 sem_getvalue(&GC_suspend_ack_sem, &i);
26239 GC_ASSERT(0 == i);
26240#endif
26241}
26242static int resend_lost_signals(int n_live_threads,
26243 int (*suspend_restart_all)(void))
26244{
26245#define WAIT_UNIT 3000
26246#define RETRY_INTERVAL 100000
26247 if (n_live_threads > 0) {
26248 unsigned long wait_usecs = 0;
26249 for (;;) {
26250 int ack_count;
26251 sem_getvalue(&GC_suspend_ack_sem, &ack_count);
26252 if (ack_count == n_live_threads)
26253 break;
26254 if (wait_usecs > RETRY_INTERVAL) {
26255 int newly_sent = suspend_restart_all();
26256 GC_COND_LOG_PRINTF("Resent %d signals after timeout\n", newly_sent);
26257 sem_getvalue(&GC_suspend_ack_sem, &ack_count);
26258 if (newly_sent < n_live_threads - ack_count) {
26259 WARN("Lost some threads while stopping or starting world?!\n", 0);
26260 n_live_threads = ack_count + newly_sent;
26261 }
26262 wait_usecs = 0;
26263 }
26264#ifdef LINT2
26265#undef WAIT_UNIT
26266#define WAIT_UNIT 1
26267 sched_yield();
26268#elif defined(CPPCHECK)
26269 {
26270 struct timespec ts;
26271 ts.tv_sec = 0;
26272 ts.tv_nsec = WAIT_UNIT * 1000;
26273 (void)nanosleep(&ts, NULL);
26274 }
26275#else
26276 usleep(WAIT_UNIT);
26277#endif
26278 wait_usecs += WAIT_UNIT;
26279 }
26280 }
26281 return n_live_threads;
26282}
26283#ifdef HAVE_CLOCK_GETTIME
26284#define TS_NSEC_ADD(ts, ns) \
26285 (ts.tv_nsec += (ns), \
26286 (void)(ts.tv_nsec >= 1000000L*1000 ? \
26287 (ts.tv_nsec -= 1000000L*1000, ts.tv_sec++, 0) : 0))
26288#endif
26289static void resend_lost_signals_retry(int n_live_threads,
26290 int (*suspend_restart_all)(void))
26291{
26292#if defined(HAVE_CLOCK_GETTIME) && !defined(DONT_TIMEDWAIT_ACK_SEM)
26293#define TIMEOUT_BEFORE_RESEND 10000
26294 int i;
26295 struct timespec ts;
26296 if (n_live_threads > 0 && clock_gettime(CLOCK_REALTIME, &ts) == 0) {
26297 TS_NSEC_ADD(ts, TIMEOUT_BEFORE_RESEND * 1000);
26298 for (i = 0; i < n_live_threads; i++) {
26299 if (0 != sem_timedwait(&GC_suspend_ack_sem, &ts))
26300 break;
26301 }
26302 n_live_threads -= i;
26303 }
26304#endif
26305 n_live_threads = resend_lost_signals(n_live_threads, suspend_restart_all);
26306 suspend_restart_barrier(n_live_threads);
26307}
26308STATIC void GC_restart_handler(int sig)
26309{
26310#if defined(DEBUG_THREADS)
26311 int old_errno = errno;
26312#endif
26313 if (sig != GC_sig_thr_restart)
26314 ABORT("Bad signal in restart handler");
26315#ifdef DEBUG_THREADS
26316 GC_log_printf("In GC_restart_handler for %p\n", (void *)pthread_self());
26317 errno = old_errno;
26318#endif
26319}
26320#ifdef USE_TKILL_ON_ANDROID
26321 EXTERN_C_BEGIN
26322 extern int tkill(pid_t tid, int sig);
26323 EXTERN_C_END
26324 static int android_thread_kill(pid_t tid, int sig)
26325 {
26326 int ret;
26327 int old_errno = errno;
26328 ret = tkill(tid, sig);
26329 if (ret < 0) {
26330 ret = errno;
26331 errno = old_errno;
26332 }
26333 return ret;
26334 }
26335#define THREAD_SYSTEM_ID(t) (t)->kernel_id
26336#define RAISE_SIGNAL(t, sig) android_thread_kill(THREAD_SYSTEM_ID(t), sig)
26337#else
26338#define THREAD_SYSTEM_ID(t) (t)->id
26339#define RAISE_SIGNAL(t, sig) pthread_kill(THREAD_SYSTEM_ID(t), sig)
26340#endif
26341#ifdef GC_ENABLE_SUSPEND_THREAD
26342#include <sys/time.h>
26343 STATIC void GC_brief_async_signal_safe_sleep(void)
26344 {
26345 struct timeval tv;
26346 tv.tv_sec = 0;
26347#if defined(GC_TIME_LIMIT) && !defined(CPPCHECK)
26348 tv.tv_usec = 1000 * GC_TIME_LIMIT / 2;
26349#else
26350 tv.tv_usec = 1000 * 50 / 2;
26351#endif
26352 (void)select(0, 0, 0, 0, &tv);
26353 }
26354 static void *GC_CALLBACK suspend_self_inner(void *client_data) {
26355 GC_thread me = (GC_thread)client_data;
26356 while (ao_load_acquire_async(&me->suspended_ext)) {
26357 GC_brief_async_signal_safe_sleep();
26358 }
26359 return NULL;
26360 }
26361 GC_API void GC_CALL GC_suspend_thread(GC_SUSPEND_THREAD_ID thread) {
26362 GC_thread t;
26363 IF_CANCEL(int cancel_state;)
26364 DCL_LOCK_STATE;
26365 LOCK();
26366 t = GC_lookup_thread((pthread_t)thread);
26367 if (t == NULL || t -> suspended_ext) {
26368 UNLOCK();
26369 return;
26370 }
26371 AO_store_release(&t->suspended_ext, TRUE);
26372 if (THREAD_EQUAL((pthread_t)thread, pthread_self())) {
26373 UNLOCK();
26374 (void)GC_do_blocking(suspend_self_inner, t);
26375 return;
26376 }
26377 if ((t -> flags & FINISHED) != 0) {
26378 UNLOCK();
26379 return;
26380 }
26381 DISABLE_CANCEL(cancel_state);
26382#ifdef PARALLEL_MARK
26383 if (GC_parallel)
26384 GC_wait_for_reclaim();
26385#endif
26386 if (GC_manual_vdb) {
26387 GC_acquire_dirty_lock();
26388 }
26389 switch (RAISE_SIGNAL(t, GC_sig_suspend)) {
26390 case 0:
26391 break;
26392 default:
26393 ABORT("pthread_kill failed");
26394 }
26395 GC_ASSERT(GC_thr_initialized);
26396 while (sem_wait(&GC_suspend_ack_sem) != 0) {
26397 if (errno != EINTR)
26398 ABORT("sem_wait for handler failed (suspend_self)");
26399 }
26400 if (GC_manual_vdb)
26401 GC_release_dirty_lock();
26402 RESTORE_CANCEL(cancel_state);
26403 UNLOCK();
26404 }
26405 GC_API void GC_CALL GC_resume_thread(GC_SUSPEND_THREAD_ID thread) {
26406 GC_thread t;
26407 DCL_LOCK_STATE;
26408 LOCK();
26409 t = GC_lookup_thread((pthread_t)thread);
26410 if (t != NULL)
26411 AO_store(&t->suspended_ext, FALSE);
26412 UNLOCK();
26413 }
26414 GC_API int GC_CALL GC_is_thread_suspended(GC_SUSPEND_THREAD_ID thread) {
26415 GC_thread t;
26416 int is_suspended = 0;
26417 DCL_LOCK_STATE;
26418 LOCK();
26419 t = GC_lookup_thread((pthread_t)thread);
26420 if (t != NULL && t -> suspended_ext)
26421 is_suspended = (int)TRUE;
26422 UNLOCK();
26423 return is_suspended;
26424 }
26425#endif
26426#undef ao_load_acquire_async
26427#undef ao_load_async
26428#undef ao_store_async
26429#undef ao_store_release_async
26430#endif
26431#ifdef IA64
26432#define IF_IA64(x) x
26433#else
26434#define IF_IA64(x)
26435#endif
26436GC_INNER void GC_push_all_stacks(void)
26437{
26438 GC_bool found_me = FALSE;
26439 size_t nthreads = 0;
26440 int i;
26441 GC_thread p;
26442 ptr_t lo, hi;
26443 IF_IA64(ptr_t bs_lo; ptr_t bs_hi;)
26444 struct GC_traced_stack_sect_s *traced_stack_sect;
26445 pthread_t self = pthread_self();
26446 word total_size = 0;
26447 if (!EXPECT(GC_thr_initialized, TRUE))
26448 GC_thr_init();
26449#ifdef DEBUG_THREADS
26450 GC_log_printf("Pushing stacks from thread %p\n", (void *)self);
26451#endif
26452 for (i = 0; i < THREAD_TABLE_SZ; i++) {
26453 for (p = GC_threads[i]; p != 0; p = p -> next) {
26454 if (p -> flags & FINISHED) continue;
26455 ++nthreads;
26456 traced_stack_sect = p -> traced_stack_sect;
26457 if (THREAD_EQUAL(p -> id, self)) {
26458 GC_ASSERT(!p->thread_blocked);
26459#ifdef SPARC
26460 lo = (ptr_t)GC_save_regs_in_stack();
26461#else
26462 lo = GC_approx_sp();
26463#endif
26464 found_me = TRUE;
26465 IF_IA64(bs_hi = (ptr_t)GC_save_regs_in_stack();)
26466 } else {
26467 lo = (ptr_t)AO_load((volatile AO_t *)&p->stop_info.stack_ptr);
26468 IF_IA64(bs_hi = p -> backing_store_ptr;)
26469 if (traced_stack_sect != NULL
26470 && traced_stack_sect->saved_stack_ptr == lo) {
26471 traced_stack_sect = traced_stack_sect->prev;
26472 }
26473 }
26474 if ((p -> flags & MAIN_THREAD) == 0) {
26475 hi = p -> stack_end;
26476 IF_IA64(bs_lo = p -> backing_store_end);
26477 } else {
26478 hi = GC_stackbottom;
26479 IF_IA64(bs_lo = BACKING_STORE_BASE;)
26480 }
26481#ifdef DEBUG_THREADS
26482 GC_log_printf("Stack for thread %p is [%p,%p)\n",
26483 (void *)p->id, (void *)lo, (void *)hi);
26484#endif
26485 if (0 == lo) ABORT("GC_push_all_stacks: sp not set!");
26486 if (p->altstack != NULL && (word)p->altstack <= (word)lo
26487 && (word)lo <= (word)p->altstack + p->altstack_size) {
26488 hi = p->altstack + p->altstack_size;
26489 }
26490 GC_push_all_stack_sections(lo, hi, traced_stack_sect);
26491#ifdef STACK_GROWS_UP
26492 total_size += lo - hi;
26493#else
26494 total_size += hi - lo;
26495#endif
26496#ifdef NACL
26497 GC_push_all_stack((ptr_t)p -> stop_info.reg_storage,
26498 (ptr_t)(p -> stop_info.reg_storage + NACL_GC_REG_STORAGE_SIZE));
26499 total_size += NACL_GC_REG_STORAGE_SIZE * sizeof(ptr_t);
26500#endif
26501#ifdef IA64
26502#ifdef DEBUG_THREADS
26503 GC_log_printf("Reg stack for thread %p is [%p,%p)\n",
26504 (void *)p->id, (void *)bs_lo, (void *)bs_hi);
26505#endif
26506 GC_push_all_register_sections(bs_lo, bs_hi,
26507 THREAD_EQUAL(p -> id, self),
26508 traced_stack_sect);
26509 total_size += bs_hi - bs_lo;
26510#endif
26511 }
26512 }
26513 GC_VERBOSE_LOG_PRINTF("Pushed %d thread stacks\n", (int)nthreads);
26514 if (!found_me && !GC_in_thread_creation)
26515 ABORT("Collecting from unknown thread");
26516 GC_total_stacksize = total_size;
26517}
26518#ifdef DEBUG_THREADS
26519 pthread_t GC_stopping_thread;
26520 int GC_stopping_pid = 0;
26521#endif
26522STATIC int GC_suspend_all(void)
26523{
26524 int n_live_threads = 0;
26525 int i;
26526#ifndef NACL
26527 GC_thread p;
26528#ifndef GC_OPENBSD_UTHREADS
26529 int result;
26530#endif
26531 pthread_t self = pthread_self();
26532 for (i = 0; i < THREAD_TABLE_SZ; i++) {
26533 for (p = GC_threads[i]; p != 0; p = p -> next) {
26534 if (!THREAD_EQUAL(p -> id, self)) {
26535 if ((p -> flags & FINISHED) != 0) continue;
26536 if (p -> thread_blocked) continue;
26537#ifndef GC_OPENBSD_UTHREADS
26538#ifdef GC_ENABLE_SUSPEND_THREAD
26539 if (p -> suspended_ext) continue;
26540#endif
26541 if (AO_load(&p->stop_info.last_stop_count) == GC_stop_count)
26542 continue;
26543 n_live_threads++;
26544#endif
26545#ifdef DEBUG_THREADS
26546 GC_log_printf("Sending suspend signal to %p\n", (void *)p->id);
26547#endif
26548#ifdef GC_OPENBSD_UTHREADS
26549 {
26550 stack_t stack;
26551 GC_acquire_dirty_lock();
26552 if (pthread_suspend_np(p -> id) != 0)
26553 ABORT("pthread_suspend_np failed");
26554 GC_release_dirty_lock();
26555 if (pthread_stackseg_np(p->id, &stack))
26556 ABORT("pthread_stackseg_np failed");
26557 p -> stop_info.stack_ptr = (ptr_t)stack.ss_sp - stack.ss_size;
26558 if (GC_on_thread_event)
26559 GC_on_thread_event(GC_EVENT_THREAD_SUSPENDED,
26560 (void *)p->id);
26561 }
26562#else
26563 result = RAISE_SIGNAL(p, GC_sig_suspend);
26564 switch(result) {
26565 case ESRCH:
26566 n_live_threads--;
26567 break;
26568 case 0:
26569 if (GC_on_thread_event)
26570 GC_on_thread_event(GC_EVENT_THREAD_SUSPENDED,
26571 (void *)(word)THREAD_SYSTEM_ID(p));
26572 break;
26573 default:
26574 ABORT_ARG1("pthread_kill failed at suspend",
26575 ": errcode= %d", result);
26576 }
26577#endif
26578 }
26579 }
26580 }
26581#else
26582#ifndef NACL_PARK_WAIT_NANOSECONDS
26583#define NACL_PARK_WAIT_NANOSECONDS (100 * 1000)
26584#endif
26585#define NANOS_PER_SECOND (1000UL * 1000 * 1000)
26586 unsigned long num_sleeps = 0;
26587#ifdef DEBUG_THREADS
26588 GC_log_printf("pthread_stop_world: number of threads: %d\n",
26589 GC_nacl_num_gc_threads - 1);
26590#endif
26591 GC_nacl_thread_parker = pthread_self();
26592 GC_nacl_park_threads_now = 1;
26593 if (GC_manual_vdb)
26594 GC_acquire_dirty_lock();
26595 while (1) {
26596 int num_threads_parked = 0;
26597 struct timespec ts;
26598 int num_used = 0;
26599 for (i = 0; i < MAX_NACL_GC_THREADS
26600 && num_used < GC_nacl_num_gc_threads; i++) {
26601 if (GC_nacl_thread_used[i] == 1) {
26602 num_used++;
26603 if (GC_nacl_thread_parked[i] == 1) {
26604 num_threads_parked++;
26605 if (GC_on_thread_event)
26606 GC_on_thread_event(GC_EVENT_THREAD_SUSPENDED, (void *)(word)i);
26607 }
26608 }
26609 }
26610 if (num_threads_parked >= GC_nacl_num_gc_threads - 1)
26611 break;
26612 ts.tv_sec = 0;
26613 ts.tv_nsec = NACL_PARK_WAIT_NANOSECONDS;
26614#ifdef DEBUG_THREADS
26615 GC_log_printf("Sleep waiting for %d threads to park...\n",
26616 GC_nacl_num_gc_threads - num_threads_parked - 1);
26617#endif
26618 nanosleep(&ts, 0);
26619 if (++num_sleeps > NANOS_PER_SECOND / NACL_PARK_WAIT_NANOSECONDS) {
26620 WARN("GC appears stalled waiting for %" WARN_PRIdPTR
26621 " threads to park...\n",
26622 GC_nacl_num_gc_threads - num_threads_parked - 1);
26623 num_sleeps = 0;
26624 }
26625 }
26626 if (GC_manual_vdb)
26627 GC_release_dirty_lock();
26628#endif
26629 return n_live_threads;
26630}
26631GC_INNER void GC_stop_world(void)
26632{
26633#if !defined(GC_OPENBSD_UTHREADS) && !defined(NACL)
26634 int n_live_threads;
26635#endif
26636 GC_ASSERT(I_HOLD_LOCK());
26637#ifdef DEBUG_THREADS
26638 GC_stopping_thread = pthread_self();
26639 GC_stopping_pid = getpid();
26640 GC_log_printf("Stopping the world from %p\n", (void *)GC_stopping_thread);
26641#endif
26642#ifdef PARALLEL_MARK
26643 if (GC_parallel) {
26644 GC_acquire_mark_lock();
26645 GC_ASSERT(GC_fl_builder_count == 0);
26646 }
26647#endif
26648#if defined(GC_OPENBSD_UTHREADS) || defined(NACL)
26649 (void)GC_suspend_all();
26650#else
26651 AO_store(&GC_stop_count,
26652 (AO_t)((word)GC_stop_count + (THREAD_RESTARTED+1)));
26653 if (GC_manual_vdb) {
26654 GC_acquire_dirty_lock();
26655 }
26656 AO_store_release(&GC_world_is_stopped, TRUE);
26657 n_live_threads = GC_suspend_all();
26658 if (GC_retry_signals) {
26659 resend_lost_signals_retry(n_live_threads, GC_suspend_all);
26660 } else {
26661 suspend_restart_barrier(n_live_threads);
26662 }
26663 if (GC_manual_vdb)
26664 GC_release_dirty_lock();
26665#endif
26666#ifdef PARALLEL_MARK
26667 if (GC_parallel)
26668 GC_release_mark_lock();
26669#endif
26670#ifdef DEBUG_THREADS
26671 GC_log_printf("World stopped from %p\n", (void *)pthread_self());
26672 GC_stopping_thread = 0;
26673#endif
26674}
26675#ifdef NACL
26676#if defined(__x86_64__)
26677#define NACL_STORE_REGS() \
26678 do { \
26679 __asm__ __volatile__ ("push %rbx"); \
26680 __asm__ __volatile__ ("push %rbp"); \
26681 __asm__ __volatile__ ("push %r12"); \
26682 __asm__ __volatile__ ("push %r13"); \
26683 __asm__ __volatile__ ("push %r14"); \
26684 __asm__ __volatile__ ("push %r15"); \
26685 __asm__ __volatile__ ("mov %%esp, %0" \
26686 : "=m" (GC_nacl_gc_thread_self->stop_info.stack_ptr)); \
26687 BCOPY(GC_nacl_gc_thread_self->stop_info.stack_ptr, \
26688 GC_nacl_gc_thread_self->stop_info.reg_storage, \
26689 NACL_GC_REG_STORAGE_SIZE * sizeof(ptr_t)); \
26690 __asm__ __volatile__ ("naclasp $48, %r15"); \
26691 } while (0)
26692#elif defined(__i386__)
26693#define NACL_STORE_REGS() \
26694 do { \
26695 __asm__ __volatile__ ("push %ebx"); \
26696 __asm__ __volatile__ ("push %ebp"); \
26697 __asm__ __volatile__ ("push %esi"); \
26698 __asm__ __volatile__ ("push %edi"); \
26699 __asm__ __volatile__ ("mov %%esp, %0" \
26700 : "=m" (GC_nacl_gc_thread_self->stop_info.stack_ptr)); \
26701 BCOPY(GC_nacl_gc_thread_self->stop_info.stack_ptr, \
26702 GC_nacl_gc_thread_self->stop_info.reg_storage, \
26703 NACL_GC_REG_STORAGE_SIZE * sizeof(ptr_t));\
26704 __asm__ __volatile__ ("add $16, %esp"); \
26705 } while (0)
26706#elif defined(__arm__)
26707#define NACL_STORE_REGS() \
26708 do { \
26709 __asm__ __volatile__ ("push {r4-r8,r10-r12,lr}"); \
26710 __asm__ __volatile__ ("mov r0, %0" \
26711 : : "r" (&GC_nacl_gc_thread_self->stop_info.stack_ptr)); \
26712 __asm__ __volatile__ ("bic r0, r0, #0xc0000000"); \
26713 __asm__ __volatile__ ("str sp, [r0]"); \
26714 BCOPY(GC_nacl_gc_thread_self->stop_info.stack_ptr, \
26715 GC_nacl_gc_thread_self->stop_info.reg_storage, \
26716 NACL_GC_REG_STORAGE_SIZE * sizeof(ptr_t)); \
26717 __asm__ __volatile__ ("add sp, sp, #40"); \
26718 __asm__ __volatile__ ("bic sp, sp, #0xc0000000"); \
26719 } while (0)
26720#else
26721#error TODO Please port NACL_STORE_REGS
26722#endif
26723 GC_API_OSCALL void nacl_pre_syscall_hook(void)
26724 {
26725 if (GC_nacl_thread_idx != -1) {
26726 NACL_STORE_REGS();
26727 GC_nacl_gc_thread_self->stop_info.stack_ptr = GC_approx_sp();
26728 GC_nacl_thread_parked[GC_nacl_thread_idx] = 1;
26729 }
26730 }
26731 GC_API_OSCALL void __nacl_suspend_thread_if_needed(void)
26732 {
26733 if (GC_nacl_park_threads_now) {
26734 pthread_t self = pthread_self();
26735 if (GC_nacl_thread_parker == self)
26736 return;
26737 if (GC_nacl_thread_idx < 0)
26738 return;
26739 if (!GC_nacl_thread_parked[GC_nacl_thread_idx]) {
26740 NACL_STORE_REGS();
26741 GC_nacl_gc_thread_self->stop_info.stack_ptr = GC_approx_sp();
26742 }
26743 GC_nacl_thread_parked[GC_nacl_thread_idx] = 1;
26744 while (GC_nacl_park_threads_now) {
26745 }
26746 GC_nacl_thread_parked[GC_nacl_thread_idx] = 0;
26747 BZERO(GC_nacl_gc_thread_self->stop_info.reg_storage,
26748 NACL_GC_REG_STORAGE_SIZE * sizeof(ptr_t));
26749 }
26750 }
26751 GC_API_OSCALL void nacl_post_syscall_hook(void)
26752 {
26753 __nacl_suspend_thread_if_needed();
26754 if (GC_nacl_thread_idx != -1) {
26755 GC_nacl_thread_parked[GC_nacl_thread_idx] = 0;
26756 }
26757 }
26758 STATIC GC_bool GC_nacl_thread_parking_inited = FALSE;
26759 STATIC pthread_mutex_t GC_nacl_thread_alloc_lock = PTHREAD_MUTEX_INITIALIZER;
26760 struct nacl_irt_blockhook {
26761 int (*register_block_hooks)(void (*pre)(void), void (*post)(void));
26762 };
26763 EXTERN_C_BEGIN
26764 extern size_t nacl_interface_query(const char *interface_ident,
26765 void *table, size_t tablesize);
26766 EXTERN_C_END
26767 GC_INNER void GC_nacl_initialize_gc_thread(void)
26768 {
26769 int i;
26770 static struct nacl_irt_blockhook gc_hook;
26771 pthread_mutex_lock(&GC_nacl_thread_alloc_lock);
26772 if (!EXPECT(GC_nacl_thread_parking_inited, TRUE)) {
26773 BZERO(GC_nacl_thread_parked, sizeof(GC_nacl_thread_parked));
26774 BZERO(GC_nacl_thread_used, sizeof(GC_nacl_thread_used));
26775 nacl_interface_query("nacl-irt-blockhook-0.1",
26776 &gc_hook, sizeof(gc_hook));
26777 gc_hook.register_block_hooks(nacl_pre_syscall_hook,
26778 nacl_post_syscall_hook);
26779 GC_nacl_thread_parking_inited = TRUE;
26780 }
26781 GC_ASSERT(GC_nacl_num_gc_threads <= MAX_NACL_GC_THREADS);
26782 for (i = 0; i < MAX_NACL_GC_THREADS; i++) {
26783 if (GC_nacl_thread_used[i] == 0) {
26784 GC_nacl_thread_used[i] = 1;
26785 GC_nacl_thread_idx = i;
26786 GC_nacl_num_gc_threads++;
26787 break;
26788 }
26789 }
26790 pthread_mutex_unlock(&GC_nacl_thread_alloc_lock);
26791 }
26792 GC_INNER void GC_nacl_shutdown_gc_thread(void)
26793 {
26794 pthread_mutex_lock(&GC_nacl_thread_alloc_lock);
26795 GC_ASSERT(GC_nacl_thread_idx >= 0);
26796 GC_ASSERT(GC_nacl_thread_idx < MAX_NACL_GC_THREADS);
26797 GC_ASSERT(GC_nacl_thread_used[GC_nacl_thread_idx] != 0);
26798 GC_nacl_thread_used[GC_nacl_thread_idx] = 0;
26799 GC_nacl_thread_idx = -1;
26800 GC_nacl_num_gc_threads--;
26801 pthread_mutex_unlock(&GC_nacl_thread_alloc_lock);
26802 }
26803#else
26804 STATIC int GC_restart_all(void)
26805 {
26806 int n_live_threads = 0;
26807 int i;
26808 pthread_t self = pthread_self();
26809 GC_thread p;
26810#ifndef GC_OPENBSD_UTHREADS
26811 int result;
26812#endif
26813 for (i = 0; i < THREAD_TABLE_SZ; i++) {
26814 for (p = GC_threads[i]; p != NULL; p = p -> next) {
26815 if (!THREAD_EQUAL(p -> id, self)) {
26816 if ((p -> flags & FINISHED) != 0) continue;
26817 if (p -> thread_blocked) continue;
26818#ifndef GC_OPENBSD_UTHREADS
26819#ifdef GC_ENABLE_SUSPEND_THREAD
26820 if (p -> suspended_ext) continue;
26821#endif
26822 if (GC_retry_signals
26823 && AO_load(&p->stop_info.last_stop_count)
26824 == (AO_t)((word)GC_stop_count | THREAD_RESTARTED))
26825 continue;
26826 n_live_threads++;
26827#endif
26828#ifdef DEBUG_THREADS
26829 GC_log_printf("Sending restart signal to %p\n", (void *)p->id);
26830#endif
26831#ifdef GC_OPENBSD_UTHREADS
26832 if (pthread_resume_np(p -> id) != 0)
26833 ABORT("pthread_resume_np failed");
26834 if (GC_on_thread_event)
26835 GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED, (void *)p->id);
26836#else
26837 result = RAISE_SIGNAL(p, GC_sig_thr_restart);
26838 switch(result) {
26839 case ESRCH:
26840 n_live_threads--;
26841 break;
26842 case 0:
26843 if (GC_on_thread_event)
26844 GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED,
26845 (void *)(word)THREAD_SYSTEM_ID(p));
26846 break;
26847 default:
26848 ABORT_ARG1("pthread_kill failed at resume",
26849 ": errcode= %d", result);
26850 }
26851#endif
26852 }
26853 }
26854 }
26855 return n_live_threads;
26856 }
26857#endif
26858GC_INNER void GC_start_world(void)
26859{
26860#ifndef NACL
26861 int n_live_threads;
26862 GC_ASSERT(I_HOLD_LOCK());
26863#ifdef DEBUG_THREADS
26864 GC_log_printf("World starting\n");
26865#endif
26866#ifndef GC_OPENBSD_UTHREADS
26867 AO_store_release(&GC_world_is_stopped, FALSE);
26868#endif
26869 n_live_threads = GC_restart_all();
26870#ifdef GC_OPENBSD_UTHREADS
26871 (void)n_live_threads;
26872#else
26873 if (GC_retry_signals) {
26874 resend_lost_signals_retry(n_live_threads, GC_restart_all);
26875 }
26876#ifdef GC_NETBSD_THREADS_WORKAROUND
26877 else {
26878 suspend_restart_barrier(n_live_threads);
26879 }
26880#endif
26881#endif
26882#ifdef DEBUG_THREADS
26883 GC_log_printf("World started\n");
26884#endif
26885#else
26886#ifdef DEBUG_THREADS
26887 GC_log_printf("World starting...\n");
26888#endif
26889 GC_nacl_park_threads_now = 0;
26890 if (GC_on_thread_event)
26891 GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED, NULL);
26892#endif
26893}
26894GC_INNER void GC_stop_init(void)
26895{
26896#if !defined(GC_OPENBSD_UTHREADS) && !defined(NACL)
26897 struct sigaction act;
26898 char *str;
26899 if (SIGNAL_UNSET == GC_sig_suspend)
26900 GC_sig_suspend = SIG_SUSPEND;
26901 if (SIGNAL_UNSET == GC_sig_thr_restart)
26902 GC_sig_thr_restart = SIG_THR_RESTART;
26903 if (GC_sig_suspend == GC_sig_thr_restart)
26904 ABORT("Cannot use same signal for thread suspend and resume");
26905 if (sem_init(&GC_suspend_ack_sem, GC_SEM_INIT_PSHARED, 0) != 0)
26906 ABORT("sem_init failed");
26907#ifdef SA_RESTART
26908 act.sa_flags = SA_RESTART
26909#else
26910 act.sa_flags = 0
26911#endif
26912#ifndef NO_SA_SIGACTION
26913 | SA_SIGINFO
26914#endif
26915 ;
26916 if (sigfillset(&act.sa_mask) != 0) {
26917 ABORT("sigfillset failed");
26918 }
26919#ifdef GC_RTEMS_PTHREADS
26920 if(sigprocmask(SIG_UNBLOCK, &act.sa_mask, NULL) != 0) {
26921 ABORT("sigprocmask failed");
26922 }
26923#endif
26924 GC_remove_allowed_signals(&act.sa_mask);
26925#ifndef NO_SA_SIGACTION
26926 act.sa_sigaction = GC_suspend_handler;
26927#else
26928 act.sa_handler = GC_suspend_handler;
26929#endif
26930 if (sigaction(GC_sig_suspend, &act, NULL) != 0) {
26931 ABORT("Cannot set SIG_SUSPEND handler");
26932 }
26933#ifndef NO_SA_SIGACTION
26934 act.sa_flags &= ~SA_SIGINFO;
26935#endif
26936 act.sa_handler = GC_restart_handler;
26937 if (sigaction(GC_sig_thr_restart, &act, NULL) != 0) {
26938 ABORT("Cannot set SIG_THR_RESTART handler");
26939 }
26940 if (sigfillset(&suspend_handler_mask) != 0) ABORT("sigfillset failed");
26941 GC_remove_allowed_signals(&suspend_handler_mask);
26942 if (sigdelset(&suspend_handler_mask, GC_sig_thr_restart) != 0)
26943 ABORT("sigdelset failed");
26944 str = GETENV("GC_RETRY_SIGNALS");
26945 if (str != NULL) {
26946 if (*str == '0' && *(str + 1) == '\0') {
26947 GC_retry_signals = FALSE;
26948 } else {
26949 GC_retry_signals = TRUE;
26950 }
26951 }
26952 if (GC_retry_signals) {
26953 GC_COND_LOG_PRINTF(
26954 "Will retry suspend and restart signals if necessary\n");
26955 }
26956#ifndef NO_SIGNALS_UNBLOCK_IN_MAIN
26957 GC_unblock_gc_signals();
26958#endif
26959#endif
26960}
26961#endif
26962#endif
26963#if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS)
26964#include <stdlib.h>
26965#include <pthread.h>
26966#include <sched.h>
26967#include <time.h>
26968#include <errno.h>
26969#include <unistd.h>
26970#if !defined(SN_TARGET_ORBIS) && !defined(SN_TARGET_PSP2)
26971#if !defined(GC_RTEMS_PTHREADS)
26972#include <sys/mman.h>
26973#endif
26974#include <sys/time.h>
26975#include <sys/types.h>
26976#include <sys/stat.h>
26977#include <fcntl.h>
26978#endif
26979#include <signal.h>
26980#if defined(GC_DARWIN_THREADS)
26981#ifndef GC_DARWIN_SEMAPHORE_H
26982#define GC_DARWIN_SEMAPHORE_H
26983#if !defined(GC_DARWIN_THREADS)
26984#error darwin_semaphore.h included with GC_DARWIN_THREADS not defined
26985#endif
26986#ifdef __cplusplus
26987 extern "C" {
26988#endif
26989typedef struct {
26990 pthread_mutex_t mutex;
26991 pthread_cond_t cond;
26992 int value;
26993} sem_t;
26994GC_INLINE int sem_init(sem_t *sem, int pshared, int value) {
26995 if (pshared != 0) {
26996 errno = EPERM;
26997 return -1;
26998 }
26999 sem->value = value;
27000 if (pthread_mutex_init(&sem->mutex, NULL) != 0)
27001 return -1;
27002 if (pthread_cond_init(&sem->cond, NULL) != 0) {
27003 (void)pthread_mutex_destroy(&sem->mutex);
27004 return -1;
27005 }
27006 return 0;
27007}
27008GC_INLINE int sem_post(sem_t *sem) {
27009 if (pthread_mutex_lock(&sem->mutex) != 0)
27010 return -1;
27011 sem->value++;
27012 if (pthread_cond_signal(&sem->cond) != 0) {
27013 (void)pthread_mutex_unlock(&sem->mutex);
27014 return -1;
27015 }
27016 return pthread_mutex_unlock(&sem->mutex) != 0 ? -1 : 0;
27017}
27018GC_INLINE int sem_wait(sem_t *sem) {
27019 if (pthread_mutex_lock(&sem->mutex) != 0)
27020 return -1;
27021 while (sem->value == 0) {
27022 if (pthread_cond_wait(&sem->cond, &sem->mutex) != 0) {
27023 (void)pthread_mutex_unlock(&sem->mutex);
27024 return -1;
27025 }
27026 }
27027 sem->value--;
27028 return pthread_mutex_unlock(&sem->mutex) != 0 ? -1 : 0;
27029}
27030GC_INLINE int sem_destroy(sem_t *sem) {
27031 return pthread_cond_destroy(&sem->cond) != 0
27032 || pthread_mutex_destroy(&sem->mutex) != 0 ? -1 : 0;
27033}
27034#ifdef __cplusplus
27035 }
27036#endif
27037#endif
27038#else
27039#include <semaphore.h>
27040#endif
27041#if defined(GC_DARWIN_THREADS) || defined(GC_FREEBSD_THREADS)
27042#include <sys/sysctl.h>
27043#endif
27044#if defined(GC_NETBSD_THREADS) || defined(GC_OPENBSD_THREADS)
27045#include <sys/param.h>
27046#include <sys/sysctl.h>
27047#endif
27048#if !defined(USE_SPIN_LOCK)
27049 GC_INNER pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
27050#endif
27051#ifdef GC_ASSERTIONS
27052 GC_INNER unsigned long GC_lock_holder = NO_THREAD;
27053#endif
27054#if defined(GC_DGUX386_THREADS)
27055#include <sys/dg_sys_info.h>
27056#include <sys/_int_psem.h>
27057 typedef unsigned int sem_t;
27058#endif
27059#undef pthread_create
27060#ifndef GC_NO_PTHREAD_SIGMASK
27061#undef pthread_sigmask
27062#endif
27063#ifndef GC_NO_PTHREAD_CANCEL
27064#undef pthread_cancel
27065#endif
27066#ifdef GC_HAVE_PTHREAD_EXIT
27067#undef pthread_exit
27068#endif
27069#undef pthread_join
27070#undef pthread_detach
27071#if defined(GC_OSF1_THREADS) && defined(_PTHREAD_USE_MANGLED_NAMES_) \
27072 && !defined(_PTHREAD_USE_PTDNAM_)
27073#define pthread_create __pthread_create
27074#define pthread_join __pthread_join
27075#define pthread_detach __pthread_detach
27076#ifndef GC_NO_PTHREAD_CANCEL
27077#define pthread_cancel __pthread_cancel
27078#endif
27079#ifdef GC_HAVE_PTHREAD_EXIT
27080#define pthread_exit __pthread_exit
27081#endif
27082#endif
27083#ifdef GC_USE_LD_WRAP
27084#define WRAP_FUNC(f) __wrap_##f
27085#define REAL_FUNC(f) __real_##f
27086 int REAL_FUNC(pthread_create)(pthread_t *,
27087 GC_PTHREAD_CREATE_CONST pthread_attr_t *,
27088 void *(*start_routine)(void *), void *);
27089 int REAL_FUNC(pthread_join)(pthread_t, void **);
27090 int REAL_FUNC(pthread_detach)(pthread_t);
27091#ifndef GC_NO_PTHREAD_SIGMASK
27092 int REAL_FUNC(pthread_sigmask)(int, const sigset_t *, sigset_t *);
27093#endif
27094#ifndef GC_NO_PTHREAD_CANCEL
27095 int REAL_FUNC(pthread_cancel)(pthread_t);
27096#endif
27097#ifdef GC_HAVE_PTHREAD_EXIT
27098 void REAL_FUNC(pthread_exit)(void *) GC_PTHREAD_EXIT_ATTRIBUTE;
27099#endif
27100#else
27101#ifdef GC_USE_DLOPEN_WRAP
27102#include <dlfcn.h>
27103#define WRAP_FUNC(f) f
27104#define REAL_FUNC(f) GC_real_##f
27105 typedef int (* GC_pthread_create_t)(pthread_t *,
27106 GC_PTHREAD_CREATE_CONST pthread_attr_t *,
27107 void * (*)(void *), void *);
27108 static GC_pthread_create_t REAL_FUNC(pthread_create);
27109#ifndef GC_NO_PTHREAD_SIGMASK
27110 typedef int (* GC_pthread_sigmask_t)(int, const sigset_t *,
27111 sigset_t *);
27112 static GC_pthread_sigmask_t REAL_FUNC(pthread_sigmask);
27113#endif
27114 typedef int (* GC_pthread_join_t)(pthread_t, void **);
27115 static GC_pthread_join_t REAL_FUNC(pthread_join);
27116 typedef int (* GC_pthread_detach_t)(pthread_t);
27117 static GC_pthread_detach_t REAL_FUNC(pthread_detach);
27118#ifndef GC_NO_PTHREAD_CANCEL
27119 typedef int (* GC_pthread_cancel_t)(pthread_t);
27120 static GC_pthread_cancel_t REAL_FUNC(pthread_cancel);
27121#endif
27122#ifdef GC_HAVE_PTHREAD_EXIT
27123 typedef void (* GC_pthread_exit_t)(void *) GC_PTHREAD_EXIT_ATTRIBUTE;
27124 static GC_pthread_exit_t REAL_FUNC(pthread_exit);
27125#endif
27126#else
27127#define WRAP_FUNC(f) GC_##f
27128#if !defined(GC_DGUX386_THREADS)
27129#define REAL_FUNC(f) f
27130#else
27131#define REAL_FUNC(f) __d10_##f
27132#endif
27133#endif
27134#endif
27135#if defined(GC_USE_LD_WRAP) || defined(GC_USE_DLOPEN_WRAP)
27136 GC_API int GC_pthread_create(pthread_t * t,
27137 GC_PTHREAD_CREATE_CONST pthread_attr_t *a,
27138 void * (* fn)(void *), void * arg)
27139 {
27140 return pthread_create(t, a, fn, arg);
27141 }
27142#ifndef GC_NO_PTHREAD_SIGMASK
27143 GC_API int GC_pthread_sigmask(int how, const sigset_t *mask,
27144 sigset_t *old)
27145 {
27146 return pthread_sigmask(how, mask, old);
27147 }
27148#endif
27149 GC_API int GC_pthread_join(pthread_t t, void **res)
27150 {
27151 return pthread_join(t, res);
27152 }
27153 GC_API int GC_pthread_detach(pthread_t t)
27154 {
27155 return pthread_detach(t);
27156 }
27157#ifndef GC_NO_PTHREAD_CANCEL
27158 GC_API int GC_pthread_cancel(pthread_t t)
27159 {
27160 return pthread_cancel(t);
27161 }
27162#endif
27163#ifdef GC_HAVE_PTHREAD_EXIT
27164 GC_API GC_PTHREAD_EXIT_ATTRIBUTE void GC_pthread_exit(void *retval)
27165 {
27166 pthread_exit(retval);
27167 }
27168#endif
27169#endif
27170#ifdef GC_USE_DLOPEN_WRAP
27171 STATIC GC_bool GC_syms_initialized = FALSE;
27172 STATIC void GC_init_real_syms(void)
27173 {
27174 void *dl_handle;
27175 if (GC_syms_initialized) return;
27176#ifdef RTLD_NEXT
27177 dl_handle = RTLD_NEXT;
27178#else
27179 dl_handle = dlopen("libpthread.so.0", RTLD_LAZY);
27180 if (NULL == dl_handle) {
27181 dl_handle = dlopen("libpthread.so", RTLD_LAZY);
27182 }
27183 if (NULL == dl_handle) ABORT("Couldn't open libpthread");
27184#endif
27185 REAL_FUNC(pthread_create) = (GC_pthread_create_t)(word)
27186 dlsym(dl_handle, "pthread_create");
27187#ifdef RTLD_NEXT
27188 if (REAL_FUNC(pthread_create) == 0)
27189 ABORT("pthread_create not found"
27190 " (probably -lgc is specified after -lpthread)");
27191#endif
27192#ifndef GC_NO_PTHREAD_SIGMASK
27193 REAL_FUNC(pthread_sigmask) = (GC_pthread_sigmask_t)(word)
27194 dlsym(dl_handle, "pthread_sigmask");
27195#endif
27196 REAL_FUNC(pthread_join) = (GC_pthread_join_t)(word)
27197 dlsym(dl_handle, "pthread_join");
27198 REAL_FUNC(pthread_detach) = (GC_pthread_detach_t)(word)
27199 dlsym(dl_handle, "pthread_detach");
27200#ifndef GC_NO_PTHREAD_CANCEL
27201 REAL_FUNC(pthread_cancel) = (GC_pthread_cancel_t)(word)
27202 dlsym(dl_handle, "pthread_cancel");
27203#endif
27204#ifdef GC_HAVE_PTHREAD_EXIT
27205 REAL_FUNC(pthread_exit) = (GC_pthread_exit_t)(word)
27206 dlsym(dl_handle, "pthread_exit");
27207#endif
27208 GC_syms_initialized = TRUE;
27209 }
27210#define INIT_REAL_SYMS() if (EXPECT(GC_syms_initialized, TRUE)) {} \
27211 else GC_init_real_syms()
27212#define ASSERT_SYMS_INITIALIZED() GC_ASSERT(GC_syms_initialized)
27213#else
27214#define INIT_REAL_SYMS() (void)0
27215#define ASSERT_SYMS_INITIALIZED() GC_ASSERT(parallel_initialized)
27216#endif
27217static GC_bool parallel_initialized = FALSE;
27218#ifndef GC_ALWAYS_MULTITHREADED
27219 GC_INNER GC_bool GC_need_to_lock = FALSE;
27220#endif
27221STATIC int GC_nprocs = 1;
27222#ifdef THREAD_LOCAL_ALLOC
27223 GC_INNER void GC_mark_thread_local_free_lists(void)
27224 {
27225 int i;
27226 GC_thread p;
27227 for (i = 0; i < THREAD_TABLE_SZ; ++i) {
27228 for (p = GC_threads[i]; 0 != p; p = p -> next) {
27229 if (!(p -> flags & FINISHED))
27230 GC_mark_thread_local_fls_for(&(p->tlfs));
27231 }
27232 }
27233 }
27234#if defined(GC_ASSERTIONS)
27235 void GC_check_tls(void)
27236 {
27237 int i;
27238 GC_thread p;
27239 for (i = 0; i < THREAD_TABLE_SZ; ++i) {
27240 for (p = GC_threads[i]; 0 != p; p = p -> next) {
27241 if (!(p -> flags & FINISHED))
27242 GC_check_tls_for(&(p->tlfs));
27243 }
27244 }
27245#if defined(USE_CUSTOM_SPECIFIC)
27246 if (GC_thread_key != 0)
27247 GC_check_tsd_marks(GC_thread_key);
27248#endif
27249 }
27250#endif
27251#endif
27252#ifndef MAX_MARKERS
27253#define MAX_MARKERS 16
27254#endif
27255#ifdef PARALLEL_MARK
27256static ptr_t marker_sp[MAX_MARKERS - 1] = {0};
27257#ifdef IA64
27258 static ptr_t marker_bsp[MAX_MARKERS - 1] = {0};
27259#endif
27260#if defined(GC_DARWIN_THREADS) && !defined(GC_NO_THREADS_DISCOVERY)
27261 static mach_port_t marker_mach_threads[MAX_MARKERS - 1] = {0};
27262 GC_INNER GC_bool GC_is_mach_marker(thread_act_t thread)
27263 {
27264 int i;
27265 for (i = 0; i < GC_markers_m1; i++) {
27266 if (marker_mach_threads[i] == thread)
27267 return TRUE;
27268 }
27269 return FALSE;
27270 }
27271#endif
27272#ifdef HAVE_PTHREAD_SETNAME_NP_WITH_TID_AND_ARG
27273 static void set_marker_thread_name(unsigned id)
27274 {
27275 int err = pthread_setname_np(pthread_self(), "GC-marker-%zu",
27276 (void*)(size_t)id);
27277 if (err != 0)
27278 WARN("pthread_setname_np failed, errno= %" WARN_PRIdPTR "\n", err);
27279 }
27280#elif defined(HAVE_PTHREAD_SETNAME_NP_WITH_TID) \
27281 || defined(HAVE_PTHREAD_SETNAME_NP_WITHOUT_TID)
27282 static void set_marker_thread_name(unsigned id)
27283 {
27284 char name_buf[16];
27285 int len = sizeof("GC-marker-") - 1;
27286 BCOPY("GC-marker-", name_buf, len);
27287 if (id >= 10)
27288 name_buf[len++] = (char)('0' + (id / 10) % 10);
27289 name_buf[len] = (char)('0' + id % 10);
27290 name_buf[len + 1] = '\0';
27291#ifdef HAVE_PTHREAD_SETNAME_NP_WITHOUT_TID
27292 (void)pthread_setname_np(name_buf);
27293#else
27294 if (pthread_setname_np(pthread_self(), name_buf) != 0)
27295 WARN("pthread_setname_np failed\n", 0);
27296#endif
27297 }
27298#else
27299#define set_marker_thread_name(id) (void)(id)
27300#endif
27301STATIC void * GC_mark_thread(void * id)
27302{
27303 word my_mark_no = 0;
27304 IF_CANCEL(int cancel_state;)
27305 if ((word)id == GC_WORD_MAX) return 0;
27306 DISABLE_CANCEL(cancel_state);
27307 set_marker_thread_name((unsigned)(word)id);
27308 marker_sp[(word)id] = GC_approx_sp();
27309#ifdef IA64
27310 marker_bsp[(word)id] = GC_save_regs_in_stack();
27311#endif
27312#if defined(GC_DARWIN_THREADS) && !defined(GC_NO_THREADS_DISCOVERY)
27313 marker_mach_threads[(word)id] = mach_thread_self();
27314#endif
27315 GC_acquire_mark_lock();
27316 if (0 == --GC_fl_builder_count)
27317 GC_notify_all_builder();
27318 for (;; ++my_mark_no) {
27319 if (my_mark_no < GC_mark_no || my_mark_no > GC_mark_no + 2) {
27320 my_mark_no = GC_mark_no;
27321 }
27322#ifdef DEBUG_THREADS
27323 GC_log_printf("Starting mark helper for mark number %lu\n",
27324 (unsigned long)my_mark_no);
27325#endif
27326 GC_help_marker(my_mark_no);
27327 }
27328}
27329STATIC pthread_t GC_mark_threads[MAX_MARKERS];
27330#ifdef CAN_HANDLE_FORK
27331 static int available_markers_m1 = 0;
27332 static pthread_cond_t mark_cv;
27333#else
27334#define available_markers_m1 GC_markers_m1
27335 static pthread_cond_t mark_cv = PTHREAD_COND_INITIALIZER;
27336#endif
27337GC_INNER void GC_start_mark_threads_inner(void)
27338{
27339 int i;
27340 pthread_attr_t attr;
27341#ifndef NO_MARKER_SPECIAL_SIGMASK
27342 sigset_t set, oldset;
27343#endif
27344 GC_ASSERT(I_DONT_HOLD_LOCK());
27345 if (available_markers_m1 <= 0) return;
27346#ifdef CAN_HANDLE_FORK
27347 if (GC_parallel) return;
27348 {
27349 pthread_cond_t mark_cv_local = PTHREAD_COND_INITIALIZER;
27350 BCOPY(&mark_cv_local, &mark_cv, sizeof(mark_cv));
27351 }
27352#endif
27353 GC_ASSERT(GC_fl_builder_count == 0);
27354 INIT_REAL_SYMS();
27355 if (0 != pthread_attr_init(&attr)) ABORT("pthread_attr_init failed");
27356 if (0 != pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))
27357 ABORT("pthread_attr_setdetachstate failed");
27358#ifdef DEFAULT_STACK_MAYBE_SMALL
27359 {
27360 size_t old_size;
27361 if (pthread_attr_getstacksize(&attr, &old_size) != 0)
27362 ABORT("pthread_attr_getstacksize failed");
27363 if (old_size < MIN_STACK_SIZE
27364 && old_size != 0 ) {
27365 if (pthread_attr_setstacksize(&attr, MIN_STACK_SIZE) != 0)
27366 ABORT("pthread_attr_setstacksize failed");
27367 }
27368 }
27369#endif
27370#ifndef NO_MARKER_SPECIAL_SIGMASK
27371 if (sigfillset(&set) != 0)
27372 ABORT("sigfillset failed");
27373#if !defined(GC_DARWIN_THREADS) && !defined(GC_OPENBSD_UTHREADS) \
27374 && !defined(NACL)
27375 if (sigdelset(&set, GC_get_suspend_signal()) != 0
27376 || sigdelset(&set, GC_get_thr_restart_signal()) != 0)
27377 ABORT("sigdelset failed");
27378#endif
27379 if (REAL_FUNC(pthread_sigmask)(SIG_BLOCK, &set, &oldset) < 0) {
27380 WARN("pthread_sigmask set failed, no markers started,"
27381 " errno= %" WARN_PRIdPTR "\n", errno);
27382 GC_markers_m1 = 0;
27383 (void)pthread_attr_destroy(&attr);
27384 return;
27385 }
27386#endif
27387#ifdef CAN_HANDLE_FORK
27388 GC_markers_m1 = available_markers_m1;
27389#endif
27390 for (i = 0; i < available_markers_m1; ++i) {
27391 if (0 != REAL_FUNC(pthread_create)(GC_mark_threads + i, &attr,
27392 GC_mark_thread, (void *)(word)i)) {
27393 WARN("Marker thread creation failed, errno= %" WARN_PRIdPTR "\n",
27394 errno);
27395 GC_markers_m1 = i;
27396 break;
27397 }
27398 }
27399#ifndef NO_MARKER_SPECIAL_SIGMASK
27400 if (REAL_FUNC(pthread_sigmask)(SIG_SETMASK, &oldset, NULL) < 0) {
27401 WARN("pthread_sigmask restore failed, errno= %" WARN_PRIdPTR "\n",
27402 errno);
27403 }
27404#endif
27405 (void)pthread_attr_destroy(&attr);
27406 GC_wait_for_markers_init();
27407 GC_COND_LOG_PRINTF("Started %d mark helper threads\n", GC_markers_m1);
27408}
27409#endif
27410GC_INNER GC_bool GC_thr_initialized = FALSE;
27411GC_INNER volatile GC_thread GC_threads[THREAD_TABLE_SZ] = {0};
27412void GC_push_thread_structures(void)
27413{
27414 GC_ASSERT(I_HOLD_LOCK());
27415 GC_PUSH_ALL_SYM(GC_threads);
27416#if defined(THREAD_LOCAL_ALLOC)
27417 GC_PUSH_ALL_SYM(GC_thread_key);
27418#endif
27419}
27420#ifdef DEBUG_THREADS
27421 STATIC int GC_count_threads(void)
27422 {
27423 int i;
27424 int count = 0;
27425 GC_ASSERT(I_HOLD_LOCK());
27426 for (i = 0; i < THREAD_TABLE_SZ; ++i) {
27427 GC_thread th = GC_threads[i];
27428 while (th) {
27429 if (!(th->flags & FINISHED))
27430 ++count;
27431 th = th->next;
27432 }
27433 }
27434 return count;
27435 }
27436#endif
27437static struct GC_Thread_Rep first_thread;
27438STATIC GC_thread GC_new_thread(pthread_t id)
27439{
27440 int hv = THREAD_TABLE_INDEX(id);
27441 GC_thread result;
27442 static GC_bool first_thread_used = FALSE;
27443#ifdef DEBUG_THREADS
27444 GC_log_printf("Creating thread %p\n", (void *)id);
27445 for (result = GC_threads[hv]; result != NULL; result = result->next)
27446 if (!THREAD_EQUAL(result->id, id)) {
27447 GC_log_printf("Hash collision at GC_threads[%d]\n", hv);
27448 break;
27449 }
27450#endif
27451 GC_ASSERT(I_HOLD_LOCK());
27452 if (!EXPECT(first_thread_used, TRUE)) {
27453 result = &first_thread;
27454 first_thread_used = TRUE;
27455 GC_ASSERT(NULL == GC_threads[hv]);
27456#if defined(THREAD_SANITIZER) && defined(CPPCHECK)
27457 GC_noop1(result->dummy[0]);
27458#endif
27459 } else {
27460 result = (struct GC_Thread_Rep *)
27461 GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep), NORMAL);
27462 if (result == 0) return(0);
27463 }
27464 result -> id = id;
27465#ifdef USE_TKILL_ON_ANDROID
27466 result -> kernel_id = gettid();
27467#endif
27468 result -> next = GC_threads[hv];
27469 GC_threads[hv] = result;
27470#ifdef NACL
27471 GC_nacl_gc_thread_self = result;
27472 GC_nacl_initialize_gc_thread();
27473#endif
27474 GC_ASSERT(result -> flags == 0 && result -> thread_blocked == 0);
27475 if (EXPECT(result != &first_thread, TRUE))
27476 GC_dirty(result);
27477 return(result);
27478}
27479STATIC void GC_delete_thread(pthread_t id)
27480{
27481 int hv = THREAD_TABLE_INDEX(id);
27482 GC_thread p = GC_threads[hv];
27483 GC_thread prev = NULL;
27484#ifdef DEBUG_THREADS
27485 GC_log_printf("Deleting thread %p, n_threads= %d\n",
27486 (void *)id, GC_count_threads());
27487#endif
27488#ifdef NACL
27489 GC_nacl_shutdown_gc_thread();
27490 GC_nacl_gc_thread_self = NULL;
27491#endif
27492 GC_ASSERT(I_HOLD_LOCK());
27493 while (!THREAD_EQUAL(p -> id, id)) {
27494 prev = p;
27495 p = p -> next;
27496 }
27497 if (prev == 0) {
27498 GC_threads[hv] = p -> next;
27499 } else {
27500 GC_ASSERT(prev != &first_thread);
27501 prev -> next = p -> next;
27502 GC_dirty(prev);
27503 }
27504 if (p != &first_thread) {
27505#ifdef GC_DARWIN_THREADS
27506 mach_port_deallocate(mach_task_self(), p->stop_info.mach_thread);
27507#endif
27508 GC_INTERNAL_FREE(p);
27509 }
27510}
27511STATIC void GC_delete_gc_thread(GC_thread t)
27512{
27513 pthread_t id = t -> id;
27514 int hv = THREAD_TABLE_INDEX(id);
27515 GC_thread p = GC_threads[hv];
27516 GC_thread prev = NULL;
27517 GC_ASSERT(I_HOLD_LOCK());
27518 while (p != t) {
27519 prev = p;
27520 p = p -> next;
27521 }
27522 if (prev == 0) {
27523 GC_threads[hv] = p -> next;
27524 } else {
27525 GC_ASSERT(prev != &first_thread);
27526 prev -> next = p -> next;
27527 GC_dirty(prev);
27528 }
27529#ifdef GC_DARWIN_THREADS
27530 mach_port_deallocate(mach_task_self(), p->stop_info.mach_thread);
27531#endif
27532 GC_INTERNAL_FREE(p);
27533#ifdef DEBUG_THREADS
27534 GC_log_printf("Deleted thread %p, n_threads= %d\n",
27535 (void *)id, GC_count_threads());
27536#endif
27537}
27538GC_INNER GC_thread GC_lookup_thread(pthread_t id)
27539{
27540 GC_thread p = GC_threads[THREAD_TABLE_INDEX(id)];
27541 while (p != 0 && !THREAD_EQUAL(p -> id, id)) p = p -> next;
27542 return(p);
27543}
27544GC_INNER void GC_reset_finalizer_nested(void)
27545{
27546 GC_thread me = GC_lookup_thread(pthread_self());
27547 me->finalizer_nested = 0;
27548}
27549GC_INNER unsigned char *GC_check_finalizer_nested(void)
27550{
27551 GC_thread me = GC_lookup_thread(pthread_self());
27552 unsigned nesting_level = me->finalizer_nested;
27553 if (nesting_level) {
27554 if (++me->finalizer_skipped < (1U << nesting_level)) return NULL;
27555 me->finalizer_skipped = 0;
27556 }
27557 me->finalizer_nested = (unsigned char)(nesting_level + 1);
27558 return &me->finalizer_nested;
27559}
27560#if defined(GC_ASSERTIONS) && defined(THREAD_LOCAL_ALLOC)
27561 GC_bool GC_is_thread_tsd_valid(void *tsd)
27562 {
27563 GC_thread me;
27564 DCL_LOCK_STATE;
27565 LOCK();
27566 me = GC_lookup_thread(pthread_self());
27567 UNLOCK();
27568 return (word)tsd >= (word)(&me->tlfs)
27569 && (word)tsd < (word)(&me->tlfs) + sizeof(me->tlfs);
27570 }
27571#endif
27572GC_API int GC_CALL GC_thread_is_registered(void)
27573{
27574 pthread_t self = pthread_self();
27575 GC_thread me;
27576 DCL_LOCK_STATE;
27577 LOCK();
27578 me = GC_lookup_thread(self);
27579 UNLOCK();
27580 return me != NULL;
27581}
27582static pthread_t main_pthread_id;
27583static void *main_stack, *main_altstack;
27584static word main_stack_size, main_altstack_size;
27585GC_API void GC_CALL GC_register_altstack(void *stack, GC_word stack_size,
27586 void *altstack,
27587 GC_word altstack_size)
27588{
27589 GC_thread me;
27590 pthread_t self = pthread_self();
27591 DCL_LOCK_STATE;
27592 LOCK();
27593 me = GC_lookup_thread(self);
27594 if (me != NULL) {
27595 me->stack = (ptr_t)stack;
27596 me->stack_size = stack_size;
27597 me->altstack = (ptr_t)altstack;
27598 me->altstack_size = altstack_size;
27599 } else {
27600 main_pthread_id = self;
27601 main_stack = stack;
27602 main_stack_size = stack_size;
27603 main_altstack = altstack;
27604 main_altstack_size = altstack_size;
27605 }
27606 UNLOCK();
27607}
27608#ifdef CAN_HANDLE_FORK
27609#ifdef CAN_CALL_ATFORK
27610 GC_ATTR_NO_SANITIZE_THREAD
27611#endif
27612 static void store_to_threads_table(int hv, GC_thread me)
27613 {
27614 GC_threads[hv] = me;
27615 }
27616STATIC void GC_remove_all_threads_but_me(void)
27617{
27618 pthread_t self = pthread_self();
27619 int hv;
27620 for (hv = 0; hv < THREAD_TABLE_SZ; ++hv) {
27621 GC_thread p, next;
27622 GC_thread me = NULL;
27623 for (p = GC_threads[hv]; 0 != p; p = next) {
27624 next = p -> next;
27625 if (THREAD_EQUAL(p -> id, self)
27626 && me == NULL) {
27627 me = p;
27628 p -> next = 0;
27629#ifdef GC_DARWIN_THREADS
27630 me -> stop_info.mach_thread = mach_thread_self();
27631#endif
27632#ifdef USE_TKILL_ON_ANDROID
27633 me -> kernel_id = gettid();
27634#endif
27635#if defined(THREAD_LOCAL_ALLOC) && !defined(USE_CUSTOM_SPECIFIC)
27636 {
27637 int res;
27638 res = GC_setspecific(GC_thread_key, &me->tlfs);
27639 if (COVERT_DATAFLOW(res) != 0)
27640 ABORT("GC_setspecific failed (in child)");
27641 }
27642#endif
27643 } else {
27644#ifdef THREAD_LOCAL_ALLOC
27645 if (!(p -> flags & FINISHED)) {
27646 GC_remove_specific_after_fork(GC_thread_key, p -> id);
27647 }
27648#endif
27649#if !defined(THREAD_SANITIZER) || !defined(CAN_CALL_ATFORK)
27650 if (p != &first_thread) GC_INTERNAL_FREE(p);
27651#endif
27652 }
27653 }
27654 store_to_threads_table(hv, me);
27655 }
27656}
27657#endif
27658#ifdef USE_PROC_FOR_LIBRARIES
27659 GC_INNER GC_bool GC_segment_is_thread_stack(ptr_t lo, ptr_t hi)
27660 {
27661 int i;
27662 GC_thread p;
27663 GC_ASSERT(I_HOLD_LOCK());
27664#ifdef PARALLEL_MARK
27665 for (i = 0; i < GC_markers_m1; ++i) {
27666 if ((word)marker_sp[i] > (word)lo && (word)marker_sp[i] < (word)hi)
27667 return TRUE;
27668#ifdef IA64
27669 if ((word)marker_bsp[i] > (word)lo
27670 && (word)marker_bsp[i] < (word)hi)
27671 return TRUE;
27672#endif
27673 }
27674#endif
27675 for (i = 0; i < THREAD_TABLE_SZ; i++) {
27676 for (p = GC_threads[i]; p != 0; p = p -> next) {
27677 if (0 != p -> stack_end) {
27678#ifdef STACK_GROWS_UP
27679 if ((word)p->stack_end >= (word)lo
27680 && (word)p->stack_end < (word)hi)
27681 return TRUE;
27682#else
27683 if ((word)p->stack_end > (word)lo
27684 && (word)p->stack_end <= (word)hi)
27685 return TRUE;
27686#endif
27687 }
27688 }
27689 }
27690 return FALSE;
27691 }
27692#endif
27693#ifdef IA64
27694 GC_INNER ptr_t GC_greatest_stack_base_below(ptr_t bound)
27695 {
27696 int i;
27697 GC_thread p;
27698 ptr_t result = 0;
27699 GC_ASSERT(I_HOLD_LOCK());
27700#ifdef PARALLEL_MARK
27701 for (i = 0; i < GC_markers_m1; ++i) {
27702 if ((word)marker_sp[i] > (word)result
27703 && (word)marker_sp[i] < (word)bound)
27704 result = marker_sp[i];
27705 }
27706#endif
27707 for (i = 0; i < THREAD_TABLE_SZ; i++) {
27708 for (p = GC_threads[i]; p != 0; p = p -> next) {
27709 if ((word)p->stack_end > (word)result
27710 && (word)p->stack_end < (word)bound) {
27711 result = p -> stack_end;
27712 }
27713 }
27714 }
27715 return result;
27716 }
27717#endif
27718#ifndef STAT_READ
27719#define STAT_READ read
27720#endif
27721#ifdef GC_HPUX_THREADS
27722#define GC_get_nprocs() pthread_num_processors_np()
27723#elif defined(GC_OSF1_THREADS) || defined(GC_AIX_THREADS) \
27724 || defined(GC_HAIKU_THREADS) || defined(GC_SOLARIS_THREADS) \
27725 || defined(HURD) || defined(HOST_ANDROID) || defined(NACL)
27726 GC_INLINE int GC_get_nprocs(void)
27727 {
27728 int nprocs = (int)sysconf(_SC_NPROCESSORS_ONLN);
27729 return nprocs > 0 ? nprocs : 1;
27730 }
27731#elif defined(GC_IRIX_THREADS)
27732 GC_INLINE int GC_get_nprocs(void)
27733 {
27734 int nprocs = (int)sysconf(_SC_NPROC_ONLN);
27735 return nprocs > 0 ? nprocs : 1;
27736 }
27737#elif defined(GC_LINUX_THREADS)
27738 STATIC int GC_get_nprocs(void)
27739 {
27740#define PROC_STAT_BUF_SZ ((1 + MAX_MARKERS) * 100)
27741 char stat_buf[PROC_STAT_BUF_SZ+1];
27742 int f;
27743 int result, i, len;
27744 f = open("/proc/stat", O_RDONLY);
27745 if (f < 0) {
27746 WARN("Could not open /proc/stat\n", 0);
27747 return 1;
27748 }
27749 len = STAT_READ(f, stat_buf, sizeof(stat_buf)-1);
27750 if (len < 0) {
27751 WARN("Failed to read /proc/stat, errno= %" WARN_PRIdPTR "\n", errno);
27752 close(f);
27753 return 1;
27754 }
27755 stat_buf[len] = '\0';
27756 close(f);
27757 result = 1;
27758 for (i = 0; i < len - 4; ++i) {
27759 if (stat_buf[i] == '\n' && stat_buf[i+1] == 'c'
27760 && stat_buf[i+2] == 'p' && stat_buf[i+3] == 'u') {
27761 int cpu_no = atoi(&stat_buf[i + 4]);
27762 if (cpu_no >= result)
27763 result = cpu_no + 1;
27764 }
27765 }
27766 return result;
27767 }
27768#elif defined(GC_DGUX386_THREADS)
27769 STATIC int GC_get_nprocs(void)
27770 {
27771 int numCpus;
27772 struct dg_sys_info_pm_info pm_sysinfo;
27773 int status = 0;
27774 status = dg_sys_info((long int *) &pm_sysinfo,
27775 DG_SYS_INFO_PM_INFO_TYPE, DG_SYS_INFO_PM_CURRENT_VERSION);
27776 if (status < 0)
27777 numCpus = -1;
27778 else
27779 numCpus = pm_sysinfo.idle_vp_count;
27780 return(numCpus);
27781 }
27782#elif defined(GC_DARWIN_THREADS) || defined(GC_FREEBSD_THREADS) \
27783 || defined(GC_NETBSD_THREADS) || defined(GC_OPENBSD_THREADS)
27784 STATIC int GC_get_nprocs(void)
27785 {
27786 int mib[] = {CTL_HW,HW_NCPU};
27787 int res;
27788 size_t len = sizeof(res);
27789 sysctl(mib, sizeof(mib)/sizeof(int), &res, &len, NULL, 0);
27790 return res;
27791 }
27792#else
27793#define GC_get_nprocs() 1
27794#endif
27795#if defined(ARM32) && defined(GC_LINUX_THREADS) && !defined(NACL)
27796 STATIC int GC_get_nprocs_present(void)
27797 {
27798 char stat_buf[16];
27799 int f;
27800 int len;
27801 f = open("/sys/devices/system/cpu/present", O_RDONLY);
27802 if (f < 0)
27803 return -1;
27804 len = STAT_READ(f, stat_buf, sizeof(stat_buf));
27805 close(f);
27806 if (len < 2 || stat_buf[0] != '0' || stat_buf[len - 1] != '\n') {
27807 return 0;
27808 } else if (len == 2) {
27809 return 1;
27810 } else if (stat_buf[1] != '-') {
27811 return 0;
27812 }
27813 stat_buf[len - 1] = '\0';
27814 return atoi(&stat_buf[2]) + 1;
27815 }
27816#endif
27817STATIC void GC_wait_for_gc_completion(GC_bool wait_for_all)
27818{
27819 DCL_LOCK_STATE;
27820#if !defined(THREAD_SANITIZER) || !defined(CAN_CALL_ATFORK)
27821 GC_ASSERT(I_HOLD_LOCK());
27822#endif
27823 ASSERT_CANCEL_DISABLED();
27824 if (GC_incremental && GC_collection_in_progress()) {
27825 word old_gc_no = GC_gc_no;
27826 while (GC_incremental && GC_collection_in_progress()
27827 && (wait_for_all || old_gc_no == GC_gc_no)) {
27828 ENTER_GC();
27829 GC_in_thread_creation = TRUE;
27830 GC_collect_a_little_inner(1);
27831 GC_in_thread_creation = FALSE;
27832 EXIT_GC();
27833 UNLOCK();
27834 sched_yield();
27835 LOCK();
27836 }
27837 }
27838}
27839#ifdef CAN_HANDLE_FORK
27840IF_CANCEL(static int fork_cancel_state;)
27841#if defined(GC_ASSERTIONS) && defined(CAN_CALL_ATFORK)
27842 GC_ATTR_NO_SANITIZE_THREAD
27843#endif
27844static void fork_prepare_proc(void)
27845{
27846 LOCK();
27847 DISABLE_CANCEL(fork_cancel_state);
27848#if defined(PARALLEL_MARK)
27849 if (GC_parallel)
27850 GC_wait_for_reclaim();
27851#endif
27852 GC_wait_for_gc_completion(TRUE);
27853#if defined(PARALLEL_MARK)
27854 if (GC_parallel)
27855 GC_acquire_mark_lock();
27856#endif
27857 GC_acquire_dirty_lock();
27858}
27859#if defined(GC_ASSERTIONS) && defined(CAN_CALL_ATFORK)
27860 GC_ATTR_NO_SANITIZE_THREAD
27861#endif
27862static void fork_parent_proc(void)
27863{
27864 GC_release_dirty_lock();
27865#if defined(PARALLEL_MARK)
27866 if (GC_parallel)
27867 GC_release_mark_lock();
27868#endif
27869 RESTORE_CANCEL(fork_cancel_state);
27870 UNLOCK();
27871}
27872#if defined(GC_ASSERTIONS) && defined(CAN_CALL_ATFORK)
27873 GC_ATTR_NO_SANITIZE_THREAD
27874#endif
27875static void fork_child_proc(void)
27876{
27877 GC_release_dirty_lock();
27878#if defined(PARALLEL_MARK)
27879 if (GC_parallel)
27880 GC_release_mark_lock();
27881#endif
27882 GC_remove_all_threads_but_me();
27883#ifdef PARALLEL_MARK
27884 GC_parallel = FALSE;
27885#endif
27886#ifndef GC_DISABLE_INCREMENTAL
27887 GC_dirty_update_child();
27888#endif
27889 RESTORE_CANCEL(fork_cancel_state);
27890 UNLOCK();
27891#ifdef USE_PTHREAD_LOCKS
27892 GC_ASSERT(I_DONT_HOLD_LOCK());
27893 (void)pthread_mutex_destroy(&GC_allocate_ml);
27894 if (0 != pthread_mutex_init(&GC_allocate_ml, NULL))
27895 ABORT("pthread_mutex_init failed (in child)");
27896#endif
27897}
27898 GC_API void GC_CALL GC_atfork_prepare(void)
27899 {
27900 if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
27901#if defined(GC_DARWIN_THREADS) && defined(MPROTECT_VDB)
27902 if (GC_auto_incremental) {
27903 GC_ASSERT(0 == GC_handle_fork);
27904 ABORT("Unable to fork while mprotect_thread is running");
27905 }
27906#endif
27907 if (GC_handle_fork <= 0)
27908 fork_prepare_proc();
27909 }
27910 GC_API void GC_CALL GC_atfork_parent(void)
27911 {
27912 if (GC_handle_fork <= 0)
27913 fork_parent_proc();
27914 }
27915 GC_API void GC_CALL GC_atfork_child(void)
27916 {
27917 if (GC_handle_fork <= 0)
27918 fork_child_proc();
27919 }
27920#endif
27921#ifdef INCLUDE_LINUX_THREAD_DESCR
27922 __thread int GC_dummy_thread_local;
27923#endif
27924#ifdef PARALLEL_MARK
27925 static void setup_mark_lock(void);
27926 static unsigned required_markers_cnt = 0;
27927#endif
27928GC_API void GC_CALL GC_set_markers_count(unsigned markers GC_ATTR_UNUSED)
27929{
27930#ifdef PARALLEL_MARK
27931 required_markers_cnt = markers < MAX_MARKERS ? markers : MAX_MARKERS;
27932#endif
27933}
27934GC_INNER void GC_thr_init(void)
27935{
27936 GC_ASSERT(I_HOLD_LOCK());
27937 if (GC_thr_initialized) return;
27938 GC_thr_initialized = TRUE;
27939 GC_ASSERT((word)&GC_threads % sizeof(word) == 0);
27940#ifdef CAN_HANDLE_FORK
27941 if (GC_handle_fork) {
27942#ifdef CAN_CALL_ATFORK
27943 if (pthread_atfork(fork_prepare_proc, fork_parent_proc,
27944 fork_child_proc) == 0) {
27945 GC_handle_fork = 1;
27946 } else
27947#endif
27948 if (GC_handle_fork != -1)
27949 ABORT("pthread_atfork failed");
27950 }
27951#endif
27952#ifdef INCLUDE_LINUX_THREAD_DESCR
27953 {
27954 ptr_t thread_local_addr = (ptr_t)(&GC_dummy_thread_local);
27955 ptr_t main_thread_start, main_thread_end;
27956 if (!GC_enclosing_mapping(thread_local_addr, &main_thread_start,
27957 &main_thread_end)) {
27958 ABORT("Failed to find mapping for main thread thread locals");
27959 } else {
27960 GC_add_roots_inner(main_thread_start, main_thread_end, FALSE);
27961 }
27962 }
27963#endif
27964 {
27965 pthread_t self = pthread_self();
27966 GC_thread t = GC_new_thread(self);
27967 if (t == NULL)
27968 ABORT("Failed to allocate memory for the initial thread");
27969#ifdef GC_DARWIN_THREADS
27970 t -> stop_info.mach_thread = mach_thread_self();
27971#else
27972 t -> stop_info.stack_ptr = GC_approx_sp();
27973#endif
27974 t -> flags = DETACHED | MAIN_THREAD;
27975 if (THREAD_EQUAL(self, main_pthread_id)) {
27976 t -> stack = (ptr_t)main_stack;
27977 t -> stack_size = main_stack_size;
27978 t -> altstack = (ptr_t)main_altstack;
27979 t -> altstack_size = main_altstack_size;
27980 }
27981 }
27982 {
27983 char * nprocs_string = GETENV("GC_NPROCS");
27984 GC_nprocs = -1;
27985 if (nprocs_string != NULL) GC_nprocs = atoi(nprocs_string);
27986 }
27987 if (GC_nprocs <= 0
27988#if defined(ARM32) && defined(GC_LINUX_THREADS) && !defined(NACL)
27989 && (GC_nprocs = GC_get_nprocs_present()) <= 1
27990#endif
27991 )
27992 {
27993 GC_nprocs = GC_get_nprocs();
27994 }
27995 if (GC_nprocs <= 0) {
27996 WARN("GC_get_nprocs() returned %" WARN_PRIdPTR "\n", GC_nprocs);
27997 GC_nprocs = 2;
27998#ifdef PARALLEL_MARK
27999 available_markers_m1 = 0;
28000#endif
28001 } else {
28002#ifdef PARALLEL_MARK
28003 {
28004 char * markers_string = GETENV("GC_MARKERS");
28005 int markers = required_markers_cnt;
28006 if (markers_string != NULL) {
28007 markers = atoi(markers_string);
28008 if (markers <= 0 || markers > MAX_MARKERS) {
28009 WARN("Too big or invalid number of mark threads: %" WARN_PRIdPTR
28010 "; using maximum threads\n", (signed_word)markers);
28011 markers = MAX_MARKERS;
28012 }
28013 } else if (0 == markers) {
28014 markers = GC_nprocs;
28015#if defined(GC_MIN_MARKERS) && !defined(CPPCHECK)
28016 if (markers < GC_MIN_MARKERS)
28017 markers = GC_MIN_MARKERS;
28018#endif
28019 if (markers > MAX_MARKERS)
28020 markers = MAX_MARKERS;
28021 }
28022 available_markers_m1 = markers - 1;
28023 }
28024#endif
28025 }
28026 GC_COND_LOG_PRINTF("Number of processors: %d\n", GC_nprocs);
28027#if defined(BASE_ATOMIC_OPS_EMULATED) && !defined(GC_DARWIN_THREADS) \
28028 && !defined(GC_OPENBSD_UTHREADS) && !defined(NACL) \
28029 && !defined(PLATFORM_STOP_WORLD) && !defined(SN_TARGET_PSP2)
28030 {
28031 cpu_set_t mask;
28032 int cpu_set_cnt = 0;
28033 int cpu_lowest_set = 0;
28034 int i = GC_nprocs > 1 ? GC_nprocs : 2;
28035 if (sched_getaffinity(0 ,
28036 sizeof(mask), &mask) == -1)
28037 ABORT_ARG1("sched_getaffinity failed", ": errno= %d", errno);
28038 while (i-- > 0)
28039 if (CPU_ISSET(i, &mask)) {
28040 cpu_lowest_set = i;
28041 cpu_set_cnt++;
28042 }
28043 if (0 == cpu_set_cnt)
28044 ABORT("sched_getaffinity returned empty mask");
28045 if (cpu_set_cnt > 1) {
28046 CPU_ZERO(&mask);
28047 CPU_SET(cpu_lowest_set, &mask);
28048 if (sched_setaffinity(0, sizeof(mask), &mask) == -1)
28049 ABORT_ARG1("sched_setaffinity failed", ": errno= %d", errno);
28050 WARN("CPU affinity mask is set to %p\n", (word)1 << cpu_lowest_set);
28051 }
28052 }
28053#endif
28054#ifndef GC_DARWIN_THREADS
28055 GC_stop_init();
28056#endif
28057#ifdef PARALLEL_MARK
28058 if (available_markers_m1 <= 0) {
28059 GC_parallel = FALSE;
28060 GC_COND_LOG_PRINTF(
28061 "Single marker thread, turning off parallel marking\n");
28062 } else {
28063 setup_mark_lock();
28064 }
28065#endif
28066}
28067GC_INNER void GC_init_parallel(void)
28068{
28069#if defined(THREAD_LOCAL_ALLOC)
28070 DCL_LOCK_STATE;
28071#endif
28072 if (parallel_initialized) return;
28073 parallel_initialized = TRUE;
28074 if (!GC_is_initialized) GC_init();
28075#if defined(THREAD_LOCAL_ALLOC)
28076 LOCK();
28077 GC_init_thread_local(&(GC_lookup_thread(pthread_self())->tlfs));
28078 UNLOCK();
28079#endif
28080}
28081#ifndef GC_NO_PTHREAD_SIGMASK
28082 GC_API int WRAP_FUNC(pthread_sigmask)(int how, const sigset_t *set,
28083 sigset_t *oset)
28084 {
28085 sigset_t fudged_set;
28086 INIT_REAL_SYMS();
28087 if (set != NULL && (how == SIG_BLOCK || how == SIG_SETMASK)) {
28088 int sig_suspend = GC_get_suspend_signal();
28089 fudged_set = *set;
28090 GC_ASSERT(sig_suspend >= 0);
28091 if (sigdelset(&fudged_set, sig_suspend) != 0)
28092 ABORT("sigdelset failed");
28093 set = &fudged_set;
28094 }
28095 return(REAL_FUNC(pthread_sigmask)(how, set, oset));
28096 }
28097#endif
28098GC_INNER void GC_do_blocking_inner(ptr_t data, void * context GC_ATTR_UNUSED)
28099{
28100 struct blocking_data * d = (struct blocking_data *) data;
28101 pthread_t self = pthread_self();
28102 GC_thread me;
28103#if defined(SPARC) || defined(IA64)
28104 ptr_t stack_ptr = GC_save_regs_in_stack();
28105#endif
28106#if defined(GC_DARWIN_THREADS) && !defined(DARWIN_DONT_PARSE_STACK)
28107 GC_bool topOfStackUnset = FALSE;
28108#endif
28109 DCL_LOCK_STATE;
28110 LOCK();
28111 me = GC_lookup_thread(self);
28112 GC_ASSERT(!(me -> thread_blocked));
28113#ifdef SPARC
28114 me -> stop_info.stack_ptr = stack_ptr;
28115#else
28116 me -> stop_info.stack_ptr = GC_approx_sp();
28117#endif
28118#if defined(GC_DARWIN_THREADS) && !defined(DARWIN_DONT_PARSE_STACK)
28119 if (me -> topOfStack == NULL) {
28120 topOfStackUnset = TRUE;
28121 me -> topOfStack = GC_FindTopOfStack(0);
28122 }
28123#endif
28124#ifdef IA64
28125 me -> backing_store_ptr = stack_ptr;
28126#endif
28127 me -> thread_blocked = (unsigned char)TRUE;
28128 UNLOCK();
28129 d -> client_data = (d -> fn)(d -> client_data);
28130 LOCK();
28131#if defined(CPPCHECK)
28132 GC_noop1((word)&me->thread_blocked);
28133#endif
28134 me -> thread_blocked = FALSE;
28135#if defined(GC_DARWIN_THREADS) && !defined(DARWIN_DONT_PARSE_STACK)
28136 if (topOfStackUnset)
28137 me -> topOfStack = NULL;
28138#endif
28139 UNLOCK();
28140}
28141GC_API void GC_CALL GC_set_stackbottom(void *gc_thread_handle,
28142 const struct GC_stack_base *sb)
28143{
28144 GC_thread t = (GC_thread)gc_thread_handle;
28145 GC_ASSERT(sb -> mem_base != NULL);
28146 if (!EXPECT(GC_is_initialized, TRUE)) {
28147 GC_ASSERT(NULL == t);
28148 } else {
28149 GC_ASSERT(I_HOLD_LOCK());
28150 if (NULL == t)
28151 t = GC_lookup_thread(pthread_self());
28152 GC_ASSERT((t -> flags & FINISHED) == 0);
28153 GC_ASSERT(!(t -> thread_blocked)
28154 && NULL == t -> traced_stack_sect);
28155 if ((t -> flags & MAIN_THREAD) == 0) {
28156 t -> stack_end = (ptr_t)sb->mem_base;
28157#ifdef IA64
28158 t -> backing_store_end = (ptr_t)sb->reg_base;
28159#endif
28160 return;
28161 }
28162 }
28163 GC_stackbottom = (char*)sb->mem_base;
28164#ifdef IA64
28165 GC_register_stackbottom = (ptr_t)sb->reg_base;
28166#endif
28167}
28168GC_API void * GC_CALL GC_get_my_stackbottom(struct GC_stack_base *sb)
28169{
28170 pthread_t self = pthread_self();
28171 GC_thread me;
28172 DCL_LOCK_STATE;
28173 LOCK();
28174 me = GC_lookup_thread(self);
28175 if ((me -> flags & MAIN_THREAD) == 0) {
28176 sb -> mem_base = me -> stack_end;
28177#ifdef IA64
28178 sb -> reg_base = me -> backing_store_end;
28179#endif
28180 } else {
28181 sb -> mem_base = GC_stackbottom;
28182#ifdef IA64
28183 sb -> reg_base = GC_register_stackbottom;
28184#endif
28185 }
28186 UNLOCK();
28187 return (void *)me;
28188}
28189GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn,
28190 void * client_data)
28191{
28192 struct GC_traced_stack_sect_s stacksect;
28193 pthread_t self = pthread_self();
28194 GC_thread me;
28195 DCL_LOCK_STATE;
28196 LOCK();
28197 me = GC_lookup_thread(self);
28198 if ((me -> flags & MAIN_THREAD) == 0) {
28199 GC_ASSERT(me -> stack_end != NULL);
28200 if ((word)me->stack_end HOTTER_THAN (word)(&stacksect))
28201 me -> stack_end = (ptr_t)(&stacksect);
28202 } else {
28203 if ((word)GC_stackbottom HOTTER_THAN (word)(&stacksect))
28204 GC_stackbottom = (ptr_t)COVERT_DATAFLOW(&stacksect);
28205 }
28206 if (!me->thread_blocked) {
28207 UNLOCK();
28208 client_data = fn(client_data);
28209 GC_noop1(COVERT_DATAFLOW(&stacksect));
28210 return client_data;
28211 }
28212 stacksect.saved_stack_ptr = me -> stop_info.stack_ptr;
28213#ifdef IA64
28214 stacksect.backing_store_end = GC_save_regs_in_stack();
28215 stacksect.saved_backing_store_ptr = me -> backing_store_ptr;
28216#endif
28217 stacksect.prev = me -> traced_stack_sect;
28218 me -> thread_blocked = FALSE;
28219 me -> traced_stack_sect = &stacksect;
28220 UNLOCK();
28221 client_data = fn(client_data);
28222 GC_ASSERT(me -> thread_blocked == FALSE);
28223 GC_ASSERT(me -> traced_stack_sect == &stacksect);
28224#if defined(CPPCHECK)
28225 GC_noop1((word)me->traced_stack_sect);
28226#endif
28227 LOCK();
28228 me -> traced_stack_sect = stacksect.prev;
28229#ifdef IA64
28230 me -> backing_store_ptr = stacksect.saved_backing_store_ptr;
28231#endif
28232 me -> thread_blocked = (unsigned char)TRUE;
28233 me -> stop_info.stack_ptr = stacksect.saved_stack_ptr;
28234 UNLOCK();
28235 return client_data;
28236}
28237STATIC void GC_unregister_my_thread_inner(GC_thread me)
28238{
28239 GC_ASSERT(I_HOLD_LOCK());
28240#ifdef DEBUG_THREADS
28241 GC_log_printf(
28242 "Unregistering thread %p, gc_thread= %p, n_threads= %d\n",
28243 (void *)me->id, (void *)me, GC_count_threads());
28244#endif
28245 GC_ASSERT(!(me -> flags & FINISHED));
28246#if defined(THREAD_LOCAL_ALLOC)
28247 GC_ASSERT(GC_getspecific(GC_thread_key) == &me->tlfs);
28248 GC_destroy_thread_local(&(me->tlfs));
28249#endif
28250#if defined(GC_HAVE_PTHREAD_EXIT) || !defined(GC_NO_PTHREAD_CANCEL)
28251 if ((me -> flags & DISABLED_GC) != 0) {
28252 GC_dont_gc--;
28253 }
28254#endif
28255 if (me -> flags & DETACHED) {
28256 GC_delete_thread(pthread_self());
28257 } else {
28258 me -> flags |= FINISHED;
28259 }
28260#if defined(THREAD_LOCAL_ALLOC)
28261 GC_remove_specific(GC_thread_key);
28262#endif
28263}
28264GC_API int GC_CALL GC_unregister_my_thread(void)
28265{
28266 pthread_t self = pthread_self();
28267 GC_thread me;
28268 IF_CANCEL(int cancel_state;)
28269 DCL_LOCK_STATE;
28270 LOCK();
28271 DISABLE_CANCEL(cancel_state);
28272 GC_wait_for_gc_completion(FALSE);
28273 me = GC_lookup_thread(self);
28274#ifdef DEBUG_THREADS
28275 GC_log_printf(
28276 "Called GC_unregister_my_thread on %p, gc_thread= %p\n",
28277 (void *)self, (void *)me);
28278#endif
28279 GC_ASSERT(THREAD_EQUAL(me->id, self));
28280 GC_unregister_my_thread_inner(me);
28281 RESTORE_CANCEL(cancel_state);
28282 UNLOCK();
28283 return GC_SUCCESS;
28284}
28285GC_INNER_PTHRSTART void GC_thread_exit_proc(void *arg)
28286{
28287 IF_CANCEL(int cancel_state;)
28288 DCL_LOCK_STATE;
28289#ifdef DEBUG_THREADS
28290 GC_log_printf("Called GC_thread_exit_proc on %p, gc_thread= %p\n",
28291 (void *)((GC_thread)arg)->id, arg);
28292#endif
28293 LOCK();
28294 DISABLE_CANCEL(cancel_state);
28295 GC_wait_for_gc_completion(FALSE);
28296 GC_unregister_my_thread_inner((GC_thread)arg);
28297 RESTORE_CANCEL(cancel_state);
28298 UNLOCK();
28299}
28300#if !defined(SN_TARGET_ORBIS) && !defined(SN_TARGET_PSP2)
28301 GC_API int WRAP_FUNC(pthread_join)(pthread_t thread, void **retval)
28302 {
28303 int result;
28304 GC_thread t;
28305 DCL_LOCK_STATE;
28306 ASSERT_SYMS_INITIALIZED();
28307 LOCK();
28308 t = (GC_thread)COVERT_DATAFLOW(GC_lookup_thread(thread));
28309 UNLOCK();
28310 result = REAL_FUNC(pthread_join)(thread, retval);
28311#if defined(GC_FREEBSD_THREADS)
28312 if (result == EINTR) result = 0;
28313#endif
28314 if (result == 0) {
28315 LOCK();
28316 if ((t -> flags & FINISHED) != 0)
28317 GC_delete_gc_thread(t);
28318 UNLOCK();
28319 }
28320 return result;
28321 }
28322 GC_API int WRAP_FUNC(pthread_detach)(pthread_t thread)
28323 {
28324 int result;
28325 GC_thread t;
28326 DCL_LOCK_STATE;
28327 ASSERT_SYMS_INITIALIZED();
28328 LOCK();
28329 t = (GC_thread)COVERT_DATAFLOW(GC_lookup_thread(thread));
28330 UNLOCK();
28331 result = REAL_FUNC(pthread_detach)(thread);
28332 if (result == 0) {
28333 LOCK();
28334 t -> flags |= DETACHED;
28335 if ((t -> flags & FINISHED) != 0) {
28336 GC_delete_gc_thread(t);
28337 }
28338 UNLOCK();
28339 }
28340 return result;
28341 }
28342#endif
28343#ifndef GC_NO_PTHREAD_CANCEL
28344 GC_API int WRAP_FUNC(pthread_cancel)(pthread_t thread)
28345 {
28346#ifdef CANCEL_SAFE
28347 GC_thread t;
28348 DCL_LOCK_STATE;
28349#endif
28350 INIT_REAL_SYMS();
28351#ifdef CANCEL_SAFE
28352 LOCK();
28353 t = GC_lookup_thread(thread);
28354 if (t != NULL && (t -> flags & DISABLED_GC) == 0) {
28355 t -> flags |= DISABLED_GC;
28356 GC_dont_gc++;
28357 }
28358 UNLOCK();
28359#endif
28360 return REAL_FUNC(pthread_cancel)(thread);
28361 }
28362#endif
28363#ifdef GC_HAVE_PTHREAD_EXIT
28364 GC_API GC_PTHREAD_EXIT_ATTRIBUTE void WRAP_FUNC(pthread_exit)(void *retval)
28365 {
28366 pthread_t self = pthread_self();
28367 GC_thread me;
28368 DCL_LOCK_STATE;
28369 INIT_REAL_SYMS();
28370 LOCK();
28371 me = GC_lookup_thread(self);
28372 if (me != 0 && (me -> flags & DISABLED_GC) == 0) {
28373 me -> flags |= DISABLED_GC;
28374 GC_dont_gc++;
28375 }
28376 UNLOCK();
28377 REAL_FUNC(pthread_exit)(retval);
28378 }
28379#endif
28380GC_INNER GC_bool GC_in_thread_creation = FALSE;
28381GC_INLINE void GC_record_stack_base(GC_thread me,
28382 const struct GC_stack_base *sb)
28383{
28384#ifndef GC_DARWIN_THREADS
28385 me -> stop_info.stack_ptr = (ptr_t)sb->mem_base;
28386#endif
28387 me -> stack_end = (ptr_t)sb->mem_base;
28388 if (me -> stack_end == NULL)
28389 ABORT("Bad stack base in GC_register_my_thread");
28390#ifdef IA64
28391 me -> backing_store_end = (ptr_t)sb->reg_base;
28392#endif
28393}
28394STATIC GC_thread GC_register_my_thread_inner(const struct GC_stack_base *sb,
28395 pthread_t my_pthread)
28396{
28397 GC_thread me;
28398 GC_in_thread_creation = TRUE;
28399 me = GC_new_thread(my_pthread);
28400 GC_in_thread_creation = FALSE;
28401 if (me == 0)
28402 ABORT("Failed to allocate memory for thread registering");
28403#ifdef GC_DARWIN_THREADS
28404 me -> stop_info.mach_thread = mach_thread_self();
28405#endif
28406 GC_record_stack_base(me, sb);
28407#ifdef GC_EXPLICIT_SIGNALS_UNBLOCK
28408 GC_unblock_gc_signals();
28409#endif
28410 return me;
28411}
28412GC_API void GC_CALL GC_allow_register_threads(void)
28413{
28414 GC_ASSERT(GC_lookup_thread(pthread_self()) != 0);
28415 set_need_to_lock();
28416}
28417GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *sb)
28418{
28419 pthread_t self = pthread_self();
28420 GC_thread me;
28421 DCL_LOCK_STATE;
28422 if (GC_need_to_lock == FALSE)
28423 ABORT("Threads explicit registering is not previously enabled");
28424 LOCK();
28425 me = GC_lookup_thread(self);
28426 if (0 == me) {
28427 me = GC_register_my_thread_inner(sb, self);
28428#if defined(CPPCHECK)
28429 GC_noop1(me->flags);
28430#endif
28431 me -> flags |= DETACHED;
28432#if defined(THREAD_LOCAL_ALLOC)
28433 GC_init_thread_local(&(me->tlfs));
28434#endif
28435 UNLOCK();
28436 return GC_SUCCESS;
28437 } else if ((me -> flags & FINISHED) != 0) {
28438#ifdef GC_DARWIN_THREADS
28439 me -> stop_info.mach_thread = mach_thread_self();
28440#endif
28441 GC_record_stack_base(me, sb);
28442 me -> flags &= ~FINISHED;
28443#ifdef GC_EXPLICIT_SIGNALS_UNBLOCK
28444 GC_unblock_gc_signals();
28445#endif
28446#if defined(THREAD_LOCAL_ALLOC)
28447 GC_init_thread_local(&(me->tlfs));
28448#endif
28449 UNLOCK();
28450 return GC_SUCCESS;
28451 } else {
28452 UNLOCK();
28453 return GC_DUPLICATE;
28454 }
28455}
28456struct start_info {
28457 void *(*start_routine)(void *);
28458 void *arg;
28459 word flags;
28460 sem_t registered;
28461};
28462GC_INNER_PTHRSTART GC_thread GC_start_rtn_prepare_thread(
28463 void *(**pstart)(void *),
28464 void **pstart_arg,
28465 struct GC_stack_base *sb, void *arg)
28466{
28467 struct start_info * si = (struct start_info *)arg;
28468 pthread_t self = pthread_self();
28469 GC_thread me;
28470 DCL_LOCK_STATE;
28471#ifdef DEBUG_THREADS
28472 GC_log_printf("Starting thread %p, pid= %ld, sp= %p\n",
28473 (void *)self, (long)getpid(), (void *)&arg);
28474#endif
28475 LOCK();
28476 me = GC_register_my_thread_inner(sb, self);
28477 me -> flags = si -> flags;
28478#if defined(THREAD_LOCAL_ALLOC)
28479 GC_init_thread_local(&(me->tlfs));
28480#endif
28481 UNLOCK();
28482 *pstart = si -> start_routine;
28483#ifdef DEBUG_THREADS
28484 GC_log_printf("start_routine= %p\n", (void *)(signed_word)(*pstart));
28485#endif
28486 *pstart_arg = si -> arg;
28487 sem_post(&(si -> registered));
28488 return me;
28489}
28490#if !defined(SN_TARGET_ORBIS) && !defined(SN_TARGET_PSP2)
28491 STATIC void * GC_start_routine(void * arg)
28492 {
28493#ifdef INCLUDE_LINUX_THREAD_DESCR
28494 struct GC_stack_base sb;
28495#ifdef REDIRECT_MALLOC
28496 GC_disable();
28497#endif
28498 if (GC_get_stack_base(&sb) != GC_SUCCESS)
28499 ABORT("Failed to get thread stack base");
28500#ifdef REDIRECT_MALLOC
28501 GC_enable();
28502#endif
28503 return GC_inner_start_routine(&sb, arg);
28504#else
28505 return GC_call_with_stack_base(GC_inner_start_routine, arg);
28506#endif
28507 }
28508 GC_API int WRAP_FUNC(pthread_create)(pthread_t *new_thread,
28509 GC_PTHREAD_CREATE_CONST pthread_attr_t *attr,
28510 void *(*start_routine)(void *), void *arg)
28511 {
28512 int result;
28513 int detachstate;
28514 word my_flags = 0;
28515 struct start_info si;
28516 DCL_LOCK_STATE;
28517 INIT_REAL_SYMS();
28518 if (!EXPECT(parallel_initialized, TRUE))
28519 GC_init_parallel();
28520 if (sem_init(&si.registered, GC_SEM_INIT_PSHARED, 0) != 0)
28521 ABORT("sem_init failed");
28522 si.start_routine = start_routine;
28523 si.arg = arg;
28524 LOCK();
28525 if (!EXPECT(GC_thr_initialized, TRUE))
28526 GC_thr_init();
28527#ifdef GC_ASSERTIONS
28528 {
28529 size_t stack_size = 0;
28530 if (NULL != attr) {
28531 if (pthread_attr_getstacksize(attr, &stack_size) != 0)
28532 ABORT("pthread_attr_getstacksize failed");
28533 }
28534 if (0 == stack_size) {
28535 pthread_attr_t my_attr;
28536 if (pthread_attr_init(&my_attr) != 0)
28537 ABORT("pthread_attr_init failed");
28538 if (pthread_attr_getstacksize(&my_attr, &stack_size) != 0)
28539 ABORT("pthread_attr_getstacksize failed");
28540 (void)pthread_attr_destroy(&my_attr);
28541 }
28542 if (0 == stack_size) {
28543#ifndef SOLARIS
28544 WARN("Failed to get stack size for assertion checking\n", 0);
28545#endif
28546 stack_size = 1000000;
28547 }
28548 GC_ASSERT(stack_size >= 65536);
28549 }
28550#endif
28551 if (NULL == attr) {
28552 detachstate = PTHREAD_CREATE_JOINABLE;
28553 } else {
28554 pthread_attr_getdetachstate(attr, &detachstate);
28555 }
28556 if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED;
28557 si.flags = my_flags;
28558 UNLOCK();
28559#ifdef DEBUG_THREADS
28560 GC_log_printf("About to start new thread from thread %p\n",
28561 (void *)pthread_self());
28562#endif
28563 set_need_to_lock();
28564 result = REAL_FUNC(pthread_create)(new_thread, attr, GC_start_routine,
28565 &si);
28566 if (0 == result) {
28567 IF_CANCEL(int cancel_state;)
28568#ifdef DEBUG_THREADS
28569 GC_log_printf("Started thread %p\n", (void *)(*new_thread));
28570#endif
28571 DISABLE_CANCEL(cancel_state);
28572 while (0 != sem_wait(&si.registered)) {
28573#if defined(GC_HAIKU_THREADS)
28574 if (EACCES == errno) continue;
28575#endif
28576 if (EINTR != errno) ABORT("sem_wait failed");
28577 }
28578 RESTORE_CANCEL(cancel_state);
28579 }
28580 sem_destroy(&si.registered);
28581 return(result);
28582 }
28583#endif
28584#if defined(USE_SPIN_LOCK) || !defined(NO_PTHREAD_TRYLOCK)
28585#define GC_PAUSE_SPIN_CYCLES 10
28586STATIC void GC_pause(void)
28587{
28588 int i;
28589 for (i = 0; i < GC_PAUSE_SPIN_CYCLES; ++i) {
28590#if defined(AO_HAVE_compiler_barrier) \
28591 && !defined(BASE_ATOMIC_OPS_EMULATED)
28592 AO_compiler_barrier();
28593#else
28594 GC_noop1(i);
28595#endif
28596 }
28597}
28598#endif
28599#ifndef SPIN_MAX
28600#define SPIN_MAX 128
28601#endif
28602GC_INNER volatile GC_bool GC_collecting = FALSE;
28603#if (!defined(USE_SPIN_LOCK) && !defined(NO_PTHREAD_TRYLOCK)) \
28604 || defined(PARALLEL_MARK)
28605#ifdef LOCK_STATS
28606 volatile AO_t GC_spin_count = 0;
28607 volatile AO_t GC_block_count = 0;
28608 volatile AO_t GC_unlocked_count = 0;
28609#endif
28610STATIC void GC_generic_lock(pthread_mutex_t * lock)
28611{
28612#ifndef NO_PTHREAD_TRYLOCK
28613 unsigned pause_length = 1;
28614 unsigned i;
28615 if (0 == pthread_mutex_trylock(lock)) {
28616#ifdef LOCK_STATS
28617 (void)AO_fetch_and_add1(&GC_unlocked_count);
28618#endif
28619 return;
28620 }
28621 for (; pause_length <= SPIN_MAX; pause_length <<= 1) {
28622 for (i = 0; i < pause_length; ++i) {
28623 GC_pause();
28624 }
28625 switch(pthread_mutex_trylock(lock)) {
28626 case 0:
28627#ifdef LOCK_STATS
28628 (void)AO_fetch_and_add1(&GC_spin_count);
28629#endif
28630 return;
28631 case EBUSY:
28632 break;
28633 default:
28634 ABORT("Unexpected error from pthread_mutex_trylock");
28635 }
28636 }
28637#endif
28638#ifdef LOCK_STATS
28639 (void)AO_fetch_and_add1(&GC_block_count);
28640#endif
28641 pthread_mutex_lock(lock);
28642}
28643#endif
28644#if defined(AO_HAVE_char_load) && !defined(BASE_ATOMIC_OPS_EMULATED)
28645#define is_collecting() \
28646 ((GC_bool)AO_char_load((unsigned char *)&GC_collecting))
28647#else
28648#define is_collecting() GC_collecting
28649#endif
28650#if defined(USE_SPIN_LOCK)
28651GC_INNER volatile AO_TS_t GC_allocate_lock = AO_TS_INITIALIZER;
28652#define low_spin_max 30
28653#define high_spin_max SPIN_MAX
28654 static volatile AO_t spin_max = low_spin_max;
28655 static volatile AO_t last_spins = 0;
28656GC_INNER void GC_lock(void)
28657{
28658 unsigned my_spin_max;
28659 unsigned my_last_spins;
28660 unsigned i;
28661 if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_CLEAR) {
28662 return;
28663 }
28664 my_spin_max = (unsigned)AO_load(&spin_max);
28665 my_last_spins = (unsigned)AO_load(&last_spins);
28666 for (i = 0; i < my_spin_max; i++) {
28667 if (is_collecting() || GC_nprocs == 1)
28668 goto yield;
28669 if (i < my_last_spins/2) {
28670 GC_pause();
28671 continue;
28672 }
28673 if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_CLEAR) {
28674 AO_store(&last_spins, (AO_t)i);
28675 AO_store(&spin_max, (AO_t)high_spin_max);
28676 return;
28677 }
28678 }
28679 AO_store(&spin_max, (AO_t)low_spin_max);
28680yield:
28681 for (i = 0;; ++i) {
28682 if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_CLEAR) {
28683 return;
28684 }
28685#define SLEEP_THRESHOLD 12
28686 if (i < SLEEP_THRESHOLD) {
28687 sched_yield();
28688 } else {
28689 struct timespec ts;
28690 if (i > 24) i = 24;
28691 ts.tv_sec = 0;
28692 ts.tv_nsec = 1 << i;
28693 nanosleep(&ts, 0);
28694 }
28695 }
28696}
28697#elif defined(USE_PTHREAD_LOCKS)
28698#ifndef NO_PTHREAD_TRYLOCK
28699 GC_INNER void GC_lock(void)
28700 {
28701 if (1 == GC_nprocs || is_collecting()) {
28702 pthread_mutex_lock(&GC_allocate_ml);
28703 } else {
28704 GC_generic_lock(&GC_allocate_ml);
28705 }
28706 }
28707#elif defined(GC_ASSERTIONS)
28708 GC_INNER void GC_lock(void)
28709 {
28710 pthread_mutex_lock(&GC_allocate_ml);
28711 }
28712#endif
28713#endif
28714#ifdef PARALLEL_MARK
28715#ifdef GC_ASSERTIONS
28716 STATIC unsigned long GC_mark_lock_holder = NO_THREAD;
28717#define SET_MARK_LOCK_HOLDER \
28718 (void)(GC_mark_lock_holder = NUMERIC_THREAD_ID(pthread_self()))
28719#define UNSET_MARK_LOCK_HOLDER \
28720 do { \
28721 GC_ASSERT(GC_mark_lock_holder \
28722 == NUMERIC_THREAD_ID(pthread_self())); \
28723 GC_mark_lock_holder = NO_THREAD; \
28724 } while (0)
28725#else
28726#define SET_MARK_LOCK_HOLDER (void)0
28727#define UNSET_MARK_LOCK_HOLDER (void)0
28728#endif
28729#ifdef GLIBC_2_1_MUTEX_HACK
28730 static pthread_mutex_t mark_mutex =
28731 {0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, {0, 0}};
28732#else
28733 static pthread_mutex_t mark_mutex = PTHREAD_MUTEX_INITIALIZER;
28734#endif
28735static pthread_cond_t builder_cv = PTHREAD_COND_INITIALIZER;
28736static void setup_mark_lock(void)
28737{
28738#ifdef GLIBC_2_19_TSX_BUG
28739 pthread_mutexattr_t mattr;
28740 int glibc_minor = -1;
28741 int glibc_major = GC_parse_version(&glibc_minor, gnu_get_libc_version());
28742 if (glibc_major > 2 || (glibc_major == 2 && glibc_minor >= 19)) {
28743 if (0 != pthread_mutexattr_init(&mattr)) {
28744 ABORT("pthread_mutexattr_init failed");
28745 }
28746 if (0 != pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_NORMAL)) {
28747 ABORT("pthread_mutexattr_settype failed");
28748 }
28749 if (0 != pthread_mutex_init(&mark_mutex, &mattr)) {
28750 ABORT("pthread_mutex_init failed");
28751 }
28752 (void)pthread_mutexattr_destroy(&mattr);
28753 }
28754#endif
28755}
28756GC_INNER void GC_acquire_mark_lock(void)
28757{
28758#if defined(NUMERIC_THREAD_ID_UNIQUE) && !defined(THREAD_SANITIZER)
28759 GC_ASSERT(GC_mark_lock_holder != NUMERIC_THREAD_ID(pthread_self()));
28760#endif
28761 GC_generic_lock(&mark_mutex);
28762 SET_MARK_LOCK_HOLDER;
28763}
28764GC_INNER void GC_release_mark_lock(void)
28765{
28766 UNSET_MARK_LOCK_HOLDER;
28767 if (pthread_mutex_unlock(&mark_mutex) != 0) {
28768 ABORT("pthread_mutex_unlock failed");
28769 }
28770}
28771STATIC void GC_wait_builder(void)
28772{
28773 ASSERT_CANCEL_DISABLED();
28774 UNSET_MARK_LOCK_HOLDER;
28775 if (pthread_cond_wait(&builder_cv, &mark_mutex) != 0) {
28776 ABORT("pthread_cond_wait failed");
28777 }
28778 GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
28779 SET_MARK_LOCK_HOLDER;
28780}
28781GC_INNER void GC_wait_for_reclaim(void)
28782{
28783 GC_acquire_mark_lock();
28784 while (GC_fl_builder_count > 0) {
28785 GC_wait_builder();
28786 }
28787 GC_release_mark_lock();
28788}
28789GC_INNER void GC_notify_all_builder(void)
28790{
28791 GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
28792 if (pthread_cond_broadcast(&builder_cv) != 0) {
28793 ABORT("pthread_cond_broadcast failed");
28794 }
28795}
28796GC_INNER void GC_wait_marker(void)
28797{
28798 ASSERT_CANCEL_DISABLED();
28799 GC_ASSERT(GC_parallel);
28800 UNSET_MARK_LOCK_HOLDER;
28801 if (pthread_cond_wait(&mark_cv, &mark_mutex) != 0) {
28802 ABORT("pthread_cond_wait failed");
28803 }
28804 GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
28805 SET_MARK_LOCK_HOLDER;
28806}
28807GC_INNER void GC_notify_all_marker(void)
28808{
28809 GC_ASSERT(GC_parallel);
28810 if (pthread_cond_broadcast(&mark_cv) != 0) {
28811 ABORT("pthread_cond_broadcast failed");
28812 }
28813}
28814#endif
28815#ifdef PTHREAD_REGISTER_CANCEL_WEAK_STUBS
28816 EXTERN_C_BEGIN
28817 extern void __pthread_register_cancel(void) __attribute__((__weak__));
28818 extern void __pthread_unregister_cancel(void) __attribute__((__weak__));
28819 EXTERN_C_END
28820 void __pthread_register_cancel(void) {}
28821 void __pthread_unregister_cancel(void) {}
28822#endif
28823#endif
28824#if defined(USE_CUSTOM_SPECIFIC)
28825static const tse invalid_tse = {INVALID_QTID, 0, 0, INVALID_THREADID};
28826GC_INNER int GC_key_create_inner(tsd ** key_ptr)
28827{
28828 int i;
28829 int ret;
28830 tsd * result;
28831 GC_ASSERT(I_HOLD_LOCK());
28832 GC_ASSERT((word)(&invalid_tse.next) % sizeof(tse *) == 0);
28833 result = (tsd *)MALLOC_CLEAR(sizeof(tsd));
28834 if (NULL == result) return ENOMEM;
28835 ret = pthread_mutex_init(&result->lock, NULL);
28836 if (ret != 0) return ret;
28837 for (i = 0; i < TS_CACHE_SIZE; ++i) {
28838 result -> cache[i] = ( tse *)&invalid_tse;
28839 }
28840#ifdef GC_ASSERTIONS
28841 for (i = 0; i < TS_HASH_SIZE; ++i) {
28842 GC_ASSERT(result -> hash[i].p == 0);
28843 }
28844#endif
28845 *key_ptr = result;
28846 return 0;
28847}
28848GC_INNER int GC_setspecific(tsd * key, void * value)
28849{
28850 pthread_t self = pthread_self();
28851 unsigned hash_val = HASH(self);
28852 volatile tse * entry;
28853 GC_ASSERT(I_HOLD_LOCK());
28854 GC_ASSERT(self != INVALID_THREADID);
28855 GC_dont_gc++;
28856 entry = (volatile tse *)MALLOC_CLEAR(sizeof(tse));
28857 GC_dont_gc--;
28858 if (0 == entry) return ENOMEM;
28859 pthread_mutex_lock(&(key -> lock));
28860 entry -> next = key->hash[hash_val].p;
28861 entry -> thread = self;
28862 entry -> value = TS_HIDE_VALUE(value);
28863 GC_ASSERT(entry -> qtid == INVALID_QTID);
28864 AO_store_release(&key->hash[hash_val].ao, (AO_t)entry);
28865 GC_dirty(( void *)entry);
28866 GC_dirty(key->hash + hash_val);
28867 if (pthread_mutex_unlock(&key->lock) != 0)
28868 ABORT("pthread_mutex_unlock failed (setspecific)");
28869 return 0;
28870}
28871GC_INNER void GC_remove_specific_after_fork(tsd * key, pthread_t t)
28872{
28873 unsigned hash_val = HASH(t);
28874 tse *entry;
28875 tse *prev = NULL;
28876#ifdef CAN_HANDLE_FORK
28877 GC_ASSERT(I_HOLD_LOCK());
28878#endif
28879 pthread_mutex_lock(&(key -> lock));
28880 entry = key->hash[hash_val].p;
28881 while (entry != NULL && !THREAD_EQUAL(entry->thread, t)) {
28882 prev = entry;
28883 entry = entry->next;
28884 }
28885 if (entry != NULL) {
28886 entry -> qtid = INVALID_QTID;
28887 if (NULL == prev) {
28888 key->hash[hash_val].p = entry->next;
28889 GC_dirty(key->hash + hash_val);
28890 } else {
28891 prev->next = entry->next;
28892 GC_dirty(prev);
28893 }
28894 }
28895#ifdef LINT2
28896 GC_noop1((word)entry);
28897#endif
28898 if (pthread_mutex_unlock(&key->lock) != 0)
28899 ABORT("pthread_mutex_unlock failed (remove_specific after fork)");
28900}
28901GC_INNER void * GC_slow_getspecific(tsd * key, word qtid,
28902 tse * volatile * cache_ptr)
28903{
28904 pthread_t self = pthread_self();
28905 tse *entry = key->hash[HASH(self)].p;
28906 GC_ASSERT(qtid != INVALID_QTID);
28907 while (entry != NULL && !THREAD_EQUAL(entry->thread, self)) {
28908 entry = entry -> next;
28909 }
28910 if (entry == NULL) return NULL;
28911 entry -> qtid = (AO_t)qtid;
28912 *cache_ptr = entry;
28913 return TS_REVEAL_PTR(entry -> value);
28914}
28915#ifdef GC_ASSERTIONS
28916 void GC_check_tsd_marks(tsd *key)
28917 {
28918 int i;
28919 tse *p;
28920 if (!GC_is_marked(GC_base(key))) {
28921 ABORT("Unmarked thread-specific-data table");
28922 }
28923 for (i = 0; i < TS_HASH_SIZE; ++i) {
28924 for (p = key->hash[i].p; p != 0; p = p -> next) {
28925 if (!GC_is_marked(GC_base(p))) {
28926 ABORT_ARG1("Unmarked thread-specific-data entry",
28927 " at %p", (void *)p);
28928 }
28929 }
28930 }
28931 for (i = 0; i < TS_CACHE_SIZE; ++i) {
28932 p = key -> cache[i];
28933 if (p != &invalid_tse && !GC_is_marked(GC_base(p))) {
28934 ABORT_ARG1("Unmarked cached thread-specific-data entry",
28935 " at %p", (void *)p);
28936 }
28937 }
28938 }
28939#endif
28940#endif
28941#if defined(GC_WIN32_THREADS)
28942#ifdef THREAD_LOCAL_ALLOC
28943#endif
28944#if !defined(USE_PTHREAD_LOCKS)
28945 GC_INNER CRITICAL_SECTION GC_allocate_ml;
28946#ifdef GC_ASSERTIONS
28947 GC_INNER DWORD GC_lock_holder = NO_THREAD;
28948#endif
28949#else
28950 GC_INNER pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
28951#ifdef GC_ASSERTIONS
28952 GC_INNER unsigned long GC_lock_holder = NO_THREAD;
28953#endif
28954#endif
28955#undef CreateThread
28956#undef ExitThread
28957#undef _beginthreadex
28958#undef _endthreadex
28959#ifdef GC_PTHREADS
28960#include <errno.h>
28961#undef pthread_create
28962#undef pthread_join
28963#undef pthread_detach
28964#ifndef GC_NO_PTHREAD_SIGMASK
28965#undef pthread_sigmask
28966#endif
28967 STATIC void * GC_pthread_start(void * arg);
28968 STATIC void GC_thread_exit_proc(void *arg);
28969#include <pthread.h>
28970#ifdef CAN_CALL_ATFORK
28971#include <unistd.h>
28972#endif
28973#elif !defined(MSWINCE)
28974#include <process.h>
28975#include <errno.h>
28976#endif
28977static ptr_t copy_ptr_regs(word *regs, const CONTEXT *pcontext);
28978#if defined(I386)
28979#ifdef WOW64_THREAD_CONTEXT_WORKAROUND
28980#define PUSHED_REGS_COUNT 9
28981#else
28982#define PUSHED_REGS_COUNT 7
28983#endif
28984#elif defined(X86_64) || defined(SHx)
28985#define PUSHED_REGS_COUNT 15
28986#elif defined(ARM32)
28987#define PUSHED_REGS_COUNT 13
28988#elif defined(AARCH64)
28989#define PUSHED_REGS_COUNT 30
28990#elif defined(MIPS) || defined(ALPHA)
28991#define PUSHED_REGS_COUNT 28
28992#elif defined(PPC)
28993#define PUSHED_REGS_COUNT 29
28994#endif
28995#if (defined(GC_DLL) || defined(GC_INSIDE_DLL)) && !defined(NO_CRT) \
28996 && !defined(GC_NO_THREADS_DISCOVERY) && !defined(MSWINCE) \
28997 && !defined(THREAD_LOCAL_ALLOC) && !defined(GC_PTHREADS)
28998#ifdef GC_DISCOVER_TASK_THREADS
28999#define GC_win32_dll_threads TRUE
29000#else
29001 STATIC GC_bool GC_win32_dll_threads = FALSE;
29002#endif
29003#else
29004#ifndef GC_NO_THREADS_DISCOVERY
29005#define GC_NO_THREADS_DISCOVERY
29006#endif
29007#define GC_win32_dll_threads FALSE
29008#undef MAX_THREADS
29009#define MAX_THREADS 1
29010#endif
29011typedef LONG * IE_t;
29012STATIC GC_bool GC_thr_initialized = FALSE;
29013#ifndef GC_ALWAYS_MULTITHREADED
29014 GC_INNER GC_bool GC_need_to_lock = FALSE;
29015#endif
29016static GC_bool parallel_initialized = FALSE;
29017GC_API void GC_CALL GC_use_threads_discovery(void)
29018{
29019#ifdef GC_NO_THREADS_DISCOVERY
29020 ABORT("GC DllMain-based thread registration unsupported");
29021#else
29022 GC_ASSERT(!parallel_initialized);
29023#ifndef GC_DISCOVER_TASK_THREADS
29024 GC_win32_dll_threads = TRUE;
29025#endif
29026 GC_init_parallel();
29027#endif
29028}
29029#define ADDR_LIMIT ((ptr_t)GC_WORD_MAX)
29030struct GC_Thread_Rep {
29031 union {
29032#ifndef GC_NO_THREADS_DISCOVERY
29033 volatile AO_t in_use;
29034 LONG long_in_use;
29035#endif
29036 struct GC_Thread_Rep * next;
29037 } tm;
29038 DWORD id;
29039#ifdef MSWINCE
29040#define THREAD_HANDLE(t) (HANDLE)(word)(t)->id
29041#else
29042 HANDLE handle;
29043#define THREAD_HANDLE(t) (t)->handle
29044#endif
29045 ptr_t stack_base;
29046 ptr_t last_stack_min;
29047#ifdef IA64
29048 ptr_t backing_store_end;
29049 ptr_t backing_store_ptr;
29050#elif defined(I386)
29051 ptr_t initial_stack_base;
29052#endif
29053 ptr_t thread_blocked_sp;
29054 struct GC_traced_stack_sect_s *traced_stack_sect;
29055 unsigned short finalizer_skipped;
29056 unsigned char finalizer_nested;
29057 unsigned char suspended;
29058#ifdef GC_PTHREADS
29059 unsigned char flags;
29060#define FINISHED 1
29061#define DETACHED 2
29062#define KNOWN_FINISHED(t) (((t) -> flags) & FINISHED)
29063 pthread_t pthread_id;
29064 void *status;
29065#else
29066#define KNOWN_FINISHED(t) 0
29067#endif
29068#ifdef THREAD_LOCAL_ALLOC
29069 struct thread_local_freelists tlfs;
29070#endif
29071#ifdef RETRY_GET_THREAD_CONTEXT
29072 ptr_t context_sp;
29073 word context_regs[PUSHED_REGS_COUNT];
29074#endif
29075};
29076typedef struct GC_Thread_Rep * GC_thread;
29077typedef volatile struct GC_Thread_Rep * GC_vthread;
29078#ifndef GC_NO_THREADS_DISCOVERY
29079 STATIC DWORD GC_main_thread = 0;
29080 STATIC volatile AO_t GC_attached_thread = FALSE;
29081 STATIC volatile GC_bool GC_please_stop = FALSE;
29082#elif defined(GC_ASSERTIONS)
29083 STATIC GC_bool GC_please_stop = FALSE;
29084#endif
29085#if defined(WRAP_MARK_SOME) && !defined(GC_PTHREADS)
29086 GC_INNER GC_bool GC_started_thread_while_stopped(void)
29087 {
29088#ifndef GC_NO_THREADS_DISCOVERY
29089 if (GC_win32_dll_threads) {
29090#ifdef AO_HAVE_compare_and_swap_release
29091 if (AO_compare_and_swap_release(&GC_attached_thread, TRUE,
29092 FALSE ))
29093 return TRUE;
29094#else
29095 AO_nop_full();
29096 if (AO_load(&GC_attached_thread)) {
29097 AO_store(&GC_attached_thread, FALSE);
29098 return TRUE;
29099 }
29100#endif
29101 }
29102#endif
29103 return FALSE;
29104 }
29105#endif
29106#ifndef MAX_THREADS
29107#define MAX_THREADS 512
29108#endif
29109volatile struct GC_Thread_Rep dll_thread_table[MAX_THREADS];
29110STATIC volatile LONG GC_max_thread_index = 0;
29111#ifndef THREAD_TABLE_SZ
29112#define THREAD_TABLE_SZ 256
29113#endif
29114#define THREAD_TABLE_INDEX(id) \
29115 (int)((((id) >> 8) ^ (id)) % THREAD_TABLE_SZ)
29116STATIC GC_thread GC_threads[THREAD_TABLE_SZ];
29117static struct GC_Thread_Rep first_thread;
29118static GC_bool first_thread_used = FALSE;
29119STATIC GC_thread GC_new_thread(DWORD id)
29120{
29121 int hv = THREAD_TABLE_INDEX(id);
29122 GC_thread result;
29123#ifdef DEBUG_THREADS
29124 GC_log_printf("Creating thread 0x%lx\n", (long)id);
29125 if (GC_threads[hv] != NULL)
29126 GC_log_printf("Hash collision at GC_threads[%d]\n", hv);
29127#endif
29128 GC_ASSERT(I_HOLD_LOCK());
29129 if (!EXPECT(first_thread_used, TRUE)) {
29130 result = &first_thread;
29131 first_thread_used = TRUE;
29132 GC_ASSERT(NULL == GC_threads[hv]);
29133 } else {
29134 GC_ASSERT(!GC_win32_dll_threads);
29135 result = (struct GC_Thread_Rep *)
29136 GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep), NORMAL);
29137 if (result == 0) return(0);
29138 }
29139 result -> tm.next = GC_threads[hv];
29140 GC_threads[hv] = result;
29141#ifdef GC_PTHREADS
29142 GC_ASSERT(result -> flags == 0);
29143#endif
29144 GC_ASSERT(result -> thread_blocked_sp == NULL);
29145 if (EXPECT(result != &first_thread, TRUE))
29146 GC_dirty(result);
29147 return(result);
29148}
29149GC_INNER GC_bool GC_in_thread_creation = FALSE;
29150GC_INLINE void GC_record_stack_base(GC_vthread me,
29151 const struct GC_stack_base *sb)
29152{
29153 me -> stack_base = (ptr_t)sb->mem_base;
29154#ifdef IA64
29155 me -> backing_store_end = (ptr_t)sb->reg_base;
29156#elif defined(I386)
29157 me -> initial_stack_base = (ptr_t)sb->mem_base;
29158#endif
29159 if (me -> stack_base == NULL)
29160 ABORT("Bad stack base in GC_register_my_thread");
29161}
29162STATIC GC_thread GC_register_my_thread_inner(const struct GC_stack_base *sb,
29163 DWORD thread_id)
29164{
29165 GC_vthread me;
29166#if defined(MPROTECT_VDB) && !defined(CYGWIN32)
29167 if (GC_auto_incremental
29168#ifdef GWW_VDB
29169 && !GC_gww_dirty_init()
29170#endif
29171 )
29172 GC_set_write_fault_handler();
29173#endif
29174#ifndef GC_NO_THREADS_DISCOVERY
29175 if (GC_win32_dll_threads) {
29176 int i;
29177 for (i = 0;
29178 InterlockedExchange(&dll_thread_table[i].tm.long_in_use, 1) != 0;
29179 i++) {
29180 if (i == MAX_THREADS - 1)
29181 ABORT("Too many threads");
29182 }
29183 while (i > GC_max_thread_index) {
29184 InterlockedIncrement((IE_t)&GC_max_thread_index);
29185 }
29186 if (GC_max_thread_index >= MAX_THREADS) {
29187 GC_max_thread_index = MAX_THREADS - 1;
29188 }
29189 me = dll_thread_table + i;
29190 } else
29191#endif
29192 {
29193 GC_ASSERT(I_HOLD_LOCK());
29194 GC_in_thread_creation = TRUE;
29195 me = GC_new_thread(thread_id);
29196 GC_in_thread_creation = FALSE;
29197 if (me == 0)
29198 ABORT("Failed to allocate memory for thread registering");
29199 }
29200#ifdef GC_PTHREADS
29201 me -> pthread_id = pthread_self();
29202#endif
29203#ifndef MSWINCE
29204 if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
29205 GetCurrentProcess(),
29206 (HANDLE*)&(me -> handle),
29207 0 , FALSE ,
29208 DUPLICATE_SAME_ACCESS)) {
29209 ABORT_ARG1("DuplicateHandle failed",
29210 ": errcode= 0x%X", (unsigned)GetLastError());
29211 }
29212#endif
29213 me -> last_stack_min = ADDR_LIMIT;
29214 GC_record_stack_base(me, sb);
29215 me -> id = thread_id;
29216#if defined(THREAD_LOCAL_ALLOC)
29217 GC_init_thread_local((GC_tlfs)(&(me->tlfs)));
29218#endif
29219#ifndef GC_NO_THREADS_DISCOVERY
29220 if (GC_win32_dll_threads) {
29221 if (GC_please_stop) {
29222 AO_store(&GC_attached_thread, TRUE);
29223 AO_nop_full();
29224 }
29225 } else
29226#endif
29227 {
29228 GC_ASSERT(!GC_please_stop);
29229 }
29230 return (GC_thread)(me);
29231}
29232GC_INLINE LONG GC_get_max_thread_index(void)
29233{
29234 LONG my_max = GC_max_thread_index;
29235 if (my_max >= MAX_THREADS) return MAX_THREADS - 1;
29236 return my_max;
29237}
29238STATIC GC_thread GC_lookup_thread_inner(DWORD thread_id)
29239{
29240#ifndef GC_NO_THREADS_DISCOVERY
29241 if (GC_win32_dll_threads) {
29242 int i;
29243 LONG my_max = GC_get_max_thread_index();
29244 for (i = 0; i <= my_max &&
29245 (!AO_load_acquire(&dll_thread_table[i].tm.in_use)
29246 || dll_thread_table[i].id != thread_id);
29247 i++) {
29248 }
29249 return i <= my_max ? (GC_thread)(dll_thread_table + i) : NULL;
29250 } else
29251#endif
29252 {
29253 GC_thread p = GC_threads[THREAD_TABLE_INDEX(thread_id)];
29254 GC_ASSERT(I_HOLD_LOCK());
29255 while (p != 0 && p -> id != thread_id) p = p -> tm.next;
29256 return(p);
29257 }
29258}
29259#ifdef LINT2
29260#define CHECK_LOOKUP_MY_THREAD(me) \
29261 if (!(me)) ABORT("GC_lookup_thread_inner(GetCurrentThreadId) failed")
29262#else
29263#define CHECK_LOOKUP_MY_THREAD(me)
29264#endif
29265GC_INNER void GC_reset_finalizer_nested(void)
29266{
29267 GC_thread me = GC_lookup_thread_inner(GetCurrentThreadId());
29268 CHECK_LOOKUP_MY_THREAD(me);
29269 me->finalizer_nested = 0;
29270}
29271GC_INNER unsigned char *GC_check_finalizer_nested(void)
29272{
29273 GC_thread me = GC_lookup_thread_inner(GetCurrentThreadId());
29274 unsigned nesting_level;
29275 CHECK_LOOKUP_MY_THREAD(me);
29276 nesting_level = me->finalizer_nested;
29277 if (nesting_level) {
29278 if (++me->finalizer_skipped < (1U << nesting_level)) return NULL;
29279 me->finalizer_skipped = 0;
29280 }
29281 me->finalizer_nested = (unsigned char)(nesting_level + 1);
29282 return &me->finalizer_nested;
29283}
29284#if defined(GC_ASSERTIONS) && defined(THREAD_LOCAL_ALLOC)
29285 GC_bool GC_is_thread_tsd_valid(void *tsd)
29286 {
29287 GC_thread me;
29288 DCL_LOCK_STATE;
29289 LOCK();
29290 me = GC_lookup_thread_inner(GetCurrentThreadId());
29291 UNLOCK();
29292 return (word)tsd >= (word)(&me->tlfs)
29293 && (word)tsd < (word)(&me->tlfs) + sizeof(me->tlfs);
29294 }
29295#endif
29296GC_API int GC_CALL GC_thread_is_registered(void)
29297{
29298 DWORD thread_id = GetCurrentThreadId();
29299 GC_thread me;
29300 DCL_LOCK_STATE;
29301 LOCK();
29302 me = GC_lookup_thread_inner(thread_id);
29303 UNLOCK();
29304 return me != NULL;
29305}
29306GC_API void GC_CALL GC_register_altstack(void *stack GC_ATTR_UNUSED,
29307 GC_word stack_size GC_ATTR_UNUSED,
29308 void *altstack GC_ATTR_UNUSED,
29309 GC_word altstack_size GC_ATTR_UNUSED)
29310{
29311}
29312#if defined(MPROTECT_VDB)
29313#define UNPROTECT_THREAD(t) \
29314 if (!GC_win32_dll_threads && GC_auto_incremental \
29315 && t != &first_thread) { \
29316 GC_ASSERT(SMALL_OBJ(GC_size(t))); \
29317 GC_remove_protection(HBLKPTR(t), 1, FALSE); \
29318 } else (void)0
29319#else
29320#define UNPROTECT_THREAD(t) (void)0
29321#endif
29322#ifdef CYGWIN32
29323#define GC_PTHREAD_PTRVAL(pthread_id) pthread_id
29324#elif defined(GC_WIN32_PTHREADS) || defined(GC_PTHREADS_PARAMARK)
29325#include <pthread.h>
29326#if defined(__WINPTHREADS_VERSION_MAJOR)
29327#define GC_PTHREAD_PTRVAL(pthread_id) pthread_id
29328#else
29329#define GC_PTHREAD_PTRVAL(pthread_id) pthread_id.p
29330#endif
29331#endif
29332STATIC void GC_delete_gc_thread_no_free(GC_vthread t)
29333{
29334#ifndef MSWINCE
29335 CloseHandle(t->handle);
29336#endif
29337#ifndef GC_NO_THREADS_DISCOVERY
29338 if (GC_win32_dll_threads) {
29339 t -> stack_base = 0;
29340 t -> id = 0;
29341 t -> suspended = FALSE;
29342#ifdef RETRY_GET_THREAD_CONTEXT
29343 t -> context_sp = NULL;
29344#endif
29345 AO_store_release(&t->tm.in_use, FALSE);
29346 } else
29347#endif
29348 {
29349 DWORD id = ((GC_thread)t) -> id;
29350 int hv = THREAD_TABLE_INDEX(id);
29351 GC_thread p = GC_threads[hv];
29352 GC_thread prev = NULL;
29353 GC_ASSERT(I_HOLD_LOCK());
29354 while (p != (GC_thread)t) {
29355 prev = p;
29356 p = p -> tm.next;
29357 }
29358 if (prev == 0) {
29359 GC_threads[hv] = p -> tm.next;
29360 } else {
29361 GC_ASSERT(prev != &first_thread);
29362 prev -> tm.next = p -> tm.next;
29363 GC_dirty(prev);
29364 }
29365 }
29366}
29367STATIC void GC_delete_thread(DWORD id)
29368{
29369 if (GC_win32_dll_threads) {
29370 GC_vthread t = GC_lookup_thread_inner(id);
29371 if (0 == t) {
29372 WARN("Removing nonexistent thread, id= %" WARN_PRIdPTR "\n", id);
29373 } else {
29374 GC_delete_gc_thread_no_free(t);
29375 }
29376 } else {
29377 int hv = THREAD_TABLE_INDEX(id);
29378 GC_thread p = GC_threads[hv];
29379 GC_thread prev = NULL;
29380 GC_ASSERT(I_HOLD_LOCK());
29381 while (p -> id != id) {
29382 prev = p;
29383 p = p -> tm.next;
29384 }
29385#ifndef MSWINCE
29386 CloseHandle(p->handle);
29387#endif
29388 if (prev == 0) {
29389 GC_threads[hv] = p -> tm.next;
29390 } else {
29391 GC_ASSERT(prev != &first_thread);
29392 prev -> tm.next = p -> tm.next;
29393 GC_dirty(prev);
29394 }
29395 if (EXPECT(p != &first_thread, TRUE)) {
29396 GC_INTERNAL_FREE(p);
29397 }
29398 }
29399}
29400GC_API void GC_CALL GC_allow_register_threads(void)
29401{
29402 GC_ASSERT(GC_lookup_thread_inner(GetCurrentThreadId()) != 0);
29403#if !defined(GC_ALWAYS_MULTITHREADED) && !defined(PARALLEL_MARK) \
29404 && !defined(GC_NO_THREADS_DISCOVERY)
29405 parallel_initialized = TRUE;
29406#endif
29407 set_need_to_lock();
29408}
29409GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *sb)
29410{
29411 GC_thread me;
29412 DWORD thread_id = GetCurrentThreadId();
29413 DCL_LOCK_STATE;
29414 if (GC_need_to_lock == FALSE)
29415 ABORT("Threads explicit registering is not previously enabled");
29416 LOCK();
29417 me = GC_lookup_thread_inner(thread_id);
29418 if (me == 0) {
29419#ifdef GC_PTHREADS
29420 me = GC_register_my_thread_inner(sb, thread_id);
29421#if defined(CPPCHECK)
29422 GC_noop1(me->flags);
29423#endif
29424 me -> flags |= DETACHED;
29425#else
29426 GC_register_my_thread_inner(sb, thread_id);
29427#endif
29428 UNLOCK();
29429 return GC_SUCCESS;
29430 } else
29431#ifdef GC_PTHREADS
29432 if ((me -> flags & FINISHED) != 0) {
29433 GC_record_stack_base(me, sb);
29434 me -> flags &= ~FINISHED;
29435#ifdef THREAD_LOCAL_ALLOC
29436 GC_init_thread_local((GC_tlfs)(&me->tlfs));
29437#endif
29438 UNLOCK();
29439 return GC_SUCCESS;
29440 } else
29441#endif
29442 {
29443 UNLOCK();
29444 return GC_DUPLICATE;
29445 }
29446}
29447STATIC void GC_wait_for_gc_completion(GC_bool wait_for_all)
29448{
29449 GC_ASSERT(I_HOLD_LOCK());
29450 if (GC_incremental && GC_collection_in_progress()) {
29451 word old_gc_no = GC_gc_no;
29452 do {
29453 ENTER_GC();
29454 GC_in_thread_creation = TRUE;
29455 GC_collect_a_little_inner(1);
29456 GC_in_thread_creation = FALSE;
29457 EXIT_GC();
29458 UNLOCK();
29459 Sleep(0);
29460 LOCK();
29461 } while (GC_incremental && GC_collection_in_progress()
29462 && (wait_for_all || old_gc_no == GC_gc_no));
29463 }
29464}
29465GC_API int GC_CALL GC_unregister_my_thread(void)
29466{
29467 DCL_LOCK_STATE;
29468#ifdef DEBUG_THREADS
29469 GC_log_printf("Unregistering thread 0x%lx\n", (long)GetCurrentThreadId());
29470#endif
29471 if (GC_win32_dll_threads) {
29472#if defined(THREAD_LOCAL_ALLOC)
29473 GC_ASSERT(FALSE);
29474#else
29475 GC_delete_thread(GetCurrentThreadId());
29476#endif
29477 } else {
29478#if defined(THREAD_LOCAL_ALLOC) || defined(GC_PTHREADS)
29479 GC_thread me;
29480#endif
29481 DWORD thread_id = GetCurrentThreadId();
29482 LOCK();
29483 GC_wait_for_gc_completion(FALSE);
29484#if defined(THREAD_LOCAL_ALLOC) || defined(GC_PTHREADS)
29485 me = GC_lookup_thread_inner(thread_id);
29486 CHECK_LOOKUP_MY_THREAD(me);
29487 GC_ASSERT(!KNOWN_FINISHED(me));
29488#endif
29489#if defined(THREAD_LOCAL_ALLOC)
29490 GC_ASSERT(GC_getspecific(GC_thread_key) == &me->tlfs);
29491 GC_destroy_thread_local(&(me->tlfs));
29492#endif
29493#ifdef GC_PTHREADS
29494 if ((me -> flags & DETACHED) == 0) {
29495 me -> flags |= FINISHED;
29496 } else
29497#endif
29498 {
29499 GC_delete_thread(thread_id);
29500 }
29501#if defined(THREAD_LOCAL_ALLOC)
29502 GC_remove_specific(GC_thread_key);
29503#endif
29504 UNLOCK();
29505 }
29506 return GC_SUCCESS;
29507}
29508GC_INNER void GC_do_blocking_inner(ptr_t data, void * context GC_ATTR_UNUSED)
29509{
29510 struct blocking_data * d = (struct blocking_data *) data;
29511 DWORD thread_id = GetCurrentThreadId();
29512 GC_thread me;
29513#ifdef IA64
29514 ptr_t stack_ptr = GC_save_regs_in_stack();
29515#endif
29516 DCL_LOCK_STATE;
29517 LOCK();
29518 me = GC_lookup_thread_inner(thread_id);
29519 CHECK_LOOKUP_MY_THREAD(me);
29520 GC_ASSERT(me -> thread_blocked_sp == NULL);
29521#ifdef IA64
29522 me -> backing_store_ptr = stack_ptr;
29523#endif
29524 me -> thread_blocked_sp = (ptr_t) &d;
29525 UNLOCK();
29526 d -> client_data = (d -> fn)(d -> client_data);
29527 LOCK();
29528#if defined(CPPCHECK)
29529 GC_noop1((word)me->thread_blocked_sp);
29530#endif
29531 me -> thread_blocked_sp = NULL;
29532 UNLOCK();
29533}
29534GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn,
29535 void * client_data)
29536{
29537 struct GC_traced_stack_sect_s stacksect;
29538 DWORD thread_id = GetCurrentThreadId();
29539 GC_thread me;
29540 DCL_LOCK_STATE;
29541 LOCK();
29542 me = GC_lookup_thread_inner(thread_id);
29543 CHECK_LOOKUP_MY_THREAD(me);
29544 GC_ASSERT(me -> stack_base != NULL);
29545 if ((word)me->stack_base < (word)(&stacksect)) {
29546 me -> stack_base = (ptr_t)(&stacksect);
29547#if defined(I386)
29548 me -> initial_stack_base = me -> stack_base;
29549#endif
29550 }
29551 if (me -> thread_blocked_sp == NULL) {
29552 UNLOCK();
29553 client_data = fn(client_data);
29554 GC_noop1(COVERT_DATAFLOW(&stacksect));
29555 return client_data;
29556 }
29557 stacksect.saved_stack_ptr = me -> thread_blocked_sp;
29558#ifdef IA64
29559 stacksect.backing_store_end = GC_save_regs_in_stack();
29560 stacksect.saved_backing_store_ptr = me -> backing_store_ptr;
29561#endif
29562 stacksect.prev = me -> traced_stack_sect;
29563 me -> thread_blocked_sp = NULL;
29564 me -> traced_stack_sect = &stacksect;
29565 UNLOCK();
29566 client_data = fn(client_data);
29567 GC_ASSERT(me -> thread_blocked_sp == NULL);
29568 GC_ASSERT(me -> traced_stack_sect == &stacksect);
29569 LOCK();
29570#if defined(CPPCHECK)
29571 GC_noop1((word)me->traced_stack_sect);
29572#endif
29573 me -> traced_stack_sect = stacksect.prev;
29574#ifdef IA64
29575 me -> backing_store_ptr = stacksect.saved_backing_store_ptr;
29576#endif
29577 me -> thread_blocked_sp = stacksect.saved_stack_ptr;
29578 UNLOCK();
29579 return client_data;
29580}
29581GC_API void GC_CALL GC_set_stackbottom(void *gc_thread_handle,
29582 const struct GC_stack_base *sb)
29583{
29584 GC_thread t = (GC_thread)gc_thread_handle;
29585 GC_ASSERT(sb -> mem_base != NULL);
29586 if (!EXPECT(GC_is_initialized, TRUE)) {
29587 GC_ASSERT(NULL == t);
29588 GC_stackbottom = (char *)sb->mem_base;
29589#ifdef IA64
29590 GC_register_stackbottom = (ptr_t)sb->reg_base;
29591#endif
29592 return;
29593 }
29594 GC_ASSERT(I_HOLD_LOCK());
29595 if (NULL == t) {
29596 t = GC_lookup_thread_inner(GetCurrentThreadId());
29597 CHECK_LOOKUP_MY_THREAD(t);
29598 }
29599 GC_ASSERT(!KNOWN_FINISHED(t));
29600 GC_ASSERT(NULL == t -> thread_blocked_sp
29601 && NULL == t -> traced_stack_sect);
29602 t -> stack_base = (ptr_t)sb->mem_base;
29603 t -> last_stack_min = ADDR_LIMIT;
29604#ifdef IA64
29605 t -> backing_store_end = (ptr_t)sb->reg_base;
29606#endif
29607}
29608GC_API void * GC_CALL GC_get_my_stackbottom(struct GC_stack_base *sb)
29609{
29610 DWORD thread_id = GetCurrentThreadId();
29611 GC_thread me;
29612 DCL_LOCK_STATE;
29613 LOCK();
29614 me = GC_lookup_thread_inner(thread_id);
29615 CHECK_LOOKUP_MY_THREAD(me);
29616 sb -> mem_base = me -> stack_base;
29617#ifdef IA64
29618 sb -> reg_base = me -> backing_store_end;
29619#endif
29620 UNLOCK();
29621 return (void *)me;
29622}
29623#ifdef GC_PTHREADS
29624#define PTHREAD_MAP_SIZE 512
29625 DWORD GC_pthread_map_cache[PTHREAD_MAP_SIZE] = {0};
29626#define PTHREAD_MAP_INDEX(pthread_id) \
29627 ((NUMERIC_THREAD_ID(pthread_id) >> 5) % PTHREAD_MAP_SIZE)
29628#define SET_PTHREAD_MAP_CACHE(pthread_id, win32_id) \
29629 (void)(GC_pthread_map_cache[PTHREAD_MAP_INDEX(pthread_id)] = (win32_id))
29630#define GET_PTHREAD_MAP_CACHE(pthread_id) \
29631 GC_pthread_map_cache[PTHREAD_MAP_INDEX(pthread_id)]
29632 STATIC GC_thread GC_lookup_pthread(pthread_t id)
29633 {
29634#ifndef GC_NO_THREADS_DISCOVERY
29635 if (GC_win32_dll_threads) {
29636 int i;
29637 LONG my_max = GC_get_max_thread_index();
29638 for (i = 0; i <= my_max &&
29639 (!AO_load_acquire(&dll_thread_table[i].tm.in_use)
29640 || THREAD_EQUAL(dll_thread_table[i].pthread_id, id));
29641 i++) {
29642 }
29643 return i <= my_max ? (GC_thread)(dll_thread_table + i) : NULL;
29644 } else
29645#endif
29646 {
29647 DWORD win32_id = GET_PTHREAD_MAP_CACHE(id);
29648 int hv_guess = THREAD_TABLE_INDEX(win32_id);
29649 int hv;
29650 GC_thread p;
29651 DCL_LOCK_STATE;
29652 LOCK();
29653 for (p = GC_threads[hv_guess]; 0 != p; p = p -> tm.next) {
29654 if (THREAD_EQUAL(p -> pthread_id, id))
29655 goto foundit;
29656 }
29657 for (hv = 0; hv < THREAD_TABLE_SZ; ++hv) {
29658 for (p = GC_threads[hv]; 0 != p; p = p -> tm.next) {
29659 if (THREAD_EQUAL(p -> pthread_id, id))
29660 goto foundit;
29661 }
29662 }
29663 p = 0;
29664 foundit:
29665 UNLOCK();
29666 return p;
29667 }
29668 }
29669#endif
29670#ifdef CAN_HANDLE_FORK
29671 STATIC void GC_remove_all_threads_but_me(void)
29672 {
29673 int hv;
29674 GC_thread me = NULL;
29675 DWORD thread_id;
29676 pthread_t pthread_id = pthread_self();
29677 GC_ASSERT(!GC_win32_dll_threads);
29678 for (hv = 0; hv < THREAD_TABLE_SZ; ++hv) {
29679 GC_thread p, next;
29680 for (p = GC_threads[hv]; 0 != p; p = next) {
29681 next = p -> tm.next;
29682 if (THREAD_EQUAL(p -> pthread_id, pthread_id)
29683 && me == NULL) {
29684 me = p;
29685 p -> tm.next = 0;
29686 } else {
29687#ifdef THREAD_LOCAL_ALLOC
29688 if ((p -> flags & FINISHED) == 0) {
29689 GC_remove_specific_after_fork(GC_thread_key, p -> pthread_id);
29690 }
29691#endif
29692 if (&first_thread != p)
29693 GC_INTERNAL_FREE(p);
29694 }
29695 }
29696 GC_threads[hv] = NULL;
29697 }
29698 GC_ASSERT(me != NULL);
29699 thread_id = GetCurrentThreadId();
29700 GC_threads[THREAD_TABLE_INDEX(thread_id)] = me;
29701 me -> id = thread_id;
29702#ifndef MSWINCE
29703 if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
29704 GetCurrentProcess(), (HANDLE *)&me->handle,
29705 0 , FALSE ,
29706 DUPLICATE_SAME_ACCESS))
29707 ABORT("DuplicateHandle failed");
29708#endif
29709#if defined(THREAD_LOCAL_ALLOC) && !defined(USE_CUSTOM_SPECIFIC)
29710 if (GC_setspecific(GC_thread_key, &me->tlfs) != 0)
29711 ABORT("GC_setspecific failed (in child)");
29712#endif
29713 }
29714 static void fork_prepare_proc(void)
29715 {
29716 LOCK();
29717#ifdef PARALLEL_MARK
29718 if (GC_parallel)
29719 GC_wait_for_reclaim();
29720#endif
29721 GC_wait_for_gc_completion(TRUE);
29722#ifdef PARALLEL_MARK
29723 if (GC_parallel)
29724 GC_acquire_mark_lock();
29725#endif
29726 }
29727 static void fork_parent_proc(void)
29728 {
29729#ifdef PARALLEL_MARK
29730 if (GC_parallel)
29731 GC_release_mark_lock();
29732#endif
29733 UNLOCK();
29734 }
29735 static void fork_child_proc(void)
29736 {
29737#ifdef PARALLEL_MARK
29738 if (GC_parallel) {
29739 GC_release_mark_lock();
29740 GC_parallel = FALSE;
29741 }
29742#endif
29743 GC_remove_all_threads_but_me();
29744 UNLOCK();
29745 }
29746 GC_API void GC_CALL GC_atfork_prepare(void)
29747 {
29748 if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
29749 if (GC_handle_fork <= 0)
29750 fork_prepare_proc();
29751 }
29752 GC_API void GC_CALL GC_atfork_parent(void)
29753 {
29754 if (GC_handle_fork <= 0)
29755 fork_parent_proc();
29756 }
29757 GC_API void GC_CALL GC_atfork_child(void)
29758 {
29759 if (GC_handle_fork <= 0)
29760 fork_child_proc();
29761 }
29762#endif
29763void GC_push_thread_structures(void)
29764{
29765 GC_ASSERT(I_HOLD_LOCK());
29766#ifndef GC_NO_THREADS_DISCOVERY
29767 if (GC_win32_dll_threads) {
29768 } else
29769#endif
29770 {
29771 GC_PUSH_ALL_SYM(GC_threads);
29772 }
29773#if defined(THREAD_LOCAL_ALLOC)
29774 GC_PUSH_ALL_SYM(GC_thread_key);
29775#endif
29776}
29777#ifdef WOW64_THREAD_CONTEXT_WORKAROUND
29778#ifndef CONTEXT_EXCEPTION_ACTIVE
29779#define CONTEXT_EXCEPTION_ACTIVE 0x08000000
29780#define CONTEXT_EXCEPTION_REQUEST 0x40000000
29781#define CONTEXT_EXCEPTION_REPORTING 0x80000000
29782#endif
29783 static BOOL isWow64;
29784#define GET_THREAD_CONTEXT_FLAGS (isWow64 \
29785 ? CONTEXT_INTEGER | CONTEXT_CONTROL \
29786 | CONTEXT_EXCEPTION_REQUEST | CONTEXT_SEGMENTS \
29787 : CONTEXT_INTEGER | CONTEXT_CONTROL)
29788#else
29789#define GET_THREAD_CONTEXT_FLAGS (CONTEXT_INTEGER | CONTEXT_CONTROL)
29790#endif
29791STATIC void GC_suspend(GC_thread t)
29792{
29793#ifndef MSWINCE
29794 DWORD exitCode;
29795#ifdef RETRY_GET_THREAD_CONTEXT
29796 int retry_cnt;
29797#define MAX_SUSPEND_THREAD_RETRIES (1000 * 1000)
29798#endif
29799#endif
29800#ifdef DEBUG_THREADS
29801 GC_log_printf("Suspending 0x%x\n", (int)t->id);
29802#endif
29803 UNPROTECT_THREAD(t);
29804 GC_acquire_dirty_lock();
29805#ifdef MSWINCE
29806 while (SuspendThread(THREAD_HANDLE(t)) == (DWORD)-1) {
29807 GC_release_dirty_lock();
29808 Sleep(10);
29809 GC_acquire_dirty_lock();
29810 }
29811#elif defined(RETRY_GET_THREAD_CONTEXT)
29812 for (retry_cnt = 0;;) {
29813 if (GetExitCodeThread(t -> handle, &exitCode)
29814 && exitCode != STILL_ACTIVE) {
29815 GC_release_dirty_lock();
29816#ifdef GC_PTHREADS
29817 t -> stack_base = 0;
29818#else
29819 GC_ASSERT(GC_win32_dll_threads);
29820 GC_delete_gc_thread_no_free(t);
29821#endif
29822 return;
29823 }
29824 if (SuspendThread(t->handle) != (DWORD)-1) {
29825 CONTEXT context;
29826 context.ContextFlags = GET_THREAD_CONTEXT_FLAGS;
29827 if (GetThreadContext(t->handle, &context)) {
29828 t->context_sp = copy_ptr_regs(t->context_regs, &context);
29829 break;
29830 }
29831 if (ResumeThread(t->handle) == (DWORD)-1)
29832 ABORT("ResumeThread failed in suspend loop");
29833 }
29834 if (retry_cnt > 1) {
29835 GC_release_dirty_lock();
29836 Sleep(0);
29837 GC_acquire_dirty_lock();
29838 }
29839 if (++retry_cnt >= MAX_SUSPEND_THREAD_RETRIES)
29840 ABORT("SuspendThread loop failed");
29841 }
29842#else
29843 if (GetExitCodeThread(t -> handle, &exitCode)
29844 && exitCode != STILL_ACTIVE) {
29845 GC_release_dirty_lock();
29846#ifdef GC_PTHREADS
29847 t -> stack_base = 0;
29848#else
29849 GC_ASSERT(GC_win32_dll_threads);
29850 GC_delete_gc_thread_no_free(t);
29851#endif
29852 return;
29853 }
29854 if (SuspendThread(t -> handle) == (DWORD)-1)
29855 ABORT("SuspendThread failed");
29856#endif
29857 t -> suspended = (unsigned char)TRUE;
29858 GC_release_dirty_lock();
29859 if (GC_on_thread_event)
29860 GC_on_thread_event(GC_EVENT_THREAD_SUSPENDED, THREAD_HANDLE(t));
29861}
29862#if defined(GC_ASSERTIONS) \
29863 && ((defined(MSWIN32) && !defined(CONSOLE_LOG)) || defined(MSWINCE))
29864 GC_INNER GC_bool GC_write_disabled = FALSE;
29865#endif
29866GC_INNER void GC_stop_world(void)
29867{
29868 DWORD thread_id = GetCurrentThreadId();
29869 if (!GC_thr_initialized)
29870 ABORT("GC_stop_world() called before GC_thr_init()");
29871 GC_ASSERT(I_HOLD_LOCK());
29872#ifdef PARALLEL_MARK
29873 if (GC_parallel) {
29874 GC_acquire_mark_lock();
29875 GC_ASSERT(GC_fl_builder_count == 0);
29876 }
29877#endif
29878#if !defined(GC_NO_THREADS_DISCOVERY) || defined(GC_ASSERTIONS)
29879 GC_please_stop = TRUE;
29880#endif
29881#if (defined(MSWIN32) && !defined(CONSOLE_LOG)) || defined(MSWINCE)
29882 GC_ASSERT(!GC_write_disabled);
29883 EnterCriticalSection(&GC_write_cs);
29884#ifdef GC_ASSERTIONS
29885 GC_write_disabled = TRUE;
29886#endif
29887#endif
29888#ifndef GC_NO_THREADS_DISCOVERY
29889 if (GC_win32_dll_threads) {
29890 int i;
29891 int my_max;
29892 AO_store(&GC_attached_thread, FALSE);
29893 my_max = (int)GC_get_max_thread_index();
29894 for (i = 0; i <= my_max; i++) {
29895 GC_vthread t = dll_thread_table + i;
29896 if (t -> stack_base != 0 && t -> thread_blocked_sp == NULL
29897 && t -> id != thread_id) {
29898 GC_suspend((GC_thread)t);
29899 }
29900 }
29901 } else
29902#endif
29903 {
29904 GC_thread t;
29905 int i;
29906 for (i = 0; i < THREAD_TABLE_SZ; i++) {
29907 for (t = GC_threads[i]; t != 0; t = t -> tm.next) {
29908 if (t -> stack_base != 0 && t -> thread_blocked_sp == NULL
29909 && !KNOWN_FINISHED(t) && t -> id != thread_id) {
29910 GC_suspend(t);
29911 }
29912 }
29913 }
29914 }
29915#if (defined(MSWIN32) && !defined(CONSOLE_LOG)) || defined(MSWINCE)
29916#ifdef GC_ASSERTIONS
29917 GC_write_disabled = FALSE;
29918#endif
29919 LeaveCriticalSection(&GC_write_cs);
29920#endif
29921#ifdef PARALLEL_MARK
29922 if (GC_parallel)
29923 GC_release_mark_lock();
29924#endif
29925}
29926GC_INNER void GC_start_world(void)
29927{
29928#ifdef GC_ASSERTIONS
29929 DWORD thread_id = GetCurrentThreadId();
29930#endif
29931 GC_ASSERT(I_HOLD_LOCK());
29932 if (GC_win32_dll_threads) {
29933 LONG my_max = GC_get_max_thread_index();
29934 int i;
29935 for (i = 0; i <= my_max; i++) {
29936 GC_thread t = (GC_thread)(dll_thread_table + i);
29937 if (t -> suspended) {
29938#ifdef DEBUG_THREADS
29939 GC_log_printf("Resuming 0x%x\n", (int)t->id);
29940#endif
29941 GC_ASSERT(t -> stack_base != 0 && t -> id != thread_id);
29942 if (ResumeThread(THREAD_HANDLE(t)) == (DWORD)-1)
29943 ABORT("ResumeThread failed");
29944 t -> suspended = FALSE;
29945 if (GC_on_thread_event)
29946 GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED, THREAD_HANDLE(t));
29947 }
29948 }
29949 } else {
29950 GC_thread t;
29951 int i;
29952 for (i = 0; i < THREAD_TABLE_SZ; i++) {
29953 for (t = GC_threads[i]; t != 0; t = t -> tm.next) {
29954 if (t -> suspended) {
29955#ifdef DEBUG_THREADS
29956 GC_log_printf("Resuming 0x%x\n", (int)t->id);
29957#endif
29958 GC_ASSERT(t -> stack_base != 0 && t -> id != thread_id);
29959 if (ResumeThread(THREAD_HANDLE(t)) == (DWORD)-1)
29960 ABORT("ResumeThread failed");
29961 UNPROTECT_THREAD(t);
29962 t -> suspended = FALSE;
29963 if (GC_on_thread_event)
29964 GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED, THREAD_HANDLE(t));
29965 } else {
29966#ifdef DEBUG_THREADS
29967 GC_log_printf("Not resuming thread 0x%x as it is not suspended\n",
29968 (int)t->id);
29969#endif
29970 }
29971 }
29972 }
29973 }
29974#if !defined(GC_NO_THREADS_DISCOVERY) || defined(GC_ASSERTIONS)
29975 GC_please_stop = FALSE;
29976#endif
29977}
29978#ifdef MSWINCE
29979#define GC_wince_evaluate_stack_min(s) \
29980 (ptr_t)(((word)(s) - 1) & ~(word)0xFFFF)
29981#elif defined(GC_ASSERTIONS)
29982#define GC_dont_query_stack_min FALSE
29983#endif
29984static ptr_t last_address = 0;
29985static MEMORY_BASIC_INFORMATION last_info;
29986STATIC ptr_t GC_get_stack_min(ptr_t s)
29987{
29988 ptr_t bottom;
29989 GC_ASSERT(I_HOLD_LOCK());
29990 if (s != last_address) {
29991 VirtualQuery(s, &last_info, sizeof(last_info));
29992 last_address = s;
29993 }
29994 do {
29995 bottom = (ptr_t)last_info.BaseAddress;
29996 VirtualQuery(bottom - 1, &last_info, sizeof(last_info));
29997 last_address = bottom - 1;
29998 } while ((last_info.Protect & PAGE_READWRITE)
29999 && !(last_info.Protect & PAGE_GUARD));
30000 return(bottom);
30001}
30002static GC_bool may_be_in_stack(ptr_t s)
30003{
30004 GC_ASSERT(I_HOLD_LOCK());
30005 if (s != last_address) {
30006 VirtualQuery(s, &last_info, sizeof(last_info));
30007 last_address = s;
30008 }
30009 return (last_info.Protect & PAGE_READWRITE)
30010 && !(last_info.Protect & PAGE_GUARD);
30011}
30012static ptr_t copy_ptr_regs(word *regs, const CONTEXT *pcontext) {
30013 ptr_t sp;
30014 int cnt = 0;
30015#define context (*pcontext)
30016#define PUSH1(reg) (regs[cnt++] = (word)pcontext->reg)
30017#define PUSH2(r1,r2) (PUSH1(r1), PUSH1(r2))
30018#define PUSH4(r1,r2,r3,r4) (PUSH2(r1,r2), PUSH2(r3,r4))
30019#if defined(I386)
30020#ifdef WOW64_THREAD_CONTEXT_WORKAROUND
30021 PUSH2(ContextFlags, SegFs);
30022#endif
30023 PUSH4(Edi,Esi,Ebx,Edx), PUSH2(Ecx,Eax), PUSH1(Ebp);
30024 sp = (ptr_t)context.Esp;
30025#elif defined(X86_64)
30026 PUSH4(Rax,Rcx,Rdx,Rbx); PUSH2(Rbp, Rsi); PUSH1(Rdi);
30027 PUSH4(R8, R9, R10, R11); PUSH4(R12, R13, R14, R15);
30028 sp = (ptr_t)context.Rsp;
30029#elif defined(ARM32)
30030 PUSH4(R0,R1,R2,R3),PUSH4(R4,R5,R6,R7),PUSH4(R8,R9,R10,R11);
30031 PUSH1(R12);
30032 sp = (ptr_t)context.Sp;
30033#elif defined(AARCH64)
30034 PUSH4(X0,X1,X2,X3),PUSH4(X4,X5,X6,X7),PUSH4(X8,X9,X10,X11);
30035 PUSH4(X12,X13,X14,X15),PUSH4(X16,X17,X18,X19),PUSH4(X20,X21,X22,X23);
30036 PUSH4(X24,X25,X26,X27),PUSH1(X28);
30037 PUSH1(Lr);
30038 sp = (ptr_t)context.Sp;
30039#elif defined(SHx)
30040 PUSH4(R0,R1,R2,R3), PUSH4(R4,R5,R6,R7), PUSH4(R8,R9,R10,R11);
30041 PUSH2(R12,R13), PUSH1(R14);
30042 sp = (ptr_t)context.R15;
30043#elif defined(MIPS)
30044 PUSH4(IntAt,IntV0,IntV1,IntA0), PUSH4(IntA1,IntA2,IntA3,IntT0);
30045 PUSH4(IntT1,IntT2,IntT3,IntT4), PUSH4(IntT5,IntT6,IntT7,IntS0);
30046 PUSH4(IntS1,IntS2,IntS3,IntS4), PUSH4(IntS5,IntS6,IntS7,IntT8);
30047 PUSH4(IntT9,IntK0,IntK1,IntS8);
30048 sp = (ptr_t)context.IntSp;
30049#elif defined(PPC)
30050 PUSH4(Gpr0, Gpr3, Gpr4, Gpr5), PUSH4(Gpr6, Gpr7, Gpr8, Gpr9);
30051 PUSH4(Gpr10,Gpr11,Gpr12,Gpr14), PUSH4(Gpr15,Gpr16,Gpr17,Gpr18);
30052 PUSH4(Gpr19,Gpr20,Gpr21,Gpr22), PUSH4(Gpr23,Gpr24,Gpr25,Gpr26);
30053 PUSH4(Gpr27,Gpr28,Gpr29,Gpr30), PUSH1(Gpr31);
30054 sp = (ptr_t)context.Gpr1;
30055#elif defined(ALPHA)
30056 PUSH4(IntV0,IntT0,IntT1,IntT2), PUSH4(IntT3,IntT4,IntT5,IntT6);
30057 PUSH4(IntT7,IntS0,IntS1,IntS2), PUSH4(IntS3,IntS4,IntS5,IntFp);
30058 PUSH4(IntA0,IntA1,IntA2,IntA3), PUSH4(IntA4,IntA5,IntT8,IntT9);
30059 PUSH4(IntT10,IntT11,IntT12,IntAt);
30060 sp = (ptr_t)context.IntSp;
30061#elif defined(CPPCHECK)
30062 sp = (ptr_t)(word)cnt;
30063#else
30064#error Architecture is not supported
30065#endif
30066#undef context
30067 GC_ASSERT(cnt == PUSHED_REGS_COUNT);
30068 return sp;
30069}
30070STATIC word GC_push_stack_for(GC_thread thread, DWORD me)
30071{
30072 ptr_t sp, stack_min;
30073 struct GC_traced_stack_sect_s *traced_stack_sect =
30074 thread -> traced_stack_sect;
30075 if (thread -> id == me) {
30076 GC_ASSERT(thread -> thread_blocked_sp == NULL);
30077 sp = GC_approx_sp();
30078 } else if ((sp = thread -> thread_blocked_sp) == NULL) {
30079#ifdef RETRY_GET_THREAD_CONTEXT
30080 word *regs = thread->context_regs;
30081 if (thread->suspended) {
30082 sp = thread->context_sp;
30083 } else
30084#else
30085 word regs[PUSHED_REGS_COUNT];
30086#endif
30087 {
30088 CONTEXT context;
30089 context.ContextFlags = GET_THREAD_CONTEXT_FLAGS;
30090 if (GetThreadContext(THREAD_HANDLE(thread), &context)) {
30091 sp = copy_ptr_regs(regs, &context);
30092 } else {
30093#ifdef RETRY_GET_THREAD_CONTEXT
30094 sp = thread->context_sp;
30095 if (NULL == sp) {
30096 return 0;
30097 }
30098#else
30099 ABORT("GetThreadContext failed");
30100#endif
30101 }
30102 }
30103#ifdef THREAD_LOCAL_ALLOC
30104 GC_ASSERT(thread->suspended || !GC_world_stopped);
30105#endif
30106#ifndef WOW64_THREAD_CONTEXT_WORKAROUND
30107 GC_push_many_regs(regs, PUSHED_REGS_COUNT);
30108#else
30109 GC_push_many_regs(regs + 2, PUSHED_REGS_COUNT - 2);
30110 if (isWow64) {
30111 DWORD ContextFlags = (DWORD)regs[0];
30112 WORD SegFs = (WORD)regs[1];
30113 if ((ContextFlags & CONTEXT_EXCEPTION_REPORTING) != 0
30114 && (ContextFlags & (CONTEXT_EXCEPTION_ACTIVE
30115 )) != 0) {
30116 LDT_ENTRY selector;
30117 PNT_TIB tib;
30118 if (!GetThreadSelectorEntry(THREAD_HANDLE(thread), SegFs, &selector))
30119 ABORT("GetThreadSelectorEntry failed");
30120 tib = (PNT_TIB)(selector.BaseLow
30121 | (selector.HighWord.Bits.BaseMid << 16)
30122 | (selector.HighWord.Bits.BaseHi << 24));
30123#ifdef DEBUG_THREADS
30124 GC_log_printf("TIB stack limit/base: %p .. %p\n",
30125 (void *)tib->StackLimit, (void *)tib->StackBase);
30126#endif
30127 GC_ASSERT(!((word)thread->stack_base
30128 COOLER_THAN (word)tib->StackBase));
30129 if (thread->stack_base != thread->initial_stack_base
30130 && ((word)thread->stack_base <= (word)tib->StackLimit
30131 || (word)tib->StackBase < (word)thread->stack_base)) {
30132 WARN("GetThreadContext might return stale register values"
30133 " including ESP= %p\n", sp);
30134 } else {
30135 sp = (ptr_t)tib->StackLimit;
30136 }
30137 }
30138#ifdef DEBUG_THREADS
30139 else {
30140 static GC_bool logged;
30141 if (!logged
30142 && (ContextFlags & CONTEXT_EXCEPTION_REPORTING) == 0) {
30143 GC_log_printf("CONTEXT_EXCEPTION_REQUEST not supported\n");
30144 logged = TRUE;
30145 }
30146 }
30147#endif
30148 }
30149#endif
30150 }
30151 if (thread -> last_stack_min == ADDR_LIMIT) {
30152#ifdef MSWINCE
30153 if (GC_dont_query_stack_min) {
30154 stack_min = GC_wince_evaluate_stack_min(traced_stack_sect != NULL ?
30155 (ptr_t)traced_stack_sect : thread -> stack_base);
30156 } else
30157#endif
30158 {
30159 stack_min = GC_get_stack_min(traced_stack_sect != NULL ?
30160 (ptr_t)traced_stack_sect : thread -> stack_base);
30161 UNPROTECT_THREAD(thread);
30162 thread -> last_stack_min = stack_min;
30163 }
30164 } else {
30165 if (traced_stack_sect != NULL &&
30166 (word)thread->last_stack_min > (word)traced_stack_sect) {
30167 UNPROTECT_THREAD(thread);
30168 thread -> last_stack_min = (ptr_t)traced_stack_sect;
30169 }
30170 if ((word)sp < (word)thread->stack_base
30171 && (word)sp >= (word)thread->last_stack_min) {
30172 stack_min = sp;
30173 } else {
30174 if (may_be_in_stack(thread -> id == me &&
30175 (word)sp < (word)thread->last_stack_min ?
30176 sp : thread -> last_stack_min)) {
30177 stack_min = (ptr_t)last_info.BaseAddress;
30178 if ((word)sp < (word)stack_min
30179 || (word)sp >= (word)thread->stack_base)
30180 stack_min = GC_get_stack_min(thread -> last_stack_min);
30181 } else {
30182 stack_min = GC_get_stack_min(thread -> stack_base);
30183 }
30184 UNPROTECT_THREAD(thread);
30185 thread -> last_stack_min = stack_min;
30186 }
30187 }
30188 GC_ASSERT(GC_dont_query_stack_min
30189 || stack_min == GC_get_stack_min(thread -> stack_base)
30190 || ((word)sp >= (word)stack_min
30191 && (word)stack_min < (word)thread->stack_base
30192 && (word)stack_min
30193 > (word)GC_get_stack_min(thread -> stack_base)));
30194 if ((word)sp >= (word)stack_min && (word)sp < (word)thread->stack_base) {
30195#ifdef DEBUG_THREADS
30196 GC_log_printf("Pushing stack for 0x%x from sp %p to %p from 0x%x\n",
30197 (int)thread->id, (void *)sp, (void *)thread->stack_base,
30198 (int)me);
30199#endif
30200 GC_push_all_stack_sections(sp, thread->stack_base, traced_stack_sect);
30201 } else {
30202 if (thread -> id == me || (word)sp >= (word)thread->stack_base
30203 || (word)(sp + GC_page_size) < (word)stack_min)
30204 WARN("Thread stack pointer %p out of range, pushing everything\n",
30205 sp);
30206#ifdef DEBUG_THREADS
30207 GC_log_printf("Pushing stack for 0x%x from (min) %p to %p from 0x%x\n",
30208 (int)thread->id, (void *)stack_min,
30209 (void *)thread->stack_base, (int)me);
30210#endif
30211 GC_push_all_stack(stack_min, thread->stack_base);
30212 }
30213 return thread->stack_base - sp;
30214}
30215GC_INNER void GC_push_all_stacks(void)
30216{
30217 DWORD thread_id = GetCurrentThreadId();
30218 GC_bool found_me = FALSE;
30219#ifndef SMALL_CONFIG
30220 unsigned nthreads = 0;
30221#endif
30222 word total_size = 0;
30223#ifndef GC_NO_THREADS_DISCOVERY
30224 if (GC_win32_dll_threads) {
30225 int i;
30226 LONG my_max = GC_get_max_thread_index();
30227 for (i = 0; i <= my_max; i++) {
30228 GC_thread t = (GC_thread)(dll_thread_table + i);
30229 if (t -> tm.in_use && t -> stack_base) {
30230#ifndef SMALL_CONFIG
30231 ++nthreads;
30232#endif
30233 total_size += GC_push_stack_for(t, thread_id);
30234 if (t -> id == thread_id) found_me = TRUE;
30235 }
30236 }
30237 } else
30238#endif
30239 {
30240 int i;
30241 for (i = 0; i < THREAD_TABLE_SZ; i++) {
30242 GC_thread t;
30243 for (t = GC_threads[i]; t != 0; t = t -> tm.next) {
30244 if (!KNOWN_FINISHED(t) && t -> stack_base) {
30245#ifndef SMALL_CONFIG
30246 ++nthreads;
30247#endif
30248 total_size += GC_push_stack_for(t, thread_id);
30249 if (t -> id == thread_id) found_me = TRUE;
30250 }
30251 }
30252 }
30253 }
30254#ifndef SMALL_CONFIG
30255 GC_VERBOSE_LOG_PRINTF("Pushed %d thread stacks%s\n", nthreads,
30256 GC_win32_dll_threads ?
30257 " based on DllMain thread tracking" : "");
30258#endif
30259 if (!found_me && !GC_in_thread_creation)
30260 ABORT("Collecting from unknown thread");
30261 GC_total_stacksize = total_size;
30262}
30263#ifdef PARALLEL_MARK
30264#ifndef MAX_MARKERS
30265#define MAX_MARKERS 16
30266#endif
30267 static ptr_t marker_sp[MAX_MARKERS - 1];
30268#ifdef IA64
30269 static ptr_t marker_bsp[MAX_MARKERS - 1];
30270#endif
30271 static ptr_t marker_last_stack_min[MAX_MARKERS - 1];
30272#endif
30273GC_INNER void GC_get_next_stack(char *start, char *limit,
30274 char **lo, char **hi)
30275{
30276 int i;
30277 char * current_min = ADDR_LIMIT;
30278 ptr_t *plast_stack_min = NULL;
30279 GC_thread thread = NULL;
30280 if (GC_win32_dll_threads) {
30281 LONG my_max = GC_get_max_thread_index();
30282 for (i = 0; i <= my_max; i++) {
30283 ptr_t s = (ptr_t)(dll_thread_table[i].stack_base);
30284 if ((word)s > (word)start && (word)s < (word)current_min) {
30285 plast_stack_min = (ptr_t * )
30286 &dll_thread_table[i].last_stack_min;
30287 current_min = s;
30288#if defined(CPPCHECK)
30289 thread = (GC_thread)&dll_thread_table[i];
30290#endif
30291 }
30292 }
30293 } else {
30294 for (i = 0; i < THREAD_TABLE_SZ; i++) {
30295 GC_thread t;
30296 for (t = GC_threads[i]; t != 0; t = t -> tm.next) {
30297 ptr_t s = t -> stack_base;
30298 if ((word)s > (word)start && (word)s < (word)current_min) {
30299 plast_stack_min = &t -> last_stack_min;
30300 thread = t;
30301 current_min = s;
30302 }
30303 }
30304 }
30305#ifdef PARALLEL_MARK
30306 for (i = 0; i < GC_markers_m1; ++i) {
30307 ptr_t s = marker_sp[i];
30308#ifdef IA64
30309#endif
30310 if ((word)s > (word)start && (word)s < (word)current_min) {
30311 GC_ASSERT(marker_last_stack_min[i] != NULL);
30312 plast_stack_min = &marker_last_stack_min[i];
30313 current_min = s;
30314 thread = NULL;
30315 }
30316 }
30317#endif
30318 }
30319 *hi = current_min;
30320 if (current_min == ADDR_LIMIT) {
30321 *lo = ADDR_LIMIT;
30322 return;
30323 }
30324 GC_ASSERT((word)current_min > (word)start && plast_stack_min != NULL);
30325#ifdef MSWINCE
30326 if (GC_dont_query_stack_min) {
30327 *lo = GC_wince_evaluate_stack_min(current_min);
30328 return;
30329 }
30330#endif
30331 if ((word)current_min > (word)limit && !may_be_in_stack(limit)) {
30332 *lo = ADDR_LIMIT;
30333 return;
30334 }
30335 if (*plast_stack_min == ADDR_LIMIT
30336 || !may_be_in_stack(*plast_stack_min)) {
30337 *lo = GC_get_stack_min(current_min);
30338 } else {
30339 *lo = GC_get_stack_min(*plast_stack_min);
30340 }
30341 if (thread != NULL) {
30342 UNPROTECT_THREAD(thread);
30343 }
30344 *plast_stack_min = *lo;
30345}
30346#ifdef PARALLEL_MARK
30347#if defined(GC_PTHREADS) && !defined(GC_PTHREADS_PARAMARK)
30348#if !defined(__MINGW32__)
30349#define GC_PTHREADS_PARAMARK
30350#endif
30351#endif
30352#if !defined(GC_PTHREADS_PARAMARK)
30353 STATIC HANDLE GC_marker_cv[MAX_MARKERS - 1] = {0};
30354 STATIC DWORD GC_marker_Id[MAX_MARKERS - 1] = {0};
30355#endif
30356#if defined(GC_PTHREADS) && defined(HAVE_PTHREAD_SETNAME_NP_WITH_TID)
30357 static void set_marker_thread_name(unsigned id)
30358 {
30359 char name_buf[16];
30360 int len = sizeof("GC-marker-") - 1;
30361 BCOPY("GC-marker-", name_buf, len);
30362 if (id >= 10)
30363 name_buf[len++] = (char)('0' + (id / 10) % 10);
30364 name_buf[len] = (char)('0' + id % 10);
30365 name_buf[len + 1] = '\0';
30366 if (pthread_setname_np(pthread_self(), name_buf) != 0)
30367 WARN("pthread_setname_np failed\n", 0);
30368 }
30369#elif !defined(MSWINCE)
30370 static FARPROC setThreadDescription_fn;
30371 static void set_marker_thread_name(unsigned id)
30372 {
30373 WCHAR name_buf[16];
30374 int len = sizeof(L"GC-marker-") / sizeof(WCHAR) - 1;
30375 HRESULT hr;
30376 if (!setThreadDescription_fn) return;
30377 BCOPY(L"GC-marker-", name_buf, len * sizeof(WCHAR));
30378 if (id >= 10)
30379 name_buf[len++] = (WCHAR)('0' + (id / 10) % 10);
30380 name_buf[len] = (WCHAR)('0' + id % 10);
30381 name_buf[len + 1] = 0;
30382 hr = (*(HRESULT (WINAPI *)(HANDLE, const WCHAR *))
30383 (word)setThreadDescription_fn)(GetCurrentThread(), name_buf);
30384 if (FAILED(hr))
30385 WARN("SetThreadDescription failed\n", 0);
30386 }
30387#else
30388#define set_marker_thread_name(id) (void)(id)
30389#endif
30390#ifdef GC_PTHREADS_PARAMARK
30391 STATIC void * GC_mark_thread(void * id)
30392#elif defined(MSWINCE)
30393 STATIC DWORD WINAPI GC_mark_thread(LPVOID id)
30394#else
30395 STATIC unsigned __stdcall GC_mark_thread(void * id)
30396#endif
30397 {
30398 word my_mark_no = 0;
30399 if ((word)id == GC_WORD_MAX) return 0;
30400 set_marker_thread_name((unsigned)(word)id);
30401 marker_sp[(word)id] = GC_approx_sp();
30402#ifdef IA64
30403 marker_bsp[(word)id] = GC_save_regs_in_stack();
30404#endif
30405#if !defined(GC_PTHREADS_PARAMARK)
30406 GC_marker_Id[(word)id] = GetCurrentThreadId();
30407#endif
30408 GC_acquire_mark_lock();
30409 if (0 == --GC_fl_builder_count)
30410 GC_notify_all_builder();
30411 for (;; ++my_mark_no) {
30412 if (my_mark_no - GC_mark_no > (word)2) {
30413 my_mark_no = GC_mark_no;
30414 }
30415#ifdef DEBUG_THREADS
30416 GC_log_printf("Starting mark helper for mark number %lu\n",
30417 (unsigned long)my_mark_no);
30418#endif
30419 GC_help_marker(my_mark_no);
30420 }
30421 }
30422#ifndef GC_ASSERTIONS
30423#define SET_MARK_LOCK_HOLDER (void)0
30424#define UNSET_MARK_LOCK_HOLDER (void)0
30425#endif
30426#ifdef CAN_HANDLE_FORK
30427 static int available_markers_m1 = 0;
30428#else
30429#define available_markers_m1 GC_markers_m1
30430#endif
30431#ifdef GC_PTHREADS_PARAMARK
30432#include <pthread.h>
30433#if defined(GC_ASSERTIONS) && !defined(NUMERIC_THREAD_ID)
30434#define NUMERIC_THREAD_ID(id) (unsigned long)(word)GC_PTHREAD_PTRVAL(id)
30435#endif
30436#ifdef CAN_HANDLE_FORK
30437 static pthread_cond_t mark_cv;
30438#else
30439 static pthread_cond_t mark_cv = PTHREAD_COND_INITIALIZER;
30440#endif
30441 GC_INNER void GC_start_mark_threads_inner(void)
30442 {
30443 int i;
30444 pthread_attr_t attr;
30445 pthread_t new_thread;
30446#ifndef NO_MARKER_SPECIAL_SIGMASK
30447 sigset_t set, oldset;
30448#endif
30449 GC_ASSERT(I_DONT_HOLD_LOCK());
30450 if (available_markers_m1 <= 0) return;
30451#ifdef CAN_HANDLE_FORK
30452 if (GC_parallel) return;
30453 {
30454 pthread_cond_t mark_cv_local = PTHREAD_COND_INITIALIZER;
30455 BCOPY(&mark_cv_local, &mark_cv, sizeof(mark_cv));
30456 }
30457#endif
30458 GC_ASSERT(GC_fl_builder_count == 0);
30459 if (0 != pthread_attr_init(&attr)) ABORT("pthread_attr_init failed");
30460 if (0 != pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))
30461 ABORT("pthread_attr_setdetachstate failed");
30462#ifndef NO_MARKER_SPECIAL_SIGMASK
30463 if (sigfillset(&set) != 0)
30464 ABORT("sigfillset failed");
30465 if (pthread_sigmask(SIG_BLOCK, &set, &oldset) < 0) {
30466 WARN("pthread_sigmask set failed, no markers started,"
30467 " errno= %" WARN_PRIdPTR "\n", errno);
30468 GC_markers_m1 = 0;
30469 (void)pthread_attr_destroy(&attr);
30470 return;
30471 }
30472#endif
30473#ifdef CAN_HANDLE_FORK
30474 GC_markers_m1 = available_markers_m1;
30475#endif
30476 for (i = 0; i < available_markers_m1; ++i) {
30477 marker_last_stack_min[i] = ADDR_LIMIT;
30478 if (0 != pthread_create(&new_thread, &attr,
30479 GC_mark_thread, (void *)(word)i)) {
30480 WARN("Marker thread creation failed\n", 0);
30481 GC_markers_m1 = i;
30482 break;
30483 }
30484 }
30485#ifndef NO_MARKER_SPECIAL_SIGMASK
30486 if (pthread_sigmask(SIG_SETMASK, &oldset, NULL) < 0) {
30487 WARN("pthread_sigmask restore failed, errno= %" WARN_PRIdPTR "\n",
30488 errno);
30489 }
30490#endif
30491 (void)pthread_attr_destroy(&attr);
30492 GC_wait_for_markers_init();
30493 GC_COND_LOG_PRINTF("Started %d mark helper threads\n", GC_markers_m1);
30494 }
30495#ifdef GC_ASSERTIONS
30496 STATIC unsigned long GC_mark_lock_holder = NO_THREAD;
30497#define SET_MARK_LOCK_HOLDER \
30498 (void)(GC_mark_lock_holder = NUMERIC_THREAD_ID(pthread_self()))
30499#define UNSET_MARK_LOCK_HOLDER \
30500 do { \
30501 GC_ASSERT(GC_mark_lock_holder \
30502 == NUMERIC_THREAD_ID(pthread_self())); \
30503 GC_mark_lock_holder = NO_THREAD; \
30504 } while (0)
30505#endif
30506 static pthread_mutex_t mark_mutex = PTHREAD_MUTEX_INITIALIZER;
30507 static pthread_cond_t builder_cv = PTHREAD_COND_INITIALIZER;
30508#ifdef LOCK_STATS
30509 volatile AO_t GC_block_count = 0;
30510#endif
30511 GC_INNER void GC_acquire_mark_lock(void)
30512 {
30513#if defined(NUMERIC_THREAD_ID_UNIQUE) && !defined(THREAD_SANITIZER)
30514 GC_ASSERT(GC_mark_lock_holder != NUMERIC_THREAD_ID(pthread_self()));
30515#endif
30516 if (pthread_mutex_lock(&mark_mutex) != 0) {
30517 ABORT("pthread_mutex_lock failed");
30518 }
30519#ifdef LOCK_STATS
30520 (void)AO_fetch_and_add1(&GC_block_count);
30521#endif
30522 SET_MARK_LOCK_HOLDER;
30523 }
30524 GC_INNER void GC_release_mark_lock(void)
30525 {
30526 UNSET_MARK_LOCK_HOLDER;
30527 if (pthread_mutex_unlock(&mark_mutex) != 0) {
30528 ABORT("pthread_mutex_unlock failed");
30529 }
30530 }
30531 STATIC void GC_wait_builder(void)
30532 {
30533 UNSET_MARK_LOCK_HOLDER;
30534 if (pthread_cond_wait(&builder_cv, &mark_mutex) != 0) {
30535 ABORT("pthread_cond_wait failed");
30536 }
30537 GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
30538 SET_MARK_LOCK_HOLDER;
30539 }
30540 GC_INNER void GC_wait_for_reclaim(void)
30541 {
30542 GC_acquire_mark_lock();
30543 while (GC_fl_builder_count > 0) {
30544 GC_wait_builder();
30545 }
30546 GC_release_mark_lock();
30547 }
30548 GC_INNER void GC_notify_all_builder(void)
30549 {
30550 GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
30551 if (pthread_cond_broadcast(&builder_cv) != 0) {
30552 ABORT("pthread_cond_broadcast failed");
30553 }
30554 }
30555 GC_INNER void GC_wait_marker(void)
30556 {
30557 GC_ASSERT(GC_parallel);
30558 UNSET_MARK_LOCK_HOLDER;
30559 if (pthread_cond_wait(&mark_cv, &mark_mutex) != 0) {
30560 ABORT("pthread_cond_wait failed");
30561 }
30562 GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
30563 SET_MARK_LOCK_HOLDER;
30564 }
30565 GC_INNER void GC_notify_all_marker(void)
30566 {
30567 GC_ASSERT(GC_parallel);
30568 if (pthread_cond_broadcast(&mark_cv) != 0) {
30569 ABORT("pthread_cond_broadcast failed");
30570 }
30571 }
30572#else
30573#ifndef MARK_THREAD_STACK_SIZE
30574#define MARK_THREAD_STACK_SIZE 0
30575#endif
30576 static HANDLE mark_mutex_event = (HANDLE)0;
30577 static HANDLE builder_cv = (HANDLE)0;
30578 static HANDLE mark_cv = (HANDLE)0;
30579 GC_INNER void GC_start_mark_threads_inner(void)
30580 {
30581 int i;
30582 GC_ASSERT(I_DONT_HOLD_LOCK());
30583 if (available_markers_m1 <= 0) return;
30584 GC_ASSERT(GC_fl_builder_count == 0);
30585 for (i = 0; i < GC_markers_m1; ++i) {
30586 if ((GC_marker_cv[i] = CreateEvent(NULL ,
30587 TRUE ,
30588 FALSE ,
30589 NULL )) == (HANDLE)0)
30590 ABORT("CreateEvent failed");
30591 }
30592 for (i = 0; i < GC_markers_m1; ++i) {
30593#if defined(MSWINCE) || defined(MSWIN_XBOX1)
30594 HANDLE handle;
30595 DWORD thread_id;
30596 marker_last_stack_min[i] = ADDR_LIMIT;
30597 handle = CreateThread(NULL ,
30598 MARK_THREAD_STACK_SIZE ,
30599 GC_mark_thread, (LPVOID)(word)i,
30600 0 , &thread_id);
30601 if (handle == NULL) {
30602 WARN("Marker thread creation failed\n", 0);
30603 break;
30604 } else {
30605 CloseHandle(handle);
30606 }
30607#else
30608 GC_uintptr_t handle;
30609 unsigned thread_id;
30610 marker_last_stack_min[i] = ADDR_LIMIT;
30611 handle = _beginthreadex(NULL ,
30612 MARK_THREAD_STACK_SIZE, GC_mark_thread,
30613 (void *)(word)i, 0 , &thread_id);
30614 if (!handle || handle == (GC_uintptr_t)-1L) {
30615 WARN("Marker thread creation failed\n", 0);
30616 break;
30617 } else {
30618 }
30619#endif
30620 }
30621 while (GC_markers_m1 > i) {
30622 GC_markers_m1--;
30623 CloseHandle(GC_marker_cv[GC_markers_m1]);
30624 }
30625 GC_wait_for_markers_init();
30626 GC_COND_LOG_PRINTF("Started %d mark helper threads\n", GC_markers_m1);
30627 if (i == 0) {
30628 CloseHandle(mark_cv);
30629 CloseHandle(builder_cv);
30630 CloseHandle(mark_mutex_event);
30631 }
30632 }
30633#ifdef GC_ASSERTIONS
30634 STATIC DWORD GC_mark_lock_holder = NO_THREAD;
30635#define SET_MARK_LOCK_HOLDER \
30636 (void)(GC_mark_lock_holder = GetCurrentThreadId())
30637#define UNSET_MARK_LOCK_HOLDER \
30638 do { \
30639 GC_ASSERT(GC_mark_lock_holder == GetCurrentThreadId()); \
30640 GC_mark_lock_holder = NO_THREAD; \
30641 } while (0)
30642#endif
30643 STATIC LONG GC_mark_mutex_state = 0;
30644#ifdef LOCK_STATS
30645 volatile AO_t GC_block_count = 0;
30646 volatile AO_t GC_unlocked_count = 0;
30647#endif
30648 GC_INNER void GC_acquire_mark_lock(void)
30649 {
30650#ifndef THREAD_SANITIZER
30651 GC_ASSERT(GC_mark_lock_holder != GetCurrentThreadId());
30652#endif
30653 if (InterlockedExchange(&GC_mark_mutex_state, 1 ) != 0) {
30654#ifdef LOCK_STATS
30655 (void)AO_fetch_and_add1(&GC_block_count);
30656#endif
30657 while (InterlockedExchange(&GC_mark_mutex_state,
30658 -1 ) != 0) {
30659 if (WaitForSingleObject(mark_mutex_event, INFINITE) == WAIT_FAILED)
30660 ABORT("WaitForSingleObject failed");
30661 }
30662 }
30663#ifdef LOCK_STATS
30664 else {
30665 (void)AO_fetch_and_add1(&GC_unlocked_count);
30666 }
30667#endif
30668 GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
30669 SET_MARK_LOCK_HOLDER;
30670 }
30671 GC_INNER void GC_release_mark_lock(void)
30672 {
30673 UNSET_MARK_LOCK_HOLDER;
30674 if (InterlockedExchange(&GC_mark_mutex_state, 0 ) < 0) {
30675 if (SetEvent(mark_mutex_event) == FALSE)
30676 ABORT("SetEvent failed");
30677 }
30678 }
30679 GC_INNER void GC_wait_for_reclaim(void)
30680 {
30681 GC_ASSERT(builder_cv != 0);
30682 for (;;) {
30683 GC_acquire_mark_lock();
30684 if (GC_fl_builder_count == 0)
30685 break;
30686 if (ResetEvent(builder_cv) == FALSE)
30687 ABORT("ResetEvent failed");
30688 GC_release_mark_lock();
30689 if (WaitForSingleObject(builder_cv, INFINITE) == WAIT_FAILED)
30690 ABORT("WaitForSingleObject failed");
30691 }
30692 GC_release_mark_lock();
30693 }
30694 GC_INNER void GC_notify_all_builder(void)
30695 {
30696 GC_ASSERT(GC_mark_lock_holder == GetCurrentThreadId());
30697 GC_ASSERT(builder_cv != 0);
30698 GC_ASSERT(GC_fl_builder_count == 0);
30699 if (SetEvent(builder_cv) == FALSE)
30700 ABORT("SetEvent failed");
30701 }
30702 GC_INNER void GC_wait_marker(void)
30703 {
30704 HANDLE event = mark_cv;
30705 DWORD thread_id = GetCurrentThreadId();
30706 int i = GC_markers_m1;
30707 while (i-- > 0) {
30708 if (GC_marker_Id[i] == thread_id) {
30709 event = GC_marker_cv[i];
30710 break;
30711 }
30712 }
30713 if (ResetEvent(event) == FALSE)
30714 ABORT("ResetEvent failed");
30715 GC_release_mark_lock();
30716 if (WaitForSingleObject(event, INFINITE) == WAIT_FAILED)
30717 ABORT("WaitForSingleObject failed");
30718 GC_acquire_mark_lock();
30719 }
30720 GC_INNER void GC_notify_all_marker(void)
30721 {
30722 DWORD thread_id = GetCurrentThreadId();
30723 int i = GC_markers_m1;
30724 while (i-- > 0) {
30725 if (SetEvent(GC_marker_Id[i] != thread_id ? GC_marker_cv[i] :
30726 mark_cv) == FALSE)
30727 ABORT("SetEvent failed");
30728 }
30729 }
30730#endif
30731 static unsigned required_markers_cnt = 0;
30732#endif
30733 typedef struct {
30734 LPTHREAD_START_ROUTINE start;
30735 LPVOID param;
30736 } thread_args;
30737 STATIC void * GC_CALLBACK GC_win32_start_inner(struct GC_stack_base *sb,
30738 void *arg)
30739 {
30740 void * ret;
30741 LPTHREAD_START_ROUTINE start = ((thread_args *)arg)->start;
30742 LPVOID param = ((thread_args *)arg)->param;
30743 GC_register_my_thread(sb);
30744#ifdef DEBUG_THREADS
30745 GC_log_printf("thread 0x%lx starting...\n", (long)GetCurrentThreadId());
30746#endif
30747 GC_free(arg);
30748#if !defined(__GNUC__) && !defined(NO_CRT)
30749 ret = NULL;
30750 __try
30751#endif
30752 {
30753 ret = (void *)(word)(*start)(param);
30754 }
30755#if !defined(__GNUC__) && !defined(NO_CRT)
30756 __finally
30757#endif
30758 {
30759 GC_unregister_my_thread();
30760 }
30761#ifdef DEBUG_THREADS
30762 GC_log_printf("thread 0x%lx returned from start routine\n",
30763 (long)GetCurrentThreadId());
30764#endif
30765 return ret;
30766 }
30767 STATIC DWORD WINAPI GC_win32_start(LPVOID arg)
30768 {
30769 return (DWORD)(word)GC_call_with_stack_base(GC_win32_start_inner, arg);
30770 }
30771 GC_API HANDLE WINAPI GC_CreateThread(
30772 LPSECURITY_ATTRIBUTES lpThreadAttributes,
30773 GC_WIN32_SIZE_T dwStackSize,
30774 LPTHREAD_START_ROUTINE lpStartAddress,
30775 LPVOID lpParameter, DWORD dwCreationFlags,
30776 LPDWORD lpThreadId)
30777 {
30778 if (!EXPECT(parallel_initialized, TRUE))
30779 GC_init_parallel();
30780#ifdef DEBUG_THREADS
30781 GC_log_printf("About to create a thread from 0x%lx\n",
30782 (long)GetCurrentThreadId());
30783#endif
30784 if (GC_win32_dll_threads) {
30785 return CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress,
30786 lpParameter, dwCreationFlags, lpThreadId);
30787 } else {
30788 thread_args *args =
30789 (thread_args *)GC_malloc_uncollectable(sizeof(thread_args));
30790 HANDLE thread_h;
30791 if (NULL == args) {
30792 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
30793 return NULL;
30794 }
30795 args -> start = lpStartAddress;
30796 args -> param = lpParameter;
30797 GC_dirty(args);
30798 REACHABLE_AFTER_DIRTY(lpParameter);
30799 set_need_to_lock();
30800 thread_h = CreateThread(lpThreadAttributes, dwStackSize, GC_win32_start,
30801 args, dwCreationFlags, lpThreadId);
30802 if (thread_h == 0) GC_free(args);
30803 return thread_h;
30804 }
30805 }
30806 GC_API DECLSPEC_NORETURN void WINAPI GC_ExitThread(DWORD dwExitCode)
30807 {
30808 GC_unregister_my_thread();
30809 ExitThread(dwExitCode);
30810 }
30811#if !defined(CYGWIN32) && !defined(MSWINCE) && !defined(MSWIN_XBOX1) \
30812 && !defined(NO_CRT)
30813 GC_API GC_uintptr_t GC_CALL GC_beginthreadex(
30814 void *security, unsigned stack_size,
30815 unsigned (__stdcall *start_address)(void *),
30816 void *arglist, unsigned initflag,
30817 unsigned *thrdaddr)
30818 {
30819 if (!EXPECT(parallel_initialized, TRUE))
30820 GC_init_parallel();
30821#ifdef DEBUG_THREADS
30822 GC_log_printf("About to create a thread from 0x%lx\n",
30823 (long)GetCurrentThreadId());
30824#endif
30825 if (GC_win32_dll_threads) {
30826 return _beginthreadex(security, stack_size, start_address,
30827 arglist, initflag, thrdaddr);
30828 } else {
30829 GC_uintptr_t thread_h;
30830 thread_args *args =
30831 (thread_args *)GC_malloc_uncollectable(sizeof(thread_args));
30832 if (NULL == args) {
30833 errno = EAGAIN;
30834 return 0;
30835 }
30836 args -> start = (LPTHREAD_START_ROUTINE)start_address;
30837 args -> param = arglist;
30838 GC_dirty(args);
30839 REACHABLE_AFTER_DIRTY(arglist);
30840 set_need_to_lock();
30841 thread_h = _beginthreadex(security, stack_size,
30842 (unsigned (__stdcall *)(void *))GC_win32_start,
30843 args, initflag, thrdaddr);
30844 if (thread_h == 0) GC_free(args);
30845 return thread_h;
30846 }
30847 }
30848 GC_API void GC_CALL GC_endthreadex(unsigned retval)
30849 {
30850 GC_unregister_my_thread();
30851 _endthreadex(retval);
30852 }
30853#endif
30854#ifdef GC_WINMAIN_REDIRECT
30855#if defined(MSWINCE) && defined(UNDER_CE)
30856#define WINMAIN_LPTSTR LPWSTR
30857#else
30858#define WINMAIN_LPTSTR LPSTR
30859#endif
30860#undef WinMain
30861 int WINAPI GC_WinMain(HINSTANCE, HINSTANCE, WINMAIN_LPTSTR, int);
30862 typedef struct {
30863 HINSTANCE hInstance;
30864 HINSTANCE hPrevInstance;
30865 WINMAIN_LPTSTR lpCmdLine;
30866 int nShowCmd;
30867 } main_thread_args;
30868 static DWORD WINAPI main_thread_start(LPVOID arg)
30869 {
30870 main_thread_args * args = (main_thread_args *) arg;
30871 return (DWORD)GC_WinMain(args->hInstance, args->hPrevInstance,
30872 args->lpCmdLine, args->nShowCmd);
30873 }
30874 STATIC void * GC_waitForSingleObjectInfinite(void * handle)
30875 {
30876 return (void *)(word)WaitForSingleObject((HANDLE)handle, INFINITE);
30877 }
30878#ifndef WINMAIN_THREAD_STACK_SIZE
30879#define WINMAIN_THREAD_STACK_SIZE 0
30880#endif
30881 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
30882 WINMAIN_LPTSTR lpCmdLine, int nShowCmd)
30883 {
30884 DWORD exit_code = 1;
30885 main_thread_args args = {
30886 hInstance, hPrevInstance, lpCmdLine, nShowCmd
30887 };
30888 HANDLE thread_h;
30889 DWORD thread_id;
30890 GC_INIT();
30891 thread_h = GC_CreateThread(NULL ,
30892 WINMAIN_THREAD_STACK_SIZE ,
30893 main_thread_start, &args, 0 ,
30894 &thread_id);
30895 if (thread_h != NULL) {
30896 if ((DWORD)(word)GC_do_blocking(GC_waitForSingleObjectInfinite,
30897 (void *)thread_h) == WAIT_FAILED)
30898 ABORT("WaitForSingleObject(main_thread) failed");
30899 GetExitCodeThread (thread_h, &exit_code);
30900 CloseHandle (thread_h);
30901 } else {
30902 ABORT("GC_CreateThread(main_thread) failed");
30903 }
30904#ifdef MSWINCE
30905 GC_deinit();
30906#endif
30907 return (int) exit_code;
30908 }
30909#endif
30910GC_API void GC_CALL GC_set_markers_count(unsigned markers GC_ATTR_UNUSED)
30911{
30912#ifdef PARALLEL_MARK
30913 required_markers_cnt = markers < MAX_MARKERS ? markers : MAX_MARKERS;
30914#endif
30915}
30916GC_INNER void GC_thr_init(void)
30917{
30918 struct GC_stack_base sb;
30919#if (!defined(HAVE_PTHREAD_SETNAME_NP_WITH_TID) && !defined(MSWINCE) \
30920 && defined(PARALLEL_MARK)) || defined(WOW64_THREAD_CONTEXT_WORKAROUND)
30921 HMODULE hK32 = GetModuleHandle(TEXT("kernel32.dll"));
30922#endif
30923 GC_ASSERT(I_HOLD_LOCK());
30924 if (GC_thr_initialized) return;
30925 GC_ASSERT((word)&GC_threads % sizeof(word) == 0);
30926#ifdef GC_NO_THREADS_DISCOVERY
30927#define GC_main_thread GetCurrentThreadId()
30928#else
30929 GC_main_thread = GetCurrentThreadId();
30930#endif
30931 GC_thr_initialized = TRUE;
30932#ifdef CAN_HANDLE_FORK
30933 if (GC_handle_fork) {
30934#ifdef CAN_CALL_ATFORK
30935 if (pthread_atfork(fork_prepare_proc, fork_parent_proc,
30936 fork_child_proc) == 0) {
30937 GC_handle_fork = 1;
30938 } else
30939#endif
30940 if (GC_handle_fork != -1)
30941 ABORT("pthread_atfork failed");
30942 }
30943#endif
30944#ifdef WOW64_THREAD_CONTEXT_WORKAROUND
30945 if (hK32) {
30946 FARPROC pfn = GetProcAddress(hK32, "IsWow64Process");
30947 if (pfn
30948 && !(*(BOOL (WINAPI*)(HANDLE, BOOL*))(word)pfn)(
30949 GetCurrentProcess(), &isWow64))
30950 isWow64 = FALSE;
30951 }
30952#endif
30953 sb.mem_base = GC_stackbottom;
30954 GC_ASSERT(sb.mem_base != NULL);
30955#ifdef IA64
30956 sb.reg_base = GC_register_stackbottom;
30957#endif
30958#if defined(PARALLEL_MARK)
30959 {
30960 char * markers_string = GETENV("GC_MARKERS");
30961 int markers = required_markers_cnt;
30962 if (markers_string != NULL) {
30963 markers = atoi(markers_string);
30964 if (markers <= 0 || markers > MAX_MARKERS) {
30965 WARN("Too big or invalid number of mark threads: %" WARN_PRIdPTR
30966 "; using maximum threads\n", (signed_word)markers);
30967 markers = MAX_MARKERS;
30968 }
30969 } else if (0 == markers) {
30970#ifdef MSWINCE
30971 markers = (int)GC_sysinfo.dwNumberOfProcessors;
30972#else
30973#ifdef _WIN64
30974 DWORD_PTR procMask = 0;
30975 DWORD_PTR sysMask;
30976#else
30977 DWORD procMask = 0;
30978 DWORD sysMask;
30979#endif
30980 int ncpu = 0;
30981 if (
30982#ifdef __cplusplus
30983 GetProcessAffinityMask(GetCurrentProcess(), &procMask, &sysMask)
30984#else
30985 GetProcessAffinityMask(GetCurrentProcess(),
30986 (void *)&procMask, (void *)&sysMask)
30987#endif
30988 && procMask) {
30989 do {
30990 ncpu++;
30991 } while ((procMask &= procMask - 1) != 0);
30992 }
30993 markers = ncpu;
30994#endif
30995#if defined(GC_MIN_MARKERS) && !defined(CPPCHECK)
30996 if (markers < GC_MIN_MARKERS)
30997 markers = GC_MIN_MARKERS;
30998#endif
30999 if (markers > MAX_MARKERS)
31000 markers = MAX_MARKERS;
31001 }
31002 available_markers_m1 = markers - 1;
31003 }
31004 if (GC_win32_dll_threads || available_markers_m1 <= 0) {
31005 GC_parallel = FALSE;
31006 GC_COND_LOG_PRINTF(
31007 "Single marker thread, turning off parallel marking\n");
31008 } else {
31009#ifndef GC_PTHREADS_PARAMARK
31010 mark_mutex_event = CreateEvent(NULL ,
31011 FALSE ,
31012 FALSE , NULL );
31013 builder_cv = CreateEvent(NULL ,
31014 TRUE ,
31015 FALSE , NULL );
31016 mark_cv = CreateEvent(NULL , TRUE ,
31017 FALSE , NULL );
31018 if (mark_mutex_event == (HANDLE)0 || builder_cv == (HANDLE)0
31019 || mark_cv == (HANDLE)0)
31020 ABORT("CreateEvent failed");
31021#endif
31022#if !defined(HAVE_PTHREAD_SETNAME_NP_WITH_TID) && !defined(MSWINCE)
31023 if (hK32)
31024 setThreadDescription_fn = GetProcAddress(hK32,
31025 "SetThreadDescription");
31026#endif
31027 }
31028#endif
31029 GC_ASSERT(0 == GC_lookup_thread_inner(GC_main_thread));
31030 GC_register_my_thread_inner(&sb, GC_main_thread);
31031#undef GC_main_thread
31032}
31033#ifdef GC_PTHREADS
31034 struct start_info {
31035 void *(*start_routine)(void *);
31036 void *arg;
31037 GC_bool detached;
31038 };
31039 GC_API int GC_pthread_join(pthread_t pthread_id, void **retval)
31040 {
31041 int result;
31042#ifndef GC_WIN32_PTHREADS
31043 GC_thread t;
31044#endif
31045 DCL_LOCK_STATE;
31046 GC_ASSERT(!GC_win32_dll_threads);
31047#ifdef DEBUG_THREADS
31048 GC_log_printf("thread %p(0x%lx) is joining thread %p\n",
31049 (void *)GC_PTHREAD_PTRVAL(pthread_self()),
31050 (long)GetCurrentThreadId(),
31051 (void *)GC_PTHREAD_PTRVAL(pthread_id));
31052#endif
31053#ifndef GC_WIN32_PTHREADS
31054 while ((t = GC_lookup_pthread(pthread_id)) == 0)
31055 Sleep(10);
31056#endif
31057 result = pthread_join(pthread_id, retval);
31058 if (0 == result) {
31059#ifdef GC_WIN32_PTHREADS
31060 GC_thread t = GC_lookup_pthread(pthread_id);
31061 if (NULL == t) ABORT("Thread not registered");
31062#endif
31063 LOCK();
31064 if ((t -> flags & FINISHED) != 0) {
31065 GC_delete_gc_thread_no_free(t);
31066 GC_INTERNAL_FREE(t);
31067 }
31068 UNLOCK();
31069 }
31070#ifdef DEBUG_THREADS
31071 GC_log_printf("thread %p(0x%lx) join with thread %p %s\n",
31072 (void *)GC_PTHREAD_PTRVAL(pthread_self()),
31073 (long)GetCurrentThreadId(),
31074 (void *)GC_PTHREAD_PTRVAL(pthread_id),
31075 result != 0 ? "failed" : "succeeded");
31076#endif
31077 return result;
31078 }
31079 GC_API int GC_pthread_create(pthread_t *new_thread,
31080 GC_PTHREAD_CREATE_CONST pthread_attr_t *attr,
31081 void *(*start_routine)(void *), void *arg)
31082 {
31083 int result;
31084 struct start_info * si;
31085 if (!EXPECT(parallel_initialized, TRUE))
31086 GC_init_parallel();
31087 GC_ASSERT(!GC_win32_dll_threads);
31088 si = (struct start_info *)GC_malloc_uncollectable(
31089 sizeof(struct start_info));
31090 if (NULL == si)
31091 return EAGAIN;
31092 si -> start_routine = start_routine;
31093 si -> arg = arg;
31094 GC_dirty(si);
31095 REACHABLE_AFTER_DIRTY(arg);
31096 if (attr != 0 &&
31097 pthread_attr_getdetachstate(attr, &si->detached)
31098 == PTHREAD_CREATE_DETACHED) {
31099 si->detached = TRUE;
31100 }
31101#ifdef DEBUG_THREADS
31102 GC_log_printf("About to create a thread from %p(0x%lx)\n",
31103 (void *)GC_PTHREAD_PTRVAL(pthread_self()),
31104 (long)GetCurrentThreadId());
31105#endif
31106 set_need_to_lock();
31107 result = pthread_create(new_thread, attr, GC_pthread_start, si);
31108 if (result) {
31109 GC_free(si);
31110 }
31111 return(result);
31112 }
31113 STATIC void * GC_CALLBACK GC_pthread_start_inner(struct GC_stack_base *sb,
31114 void * arg)
31115 {
31116 struct start_info * si = (struct start_info *)arg;
31117 void * result;
31118 void *(*start)(void *);
31119 void *start_arg;
31120 DWORD thread_id = GetCurrentThreadId();
31121 pthread_t pthread_id = pthread_self();
31122 GC_thread me;
31123 DCL_LOCK_STATE;
31124#ifdef DEBUG_THREADS
31125 GC_log_printf("thread %p(0x%x) starting...\n",
31126 (void *)GC_PTHREAD_PTRVAL(pthread_id), (int)thread_id);
31127#endif
31128 GC_ASSERT(!GC_win32_dll_threads);
31129 LOCK();
31130 me = GC_register_my_thread_inner(sb, thread_id);
31131 SET_PTHREAD_MAP_CACHE(pthread_id, thread_id);
31132 GC_ASSERT(me != &first_thread);
31133 me -> pthread_id = pthread_id;
31134 if (si->detached) me -> flags |= DETACHED;
31135 UNLOCK();
31136 start = si -> start_routine;
31137 start_arg = si -> arg;
31138 GC_free(si);
31139 pthread_cleanup_push(GC_thread_exit_proc, (void *)me);
31140 result = (*start)(start_arg);
31141 me -> status = result;
31142 GC_dirty(me);
31143 pthread_cleanup_pop(1);
31144#ifdef DEBUG_THREADS
31145 GC_log_printf("thread %p(0x%x) returned from start routine\n",
31146 (void *)GC_PTHREAD_PTRVAL(pthread_id), (int)thread_id);
31147#endif
31148 return(result);
31149 }
31150 STATIC void * GC_pthread_start(void * arg)
31151 {
31152 return GC_call_with_stack_base(GC_pthread_start_inner, arg);
31153 }
31154 STATIC void GC_thread_exit_proc(void *arg)
31155 {
31156 GC_thread me = (GC_thread)arg;
31157 DCL_LOCK_STATE;
31158 GC_ASSERT(!GC_win32_dll_threads);
31159#ifdef DEBUG_THREADS
31160 GC_log_printf("thread %p(0x%lx) called pthread_exit()\n",
31161 (void *)GC_PTHREAD_PTRVAL(pthread_self()),
31162 (long)GetCurrentThreadId());
31163#endif
31164 LOCK();
31165 GC_wait_for_gc_completion(FALSE);
31166#if defined(THREAD_LOCAL_ALLOC)
31167 GC_ASSERT(GC_getspecific(GC_thread_key) == &me->tlfs);
31168 GC_destroy_thread_local(&(me->tlfs));
31169#endif
31170 if (me -> flags & DETACHED) {
31171 GC_delete_thread(GetCurrentThreadId());
31172 } else {
31173 me -> flags |= FINISHED;
31174 }
31175#if defined(THREAD_LOCAL_ALLOC)
31176 GC_remove_specific(GC_thread_key);
31177#endif
31178 UNLOCK();
31179 }
31180#ifndef GC_NO_PTHREAD_SIGMASK
31181 GC_API int GC_pthread_sigmask(int how, const sigset_t *set,
31182 sigset_t *oset)
31183 {
31184 return pthread_sigmask(how, set, oset);
31185 }
31186#endif
31187 GC_API int GC_pthread_detach(pthread_t thread)
31188 {
31189 int result;
31190 GC_thread t;
31191 DCL_LOCK_STATE;
31192 GC_ASSERT(!GC_win32_dll_threads);
31193 while ((t = GC_lookup_pthread(thread)) == NULL)
31194 Sleep(10);
31195 result = pthread_detach(thread);
31196 if (result == 0) {
31197 LOCK();
31198 t -> flags |= DETACHED;
31199 if ((t -> flags & FINISHED) != 0) {
31200 GC_delete_gc_thread_no_free(t);
31201 GC_INTERNAL_FREE(t);
31202 }
31203 UNLOCK();
31204 }
31205 return result;
31206 }
31207#elif !defined(GC_NO_THREADS_DISCOVERY)
31208#ifdef GC_INSIDE_DLL
31209 GC_API
31210#else
31211#define GC_DllMain DllMain
31212#endif
31213 BOOL WINAPI GC_DllMain(HINSTANCE inst GC_ATTR_UNUSED, ULONG reason,
31214 LPVOID reserved GC_ATTR_UNUSED)
31215 {
31216 DWORD thread_id;
31217 if (!GC_win32_dll_threads && parallel_initialized) return TRUE;
31218 switch (reason) {
31219 case DLL_THREAD_ATTACH:
31220#ifdef PARALLEL_MARK
31221 if (GC_parallel) {
31222 break;
31223 }
31224#endif
31225 case DLL_PROCESS_ATTACH:
31226 thread_id = GetCurrentThreadId();
31227 if (parallel_initialized && GC_main_thread != thread_id) {
31228#ifdef PARALLEL_MARK
31229 ABORT("Cannot initialize parallel marker from DllMain");
31230#else
31231 struct GC_stack_base sb;
31232#ifdef GC_ASSERTIONS
31233 int sb_result =
31234#endif
31235 GC_get_stack_base(&sb);
31236 GC_ASSERT(sb_result == GC_SUCCESS);
31237 GC_register_my_thread_inner(&sb, thread_id);
31238#endif
31239 }
31240 break;
31241 case DLL_THREAD_DETACH:
31242 GC_ASSERT(parallel_initialized);
31243 if (GC_win32_dll_threads) {
31244 GC_delete_thread(GetCurrentThreadId());
31245 }
31246 break;
31247 case DLL_PROCESS_DETACH:
31248 if (GC_win32_dll_threads) {
31249 int i;
31250 int my_max = (int)GC_get_max_thread_index();
31251 for (i = 0; i <= my_max; ++i) {
31252 if (AO_load(&(dll_thread_table[i].tm.in_use)))
31253 GC_delete_gc_thread_no_free(&dll_thread_table[i]);
31254 }
31255 GC_deinit();
31256 }
31257 break;
31258 }
31259 return TRUE;
31260 }
31261#endif
31262GC_INNER void GC_init_parallel(void)
31263{
31264#if defined(THREAD_LOCAL_ALLOC)
31265 GC_thread me;
31266 DCL_LOCK_STATE;
31267#endif
31268 if (parallel_initialized) return;
31269 parallel_initialized = TRUE;
31270 if (!GC_is_initialized) GC_init();
31271#if defined(CPPCHECK) && !defined(GC_NO_THREADS_DISCOVERY)
31272 GC_noop1((word)&GC_DllMain);
31273#endif
31274 if (GC_win32_dll_threads) {
31275 set_need_to_lock();
31276 }
31277#if defined(THREAD_LOCAL_ALLOC)
31278 LOCK();
31279 me = GC_lookup_thread_inner(GetCurrentThreadId());
31280 CHECK_LOOKUP_MY_THREAD(me);
31281 GC_init_thread_local(&me->tlfs);
31282 UNLOCK();
31283#endif
31284}
31285#if defined(USE_PTHREAD_LOCKS)
31286 GC_INNER void GC_lock(void)
31287 {
31288 pthread_mutex_lock(&GC_allocate_ml);
31289 }
31290#endif
31291#if defined(THREAD_LOCAL_ALLOC)
31292 GC_INNER void GC_mark_thread_local_free_lists(void)
31293 {
31294 int i;
31295 GC_thread p;
31296 for (i = 0; i < THREAD_TABLE_SZ; ++i) {
31297 for (p = GC_threads[i]; 0 != p; p = p -> tm.next) {
31298 if (!KNOWN_FINISHED(p)) {
31299#ifdef DEBUG_THREADS
31300 GC_log_printf("Marking thread locals for 0x%x\n", (int)p -> id);
31301#endif
31302 GC_mark_thread_local_fls_for(&(p->tlfs));
31303 }
31304 }
31305 }
31306 }
31307#if defined(GC_ASSERTIONS)
31308 void GC_check_tls(void)
31309 {
31310 int i;
31311 GC_thread p;
31312 for (i = 0; i < THREAD_TABLE_SZ; ++i) {
31313 for (p = GC_threads[i]; 0 != p; p = p -> tm.next) {
31314 if (!KNOWN_FINISHED(p))
31315 GC_check_tls_for(&(p->tlfs));
31316 }
31317 }
31318#if defined(USE_CUSTOM_SPECIFIC)
31319 if (GC_thread_key != 0)
31320 GC_check_tsd_marks(GC_thread_key);
31321#endif
31322 }
31323#endif
31324#endif
31325#ifndef GC_NO_THREAD_REDIRECTS
31326#define CreateThread GC_CreateThread
31327#define ExitThread GC_ExitThread
31328#undef _beginthreadex
31329#define _beginthreadex GC_beginthreadex
31330#undef _endthreadex
31331#define _endthreadex GC_endthreadex
31332#endif
31333#endif
31334#ifndef GC_PTHREAD_START_STANDALONE
31335#if defined(__GNUC__) && defined(__linux__)
31336#undef __EXCEPTIONS
31337#endif
31338#if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS)
31339#include <pthread.h>
31340#include <sched.h>
31341GC_INNER_PTHRSTART void * GC_CALLBACK GC_inner_start_routine(
31342 struct GC_stack_base *sb, void *arg)
31343{
31344 void * (*start)(void *);
31345 void * start_arg;
31346 void * result;
31347 volatile GC_thread me =
31348 GC_start_rtn_prepare_thread(&start, &start_arg, sb, arg);
31349#ifndef NACL
31350 pthread_cleanup_push(GC_thread_exit_proc, me);
31351#endif
31352 result = (*start)(start_arg);
31353#if defined(DEBUG_THREADS) && !defined(GC_PTHREAD_START_STANDALONE)
31354 GC_log_printf("Finishing thread %p\n", (void *)pthread_self());
31355#endif
31356 me -> status = result;
31357 GC_end_stubborn_change(me);
31358#ifndef NACL
31359 pthread_cleanup_pop(1);
31360#endif
31361 return result;
31362}
31363#endif
31364#endif
31365#ifndef GC_NO_THREAD_REDIRECTS
31366#define GC_PTHREAD_REDIRECTS_ONLY
31367#endif