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