all: support `-gc boehm` on systems with libgc-dev installed (#9382)
parent
a6ddd24f5c
commit
8810af76df
|
@ -69,6 +69,20 @@ see also `v help build`.
|
||||||
and unsafe{free(x)} calls manually in this mode).
|
and unsafe{free(x)} calls manually in this mode).
|
||||||
Some short lived applications, like compilers and other CLI tools are
|
Some short lived applications, like compilers and other CLI tools are
|
||||||
more performant without autofree.
|
more performant without autofree.
|
||||||
|
|
||||||
|
-gc <mode>
|
||||||
|
Use and link an optional garbage collector.
|
||||||
|
Only `-gc boehm` is supported currently. You need to install a
|
||||||
|
`libgc-dev` package first, or install it manually from source:
|
||||||
|
https://github.com/ivmai/bdwgc
|
||||||
|
|
||||||
|
Note, this option is complementary to -autofree. The Boehm garbage
|
||||||
|
collector is conservative, and it may make your program significantly
|
||||||
|
slower if it does many small allocations in a loop. This option
|
||||||
|
is intended *mainly* for reducing the memory usage of programs, that
|
||||||
|
process large amounts of text in *batch mode* on low/limited memory
|
||||||
|
environments like small VPSes, and for which a few ms of garbage
|
||||||
|
collection pauses from time to time *do not matter much*.
|
||||||
|
|
||||||
# Miscellaneous:
|
# Miscellaneous:
|
||||||
-printfn <fn_name>
|
-printfn <fn_name>
|
||||||
|
|
|
@ -3698,6 +3698,9 @@ If you do need a custom flag file, that has platform dependent code, use the
|
||||||
postfix `_d_customflag.v`, and then use plaftorm dependent compile time
|
postfix `_d_customflag.v`, and then use plaftorm dependent compile time
|
||||||
conditional blocks inside it, i.e. `$if linux {}` etc.
|
conditional blocks inside it, i.e. `$if linux {}` etc.
|
||||||
|
|
||||||
|
- `_notd_customflag.v` => similar to _d_customflag.v, but will be used
|
||||||
|
*only* if you do NOT pass `-d customflag` to V.
|
||||||
|
|
||||||
## Compile time pseudo variables
|
## Compile time pseudo variables
|
||||||
|
|
||||||
V also gives your code access to a set of pseudo string variables,
|
V also gives your code access to a set of pseudo string variables,
|
||||||
|
|
|
@ -482,7 +482,7 @@ pub fn (a &array) free() {
|
||||||
// if a.is_slice {
|
// if a.is_slice {
|
||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
C.free(a.data)
|
unsafe { free(a.data) }
|
||||||
}
|
}
|
||||||
|
|
||||||
[unsafe]
|
[unsafe]
|
||||||
|
@ -493,7 +493,7 @@ pub fn (mut a []string) free() {
|
||||||
for s in a {
|
for s in a {
|
||||||
unsafe { s.free() }
|
unsafe { s.free() }
|
||||||
}
|
}
|
||||||
C.free(a.data)
|
unsafe { free(a.data) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// str returns a string representation of the array of strings
|
// str returns a string representation of the array of strings
|
||||||
|
|
|
@ -184,7 +184,11 @@ pub fn malloc(n int) byteptr {
|
||||||
}
|
}
|
||||||
nr_mallocs++
|
nr_mallocs++
|
||||||
} $else {
|
} $else {
|
||||||
res = unsafe { C.malloc(n) }
|
$if gcboehm ? {
|
||||||
|
res = unsafe { C.GC_MALLOC(n) }
|
||||||
|
} $else {
|
||||||
|
res = unsafe { C.malloc(n) }
|
||||||
|
}
|
||||||
if res == 0 {
|
if res == 0 {
|
||||||
panic('malloc($n) failed')
|
panic('malloc($n) failed')
|
||||||
}
|
}
|
||||||
|
@ -214,7 +218,11 @@ pub fn v_realloc(b byteptr, n int) byteptr {
|
||||||
C.memcpy(new_ptr, b, n)
|
C.memcpy(new_ptr, b, n)
|
||||||
}
|
}
|
||||||
} $else {
|
} $else {
|
||||||
new_ptr = unsafe { C.realloc(b, n) }
|
$if gcboehm ? {
|
||||||
|
new_ptr = unsafe { C.GC_REALLOC(b, n) }
|
||||||
|
} $else {
|
||||||
|
new_ptr = unsafe { C.realloc(b, n) }
|
||||||
|
}
|
||||||
if new_ptr == 0 {
|
if new_ptr == 0 {
|
||||||
panic('realloc($n) failed')
|
panic('realloc($n) failed')
|
||||||
}
|
}
|
||||||
|
@ -254,11 +262,16 @@ pub fn realloc_data(old_data byteptr, old_size int, new_size int) byteptr {
|
||||||
min_size := if old_size < new_size { old_size } else { new_size }
|
min_size := if old_size < new_size { old_size } else { new_size }
|
||||||
C.memcpy(new_ptr, old_data, min_size)
|
C.memcpy(new_ptr, old_data, min_size)
|
||||||
C.memset(old_data, 0x57, old_size)
|
C.memset(old_data, 0x57, old_size)
|
||||||
C.free(old_data)
|
free(old_data)
|
||||||
return new_ptr
|
return new_ptr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nptr := unsafe { C.realloc(old_data, new_size) }
|
mut nptr := byteptr(0)
|
||||||
|
$if gcboehm ? {
|
||||||
|
nptr = unsafe { C.GC_REALLOC(old_data, new_size) }
|
||||||
|
} $else {
|
||||||
|
nptr = unsafe { C.realloc(old_data, new_size) }
|
||||||
|
}
|
||||||
if nptr == 0 {
|
if nptr == 0 {
|
||||||
panic('realloc_data($old_data, $old_size, $new_size) failed')
|
panic('realloc_data($old_data, $old_size, $new_size) failed')
|
||||||
}
|
}
|
||||||
|
@ -268,7 +281,11 @@ pub fn realloc_data(old_data byteptr, old_size int, new_size int) byteptr {
|
||||||
// v_calloc dynamically allocates a zeroed `n` bytes block of memory on the heap.
|
// v_calloc dynamically allocates a zeroed `n` bytes block of memory on the heap.
|
||||||
// v_calloc returns a `byteptr` pointing to the memory address of the allocated space.
|
// v_calloc returns a `byteptr` pointing to the memory address of the allocated space.
|
||||||
pub fn v_calloc(n int) byteptr {
|
pub fn v_calloc(n int) byteptr {
|
||||||
return C.calloc(1, n)
|
$if gcboehm ? {
|
||||||
|
return C.GC_MALLOC(n)
|
||||||
|
} $else {
|
||||||
|
return C.calloc(1, n)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// vcalloc dynamically allocates a zeroed `n` bytes block of memory on the heap.
|
// vcalloc dynamically allocates a zeroed `n` bytes block of memory on the heap.
|
||||||
|
@ -280,7 +297,11 @@ pub fn vcalloc(n int) byteptr {
|
||||||
} else if n == 0 {
|
} else if n == 0 {
|
||||||
return byteptr(0)
|
return byteptr(0)
|
||||||
}
|
}
|
||||||
return C.calloc(1, n)
|
$if gcboehm ? {
|
||||||
|
return C.GC_MALLOC(n)
|
||||||
|
} $else {
|
||||||
|
return C.calloc(1, n)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// free allows for manually freeing memory allocated at the address `ptr`.
|
// free allows for manually freeing memory allocated at the address `ptr`.
|
||||||
|
@ -289,6 +310,10 @@ pub fn free(ptr voidptr) {
|
||||||
$if prealloc {
|
$if prealloc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
$if gcboehm ? {
|
||||||
|
C.GC_FREE(ptr)
|
||||||
|
return
|
||||||
|
}
|
||||||
C.free(ptr)
|
C.free(ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,14 +331,6 @@ pub fn memdup(src voidptr, sz int) voidptr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// v_ptr_free is used internally to manually free up memory allocated at the address `ptr`.
|
|
||||||
fn v_ptr_free(ptr voidptr) {
|
|
||||||
$if prealloc {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
C.free(ptr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// is_atty returns 1 if the `fd` file descriptor is open and refers to a terminal
|
// is_atty returns 1 if the `fd` file descriptor is open and refers to a terminal
|
||||||
pub fn is_atty(fd int) int {
|
pub fn is_atty(fd int) int {
|
||||||
$if windows {
|
$if windows {
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
module builtin
|
||||||
|
|
||||||
|
#define GC_THREADS 1
|
||||||
|
|
||||||
|
#include <gc.h>
|
||||||
|
|
||||||
|
#flag -lgc
|
||||||
|
|
||||||
|
fn C.GC_MALLOC(n size_t) voidptr
|
||||||
|
|
||||||
|
fn C.GC_REALLOC(ptr voidptr, n size_t) voidptr
|
||||||
|
|
||||||
|
fn C.GC_FREE(ptr voidptr)
|
|
@ -0,0 +1,11 @@
|
||||||
|
module builtin
|
||||||
|
|
||||||
|
// Just define the C functions, so that V does not error because of the missing definitions.
|
||||||
|
|
||||||
|
// NB: they will NOT be used, since calls to them are wrapped with `$if gcboehm ? { }`
|
||||||
|
|
||||||
|
fn C.GC_MALLOC(n size_t) voidptr
|
||||||
|
|
||||||
|
fn C.GC_REALLOC(ptr voidptr, n size_t) voidptr
|
||||||
|
|
||||||
|
fn C.GC_FREE(ptr voidptr)
|
|
@ -91,6 +91,6 @@ pub fn (ie &IError) free() {
|
||||||
unsafe {
|
unsafe {
|
||||||
ie.msg.free()
|
ie.msg.free()
|
||||||
cie := &C.IError(ie)
|
cie := &C.IError(ie)
|
||||||
C.free(cie._object)
|
free(cie._object)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -422,6 +422,9 @@ pub fn (mut g Gen) init() {
|
||||||
}
|
}
|
||||||
g.comptime_defines.writeln('')
|
g.comptime_defines.writeln('')
|
||||||
}
|
}
|
||||||
|
if g.pref.gc_mode == .boehm {
|
||||||
|
g.comptime_defines.writeln('#define _VGCBOEHM (1)')
|
||||||
|
}
|
||||||
if g.pref.is_debug || 'debug' in g.pref.compile_defines {
|
if g.pref.is_debug || 'debug' in g.pref.compile_defines {
|
||||||
g.comptime_defines.writeln('#define _VDEBUG (1)')
|
g.comptime_defines.writeln('#define _VDEBUG (1)')
|
||||||
}
|
}
|
||||||
|
|
|
@ -454,9 +454,10 @@ void _vcleanup();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void v_free(voidptr ptr);
|
||||||
voidptr memdup(voidptr src, int sz);
|
voidptr memdup(voidptr src, int sz);
|
||||||
static voidptr memfreedup(voidptr ptr, voidptr src, int sz) {
|
static voidptr memfreedup(voidptr ptr, voidptr src, int sz) {
|
||||||
free(ptr);
|
v_free(ptr);
|
||||||
return memdup(src, sz);
|
return memdup(src, sz);
|
||||||
}
|
}
|
||||||
'
|
'
|
||||||
|
|
|
@ -533,6 +533,9 @@ fn (mut g Gen) comp_if_to_ifdef(name string, is_comptime_optional bool) ?string
|
||||||
return '__cplusplus'
|
return '__cplusplus'
|
||||||
}
|
}
|
||||||
// other:
|
// other:
|
||||||
|
'gcboehm' {
|
||||||
|
return '_VGCBOEHM'
|
||||||
|
}
|
||||||
'debug' {
|
'debug' {
|
||||||
return '_VDEBUG'
|
return '_VDEBUG'
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,11 @@ void _STR_PRINT_ARG(const char *fmt, char** refbufp, int *nbytes, int *memsize,
|
||||||
}
|
}
|
||||||
// increase buffer (somewhat exponentially)
|
// increase buffer (somewhat exponentially)
|
||||||
*memsize += (*memsize + *memsize) / 3 + guess;
|
*memsize += (*memsize + *memsize) / 3 + guess;
|
||||||
|
#ifdef _VGCBOEHM
|
||||||
|
*refbufp = (char*)GC_REALLOC((void*)*refbufp, *memsize);
|
||||||
|
#else
|
||||||
*refbufp = (char*)realloc((void*)*refbufp, *memsize);
|
*refbufp = (char*)realloc((void*)*refbufp, *memsize);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
@ -35,7 +39,11 @@ string _STR(const char *fmt, int nfmts, ...) {
|
||||||
va_list argptr;
|
va_list argptr;
|
||||||
int memsize = 128;
|
int memsize = 128;
|
||||||
int nbytes = 0;
|
int nbytes = 0;
|
||||||
|
#ifdef _VGCBOEHM
|
||||||
|
char* buf = (char*)GC_MALLOC(memsize);
|
||||||
|
#else
|
||||||
char* buf = (char*)malloc(memsize);
|
char* buf = (char*)malloc(memsize);
|
||||||
|
#endif
|
||||||
va_start(argptr, nfmts);
|
va_start(argptr, nfmts);
|
||||||
for (int i=0; i<nfmts; ++i) {
|
for (int i=0; i<nfmts; ++i) {
|
||||||
int k = strlen(fmt);
|
int k = strlen(fmt);
|
||||||
|
@ -84,11 +92,18 @@ string _STR(const char *fmt, int nfmts, ...) {
|
||||||
}
|
}
|
||||||
va_end(argptr);
|
va_end(argptr);
|
||||||
buf[nbytes] = 0;
|
buf[nbytes] = 0;
|
||||||
|
|
||||||
|
#ifdef _VGCBOEHM
|
||||||
|
buf = (char*)GC_REALLOC((void*)buf, nbytes+1);
|
||||||
|
#else
|
||||||
buf = (char*)realloc((void*)buf, nbytes+1);
|
buf = (char*)realloc((void*)buf, nbytes+1);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef DEBUG_ALLOC
|
#ifdef DEBUG_ALLOC
|
||||||
//puts('_STR:');
|
//puts('_STR:');
|
||||||
puts(buf);
|
puts(buf);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if _VAUTOFREE
|
#if _VAUTOFREE
|
||||||
//g_cur_str = (byteptr)buf;
|
//g_cur_str = (byteptr)buf;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -17,6 +17,11 @@ pub enum BuildMode {
|
||||||
build_module
|
build_module
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum GarbageCollectionMode {
|
||||||
|
no_gc
|
||||||
|
boehm
|
||||||
|
}
|
||||||
|
|
||||||
pub enum OutputMode {
|
pub enum OutputMode {
|
||||||
stdout
|
stdout
|
||||||
silent
|
silent
|
||||||
|
@ -153,6 +158,7 @@ pub mut:
|
||||||
build_options []string // list of options, that should be passed down to `build-module`, if needed for -usecache
|
build_options []string // list of options, that should be passed down to `build-module`, if needed for -usecache
|
||||||
cache_manager vcache.CacheManager
|
cache_manager vcache.CacheManager
|
||||||
is_help bool // -h, -help or --help was passed
|
is_help bool // -h, -help or --help was passed
|
||||||
|
gc_mode GarbageCollectionMode = .no_gc // .no_gc, .boehm
|
||||||
// checker settings:
|
// checker settings:
|
||||||
checker_match_exhaustive_cutoff_limit int = 10
|
checker_match_exhaustive_cutoff_limit int = 10
|
||||||
}
|
}
|
||||||
|
@ -177,7 +183,7 @@ pub fn parse_args(known_external_commands []string, args []string) (&Preferences
|
||||||
target_arch := cmdline.option(current_args, '-arch', '')
|
target_arch := cmdline.option(current_args, '-arch', '')
|
||||||
i++
|
i++
|
||||||
target_arch_kind := arch_from_string(target_arch) or {
|
target_arch_kind := arch_from_string(target_arch) or {
|
||||||
eprintln('unknown architercture target `$target_arch`')
|
eprintln('unknown architecture target `$target_arch`')
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
res.arch = target_arch_kind
|
res.arch = target_arch_kind
|
||||||
|
@ -214,6 +220,23 @@ pub fn parse_args(known_external_commands []string, args []string) (&Preferences
|
||||||
'-silent' {
|
'-silent' {
|
||||||
res.output_mode = .silent
|
res.output_mode = .silent
|
||||||
}
|
}
|
||||||
|
'-gc' {
|
||||||
|
gc_mode := cmdline.option(current_args, '-gc', '')
|
||||||
|
match gc_mode {
|
||||||
|
'' {
|
||||||
|
res.gc_mode = .no_gc
|
||||||
|
}
|
||||||
|
'boehm' {
|
||||||
|
res.gc_mode = .boehm
|
||||||
|
parse_define(mut res, 'gcboehm')
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
eprintln('unknown garbage collection mode, only `-gc boehm` is supported')
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
'-g' {
|
'-g' {
|
||||||
res.is_debug = true
|
res.is_debug = true
|
||||||
res.is_vlines = true
|
res.is_vlines = true
|
||||||
|
|
|
@ -40,6 +40,19 @@ pub fn (prefs &Preferences) should_compile_filtered_files(dir string, files_ []s
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if file.contains('_notd_') {
|
||||||
|
mut allowed := true
|
||||||
|
for cdefine in prefs.compile_defines {
|
||||||
|
file_postfix := '_notd_${cdefine}.v'
|
||||||
|
if file.ends_with(file_postfix) {
|
||||||
|
allowed = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !allowed {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
all_v_files << os.join_path(dir, file)
|
all_v_files << os.join_path(dir, file)
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
|
|
Loading…
Reference in New Issue