Skip to content

Commit 8810af7

Browse files
authored
all: support -gc boehm on systems with libgc-dev installed (#9382)
1 parent a6ddd24 commit 8810af7

File tree

13 files changed

+135
-19
lines changed

13 files changed

+135
-19
lines changed

cmd/v/help/build-c.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,20 @@ see also `v help build`.
6969
and unsafe{free(x)} calls manually in this mode).
7070
Some short lived applications, like compilers and other CLI tools are
7171
more performant without autofree.
72+
73+
-gc <mode>
74+
Use and link an optional garbage collector.
75+
Only `-gc boehm` is supported currently. You need to install a
76+
`libgc-dev` package first, or install it manually from source:
77+
https://github.com/ivmai/bdwgc
78+
79+
Note, this option is complementary to -autofree. The Boehm garbage
80+
collector is conservative, and it may make your program significantly
81+
slower if it does many small allocations in a loop. This option
82+
is intended *mainly* for reducing the memory usage of programs, that
83+
process large amounts of text in *batch mode* on low/limited memory
84+
environments like small VPSes, and for which a few ms of garbage
85+
collection pauses from time to time *do not matter much*.
7286

7387
# Miscellaneous:
7488
-printfn <fn_name>

doc/docs.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3698,6 +3698,9 @@ If you do need a custom flag file, that has platform dependent code, use the
36983698
postfix `_d_customflag.v`, and then use plaftorm dependent compile time
36993699
conditional blocks inside it, i.e. `$if linux {}` etc.
37003700

3701+
- `_notd_customflag.v` => similar to _d_customflag.v, but will be used
3702+
*only* if you do NOT pass `-d customflag` to V.
3703+
37013704
## Compile time pseudo variables
37023705

37033706
V also gives your code access to a set of pseudo string variables,

vlib/builtin/array.v

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ pub fn (a &array) free() {
482482
// if a.is_slice {
483483
// return
484484
// }
485-
C.free(a.data)
485+
unsafe { free(a.data) }
486486
}
487487

488488
[unsafe]
@@ -493,7 +493,7 @@ pub fn (mut a []string) free() {
493493
for s in a {
494494
unsafe { s.free() }
495495
}
496-
C.free(a.data)
496+
unsafe { free(a.data) }
497497
}
498498

499499
// str returns a string representation of the array of strings

vlib/builtin/builtin.c.v

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,11 @@ pub fn malloc(n int) byteptr {
184184
}
185185
nr_mallocs++
186186
} $else {
187-
res = unsafe { C.malloc(n) }
187+
$if gcboehm ? {
188+
res = unsafe { C.GC_MALLOC(n) }
189+
} $else {
190+
res = unsafe { C.malloc(n) }
191+
}
188192
if res == 0 {
189193
panic('malloc($n) failed')
190194
}
@@ -214,7 +218,11 @@ pub fn v_realloc(b byteptr, n int) byteptr {
214218
C.memcpy(new_ptr, b, n)
215219
}
216220
} $else {
217-
new_ptr = unsafe { C.realloc(b, n) }
221+
$if gcboehm ? {
222+
new_ptr = unsafe { C.GC_REALLOC(b, n) }
223+
} $else {
224+
new_ptr = unsafe { C.realloc(b, n) }
225+
}
218226
if new_ptr == 0 {
219227
panic('realloc($n) failed')
220228
}
@@ -254,11 +262,16 @@ pub fn realloc_data(old_data byteptr, old_size int, new_size int) byteptr {
254262
min_size := if old_size < new_size { old_size } else { new_size }
255263
C.memcpy(new_ptr, old_data, min_size)
256264
C.memset(old_data, 0x57, old_size)
257-
C.free(old_data)
265+
free(old_data)
258266
return new_ptr
259267
}
260268
}
261-
nptr := unsafe { C.realloc(old_data, new_size) }
269+
mut nptr := byteptr(0)
270+
$if gcboehm ? {
271+
nptr = unsafe { C.GC_REALLOC(old_data, new_size) }
272+
} $else {
273+
nptr = unsafe { C.realloc(old_data, new_size) }
274+
}
262275
if nptr == 0 {
263276
panic('realloc_data($old_data, $old_size, $new_size) failed')
264277
}
@@ -268,7 +281,11 @@ pub fn realloc_data(old_data byteptr, old_size int, new_size int) byteptr {
268281
// v_calloc dynamically allocates a zeroed `n` bytes block of memory on the heap.
269282
// v_calloc returns a `byteptr` pointing to the memory address of the allocated space.
270283
pub fn v_calloc(n int) byteptr {
271-
return C.calloc(1, n)
284+
$if gcboehm ? {
285+
return C.GC_MALLOC(n)
286+
} $else {
287+
return C.calloc(1, n)
288+
}
272289
}
273290

274291
// vcalloc dynamically allocates a zeroed `n` bytes block of memory on the heap.
@@ -280,7 +297,11 @@ pub fn vcalloc(n int) byteptr {
280297
} else if n == 0 {
281298
return byteptr(0)
282299
}
283-
return C.calloc(1, n)
300+
$if gcboehm ? {
301+
return C.GC_MALLOC(n)
302+
} $else {
303+
return C.calloc(1, n)
304+
}
284305
}
285306

