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