v / vlib / builtin / builtin_d_gcboehm.c.v
318 lines · 277 sloc · 9.07 KB · d1b46e92e1faa3a6eb943070f508920306158ac6
Raw
1module builtin
2
3$if !no_gc_threads ? {
4 #flag -DGC_THREADS=1
5}
6
7$if use_bundled_libgc ? {
8 #flag -DGC_BUILTIN_ATOMIC=1
9 #flag -I @VEXEROOT/thirdparty/libgc/include
10 #flag -DALL_INTERIOR_POINTERS=1
11 #flag @VEXEROOT/thirdparty/libgc/gc.o
12}
13
14$if dynamic_boehm ? {
15 $if windows {
16 $if tinyc {
17 #flag -I @VEXEROOT/thirdparty/libgc/include
18 #flag -L @VEXEROOT/thirdparty/tcc/lib
19 #flag -lgc
20 } $else $if msvc {
21 #flag -DGC_BUILTIN_ATOMIC=1
22 #flag -I @VEXEROOT/thirdparty/libgc/include
23 } $else {
24 #flag -DGC_WIN32_THREADS=1
25 #flag -DGC_BUILTIN_ATOMIC=1
26 #flag -I @VEXEROOT/thirdparty/libgc/include
27 #flag -DALL_INTERIOR_POINTERS=1
28 #flag @VEXEROOT/thirdparty/libgc/gc.o
29 }
30 } $else {
31 $if $pkgconfig('bdw-gc-threaded') {
32 #pkgconfig bdw-gc-threaded
33 } $else $if $pkgconfig('bdw-gc') {
34 #pkgconfig bdw-gc
35 } $else {
36 $if openbsd || freebsd {
37 #flag -I/usr/local/include
38 #flag -L/usr/local/lib
39 }
40 $if freebsd {
41 #flag -lgc-threaded
42 } $else {
43 #flag -lgc
44 }
45 }
46 }
47} $else {
48 $if macos || linux {
49 #flag -DGC_BUILTIN_ATOMIC=1
50 #flag -I @VEXEROOT/thirdparty/libgc/include
51 $if (prod && !tinyc && !debug) || !(amd64 || arm64 || i386 || arm32 || rv64) {
52 // TODO: replace the architecture check with a `!$exists("@VEXEROOT/thirdparty/tcc/lib/libgc.a")` comptime call
53 #flag -DALL_INTERIOR_POINTERS=1
54 #flag @VEXEROOT/thirdparty/libgc/gc.o
55 } $else {
56 $if !use_bundled_libgc ? {
57 $if macos {
58 $if tinyc {
59 $if arm64 {
60 // tcc on macOS arm64 can leave the bundled GC archive symbols unresolved.
61 #flag @VEXEROOT/thirdparty/tcc/lib/libgc.dylib
62 #flag -Wl,-rpath,"@VEXEROOT/thirdparty/tcc/lib"
63 } $else {
64 // macOS amd64 tccbin only ships libgc.a (no .dylib).
65 #flag @VEXEROOT/thirdparty/tcc/lib/libgc.a
66 }
67 } $else {
68 #flag -L@VEXEROOT/thirdparty/tcc/lib
69 #flag -lgc
70 #flag -Xlinker -rpath -Xlinker "@VEXEROOT/thirdparty/tcc/lib"
71 }
72 } $else {
73 $if musl ? {
74 // The bundled tcc libgc archive is built for glibc and
75 // references __data_start/data_start, which musl does
76 // not provide. Alpine installs musl-compatible libgc.
77 $if tinyc {
78 // Prefer the shared library when present: Alpine's
79 // static libgc archive can leave weak data segment
80 // probes unresolved under tcc.
81 #flag $when_first_existing("/usr/lib/libgc.so", "/usr/local/lib/libgc.so", "/lib/libgc.so")
82 }
83 #flag -lgc
84 } $else {
85 #flag @VEXEROOT/thirdparty/tcc/lib/libgc.a
86 }
87 }
88 }
89 }
90 $if macos {
91 #flag -DMPROTECT_VDB=1
92 }
93 #flag -ldl
94 #flag -lpthread
95 } $else $if freebsd {
96 // Tested on FreeBSD 13.0-RELEASE-p3, with clang, gcc and tcc
97 #flag -DGC_BUILTIN_ATOMIC=1
98 #flag -DBUS_PAGE_FAULT=T_PAGEFLT
99 #flag -DALL_INTERIOR_POINTERS=1
100 $if !tinyc {
101 #flag -DUSE_MMAP
102 #flag -I @VEXEROOT/thirdparty/libgc/include
103 #flag @VEXEROOT/thirdparty/libgc/gc.o
104 }
105 $if tinyc {
106 // Prefer the bundled header: older FreeBSD libgc headers still use the
107 // unsupported `"X"` asm constraint in `GC_reachable_here` under tcc.
108 #flag -I @VEXEROOT/thirdparty/libgc/include
109 #flag -I/usr/local/include
110 #flag $first_existing("@VEXEROOT/thirdparty/tcc/lib/libgc.a", "/usr/local/lib/libgc-threaded.a", "/usr/lib/libgc-threaded.a")
111 #flag -lgc-threaded
112 }
113 #flag -lpthread
114 } $else $if openbsd {
115 // Tested on OpenBSD 7.5, with clang, gcc and tcc
116 #flag -DGC_BUILTIN_ATOMIC=1
117 $if !tinyc {
118 #flag -I @VEXEROOT/thirdparty/libgc/include
119 #flag -DALL_INTERIOR_POINTERS=1
120 #flag @VEXEROOT/thirdparty/libgc/gc.o
121 }
122 $if tinyc {
123 // Prefer the bundled header: older OpenBSD libgc headers still use the
124 // unsupported `"X"` asm constraint in `GC_reachable_here` under tcc.
125 #flag -I @VEXEROOT/thirdparty/libgc/include
126 #flag -L/usr/local/lib
127 #flag -I/usr/local/include
128 #flag $first_existing("/usr/local/lib/libgc.a", "/usr/lib/libgc.a")
129 #flag -lgc
130 }
131 #flag -lpthread
132 } $else $if windows {
133 #flag -DGC_NOT_DLL=1
134 #flag -DGC_WIN32_THREADS=1
135 #flag -luser32
136 $if tinyc {
137 #flag -DGC_BUILTIN_ATOMIC=1
138 #flag -I @VEXEROOT/thirdparty/libgc/include
139 $if !use_bundled_libgc ? {
140 #flag @VEXEROOT/thirdparty/tcc/lib/libgc.a
141 }
142 } $else $if msvc {
143 // Build libatomic_ops
144 #flag @VEXEROOT/thirdparty/libatomic_ops/atomic_ops.o
145 #flag -I @VEXEROOT/thirdparty/libatomic_ops
146
147 #flag -I @VEXEROOT/thirdparty/libgc/include
148 #flag -DALL_INTERIOR_POINTERS=1
149 #flag @VEXEROOT/thirdparty/libgc/gc.o
150 } $else {
151 #flag -DGC_BUILTIN_ATOMIC=1
152 #flag -I @VEXEROOT/thirdparty/libgc/include
153 #flag -DALL_INTERIOR_POINTERS=1
154 #flag @VEXEROOT/thirdparty/libgc/gc.o
155 }
156 } $else $if $pkgconfig('bdw-gc') {
157 #flag -DGC_BUILTIN_ATOMIC=1
158 #pkgconfig bdw-gc
159 } $else {
160 #flag -DGC_BUILTIN_ATOMIC=1
161 #flag -lgc
162 }
163}
164
165$if gcboehm_leak ? {
166 #flag -DGC_DEBUG=1
167}
168
169#include <gc.h>
170#include "@VEXEROOT/vlib/builtin/gc_debugger_linux.h"
171
172// #include <gc/gc_mark.h>
173
174// replacements for `malloc()/calloc()`, `realloc()` and `free()`
175// for use with Boehm-GC
176// Do not use them manually. They are automatically chosen when
177// compiled with `-gc boehm` or `-gc boehm_leak`.
178fn C.GC_MALLOC(n usize) voidptr
179
180fn C.GC_MALLOC_ATOMIC(n usize) voidptr
181
182fn C.GC_MALLOC_UNCOLLECTABLE(n usize) voidptr
183
184fn C.GC_REALLOC(ptr voidptr, n usize) voidptr
185
186fn C.GC_FREE(ptr voidptr)
187
188fn C.GC_memalign(align isize, size isize) voidptr
189
190// explicitly perform garbage collection now! Garbage collections
191// are done automatically when needed, so this function is hardly needed
192fn C.GC_gcollect()
193
194// functions to temporarily suspend/resume garbage collection
195fn C.GC_disable()
196
197fn C.GC_enable()
198
199// returns non-zero if GC is disabled
200fn C.GC_is_disabled() i32
201
202fn C.GC_set_no_dls(i32)
203
204// protect memory block from being freed before this call
205fn C.GC_reachable_here(voidptr)
206
207// gc_is_enabled returns true, if the GC is enabled at runtime.
208// See also gc_disable() and gc_enable().
209pub fn gc_is_enabled() bool {
210 return 0 == C.GC_is_disabled()
211}
212
213// gc_collect explicitly performs a single garbage collection run.
214// Note, that garbage collections, are done automatically, when needed in most cases,
215// so usually you should NOT need to call gc_collect() often.
216// Note that gc_collect() is a NOP with `-gc none`.
217pub fn gc_collect() {
218 C.GC_gcollect()
219}
220
221// gc_enable explicitly enables the GC.
222// Note, that garbage collections are done automatically, when needed in most cases,
223// and also that by default the GC is on, so you do not need to enable it.
224// See also gc_disable() and gc_collect().
225// Note that gc_enable() is a NOP with `-gc none`.
226pub fn gc_enable() {
227 C.GC_enable()
228}
229
230// gc_disable explicitly disables the GC. Do not forget to enable it again by calling gc_enable(), when your program is otherwise idle, and can afford it.
231// See also gc_enable() and gc_collect().
232// Note that gc_disable() is a NOP with `-gc none`.
233pub fn gc_disable() {
234 C.GC_disable()
235}
236
237// gc_check_leaks is useful for leak detection (it does an explicit garbage collections, but only when a program is compiled with `-gc boehm_leak`).
238pub fn gc_check_leaks() {
239 $if gcboehm_leak ? {
240 C.GC_gcollect()
241 }
242}
243
244fn C.GC_get_heap_usage_safe(pheap_size &usize, pfree_bytes &usize, punmapped_bytes &usize, pbytes_since_gc &usize,
245 ptotal_bytes &usize)
246fn C.GC_get_memory_use() usize
247
248pub struct C.GC_stack_base {
249 mem_base voidptr
250 // reg_base voidptr
251}
252
253fn C.GC_get_stack_base(voidptr) i32
254fn C.GC_register_my_thread(voidptr) i32
255fn C.GC_unregister_my_thread() i32
256
257// fn C.GC_get_my_stackbottom(voidptr) voidptr
258fn C.GC_set_stackbottom(voidptr, voidptr)
259
260// fn C.GC_push_all_stacks()
261
262fn C.GC_add_roots(voidptr, voidptr)
263fn C.GC_remove_roots(voidptr, voidptr)
264
265fn C.v__gc_can_register_main_data_roots_linux() i32
266fn C.v__gc_debugger_present_linux() i32
267fn C.v__gc_register_main_data_roots_linux()
268
269// fn C.GC_get_push_other_roots() fn()
270// fn C.GC_set_push_other_roots(fn())
271
272fn C.GC_get_sp_corrector() fn (voidptr, voidptr)
273fn C.GC_set_sp_corrector(fn (voidptr, voidptr))
274
275// FnGC_WarnCB is the type of the callback, that you have to define, if you want to redirect GC warnings and handle them.
276// Note: GC warnings are silenced by default. Use gc_set_warn_proc/1 to set your own handler for them.
277pub type FnGC_WarnCB = fn (const_msg &char, arg usize)
278
279fn C.GC_get_warn_proc() FnGC_WarnCB
280fn C.GC_set_warn_proc(cb FnGC_WarnCB)
281
282fn C.GC_register_displacement(offset usize)
283
284// gc_get_warn_proc returns the current callback fn, that will be used for printing GC warnings.
285pub fn gc_get_warn_proc() FnGC_WarnCB {
286 return C.GC_get_warn_proc()
287}
288
289// gc_set_warn_proc sets the callback fn, that will be used for printing GC warnings.
290pub fn gc_set_warn_proc(cb FnGC_WarnCB) {
291 C.GC_set_warn_proc(cb)
292}
293
294// used by builtin_init:
295fn internal_gc_warn_proc_none(const_msg &char, arg usize) {}
296
297@[markused]
298fn gc_prepare_for_debugger_init() bool {
299 $if linux {
300 if C.v__gc_debugger_present_linux() != 0
301 && C.v__gc_can_register_main_data_roots_linux() != 0 {
302 C.GC_set_no_dls(1)
303 return true
304 }
305 }
306 return false
307}
308
309@[markused]
310fn gc_restore_roots_after_debugger_init(use_manual_roots bool) {
311 if !use_manual_roots {
312 return
313 }
314 $if linux {
315 C.v__gc_register_main_data_roots_linux()
316 C.GC_set_no_dls(0)
317 }
318}
319