286307
// free allows for manually freeing memory allocated at the address `ptr`.
@@ -289,6 +310,10 @@ pub fn free(ptr voidptr) {
289310
$if prealloc {
290311
return
291312
}
313+
$if gcboehm ? {
314+
C.GC_FREE(ptr)
315+
return
316+
}
292317
C.free(ptr)
293318
}
294319

@@ -306,14 +331,6 @@ pub fn memdup(src voidptr, sz int) voidptr {
306331
}
307332
}
308333

309-
// v_ptr_free is used internally to manually free up memory allocated at the address `ptr`.
310-
fn v_ptr_free(ptr voidptr) {
311-
$if prealloc {
312-
return
313-
}
314-
C.free(ptr)
315-
}
316-
317334
// is_atty returns 1 if the `fd` file descriptor is open and refers to a terminal
318335
pub fn is_atty(fd int) int {
319336
$if windows {

vlib/builtin/builtin_d_gcboehm.v

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module builtin
2+
3+
#define GC_THREADS 1
4+
5+
#include <gc.h>
6+
7+
#flag -lgc
8+
9+
fn C.GC_MALLOC(n size_t) voidptr
10+
11+
fn C.GC_REALLOC(ptr voidptr, n size_t) voidptr
12+
13+
fn C.GC_FREE(ptr voidptr)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module builtin
2+
3+
// Just define the C functions, so that V does not error because of the missing definitions.
4+
5+
// NB: they will NOT be used, since calls to them are wrapped with `$if gcboehm ? { }`
6+
7+
fn C.GC_MALLOC(n size_t) voidptr
8+
9+
fn C.GC_REALLOC(ptr voidptr, n size_t) voidptr
10+
11+
fn C.GC_FREE(ptr voidptr)

vlib/builtin/option.v

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,6 @@ pub fn (ie &IError) free() {
9191
unsafe {
9292
ie.msg.free()
9393
cie := &C.IError(ie)
94-
C.free(cie._object)
94+
free(cie._object)
9595
}
9696
}

vlib/v/gen/c/cgen.v

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,9 @@ pub fn (mut g Gen) init() {
422422
}
423423
g.comptime_defines.writeln('')
424424
}
425+
if g.pref.gc_mode == .boehm {
426+
g.comptime_defines.writeln('#define _VGCBOEHM (1)')
427+
}
425428
if g.pref.is_debug || 'debug' in g.pref.compile_defines {
426429
g.comptime_defines.writeln('#define _VDEBUG (1)')
427430
}

vlib/v/gen/c/cheaders.v

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,9 +454,10 @@ void _vcleanup();
454454
}
455455
#endif
456456
457+
void v_free(voidptr ptr);
457458
voidptr memdup(voidptr src, int sz);
458459
static voidptr memfreedup(voidptr ptr, voidptr src, int sz) {
459-
free(ptr);
460+
v_free(ptr);
460461
return memdup(src, sz);
461462
}
462463
'

vlib/v/gen/c/comptime.v

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,9 @@ fn (mut g Gen) comp_if_to_ifdef(name string, is_comptime_optional bool) ?string
533533
return '__cplusplus'
534534
}
535535
// other:
536+
'gcboehm' {
537+
return '_VGCBOEHM'
538+
}
536539
'debug' {
537540
return '_VDEBUG'
538541
}

0 commit comments

Comments
 (0)