From 652e7ba973f2c1e7afd82994474345dd095a146e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kr=C3=BCger?= <45282134+UweKrueger@users.noreply.github.com> Date: Sat, 12 Jun 2021 10:27:08 +0200 Subject: [PATCH] gc: extend optimized mode to strings (#10431) --- vlib/builtin/array_notd_gcboehm_opt.v | 10 +++++ vlib/builtin/builtin.c.v | 59 ++++++++++++++++++++++++++- vlib/builtin/string.v | 40 +++++++++++------- 3 files changed, 94 insertions(+), 15 deletions(-) create mode 100644 vlib/builtin/array_notd_gcboehm_opt.v diff --git a/vlib/builtin/array_notd_gcboehm_opt.v b/vlib/builtin/array_notd_gcboehm_opt.v new file mode 100644 index 0000000000..170316733a --- /dev/null +++ b/vlib/builtin/array_notd_gcboehm_opt.v @@ -0,0 +1,10 @@ +// dummy placeholder for functions from `array_d_gcboehm_opt.v` +// that might be needed for compile time +// `$if gcboehm_opt ? { ... } $else { ... }` + +module builtin + +// this is needed in `string.v` +fn __new_array_noscan(mylen int, cap int, elm_size int) array { + return array{} +} diff --git a/vlib/builtin/builtin.c.v b/vlib/builtin/builtin.c.v index e73c45cb1d..29737d1671 100644 --- a/vlib/builtin/builtin.c.v +++ b/vlib/builtin/builtin.c.v @@ -256,6 +256,59 @@ pub fn malloc(n int) &byte { return res } +[unsafe] +pub fn malloc_noscan(n int) &byte { + if n <= 0 { + panic('> V malloc(<=0)') + } + $if vplayground ? { + if n > 10000 { + panic('allocating more than 10 KB at once is not allowed in the V playground') + } + if total_m > 50 * 1024 * 1024 { + panic('allocating more than 50 MB is not allowed in the V playground') + } + } + $if trace_malloc ? { + total_m += n + C.fprintf(C.stderr, c'v_malloc %6d total %10d\n', n, total_m) + // print_backtrace() + } + mut res := &byte(0) + $if prealloc { + return unsafe { prealloc_malloc(n) } + } $else $if gcboehm ? { + $if gcboehm_opt ? { + unsafe { + res = C.GC_MALLOC_ATOMIC(n) + } + } $else { + unsafe { + res = C.GC_MALLOC(n) + } + } + } $else $if freestanding { + mut e := Errno{} + res, e = mm_alloc(u64(n)) + if e != .enoerror { + eprint('malloc() failed: ') + eprintln(e.str()) + panic('malloc() failed') + } + } $else { + res = unsafe { C.malloc(n) } + } + if res == 0 { + panic('malloc($n) failed') + } + $if debug_malloc ? { + // Fill in the memory with something != 0, so it is easier to spot + // when the calling code wrongly relies on it being zeroed. + unsafe { C.memset(res, 0x88, n) } + } + return res +} + // v_realloc resizes the memory block `b` with `n` bytes. // The `b byteptr` must be a pointer to an existing memory block // previously allocated with `malloc`, `v_calloc` or `vcalloc`. @@ -369,7 +422,11 @@ pub fn vcalloc_noscan(n int) &byte { if n < 0 { panic('calloc(<0)') } - return unsafe { &byte(C.memset(C.GC_MALLOC_ATOMIC(n), 0, n)) } + return $if gcboehm_opt ? { + unsafe { &byte(C.memset(C.GC_MALLOC_ATOMIC(n), 0, n)) } + } $else { + unsafe { &byte(C.GC_MALLOC(n)) } + } } $else { return unsafe { vcalloc(n) } } diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index d8c48fb729..78bb2bd05b 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -248,7 +248,7 @@ pub fn (a string) clone() string { return '' } mut b := string{ - str: unsafe { malloc(a.len + 1) } + str: unsafe { malloc_noscan(a.len + 1) } len: a.len } unsafe { @@ -303,7 +303,7 @@ pub fn (s string) replace(rep string, with string) string { } // Now we know the number of replacements we need to do and we can calc the len of the new string new_len := s.len + idxs.len * (with.len - rep.len) - mut b := unsafe { malloc(new_len + 1) } // add space for the null byte at the end + mut b := unsafe { malloc_noscan(new_len + 1) } // add space for the null byte at the end // Fill the new string mut b_i := 0 mut s_idx := 0 @@ -406,7 +406,7 @@ pub fn (s string) replace_each(vals []string) string { return s.clone() } idxs.sort2() - mut b := unsafe { malloc(new_len + 1) } // add space for 0 terminator + mut b := unsafe { malloc_noscan(new_len + 1) } // add space for 0 terminator // Fill the new string mut idx_pos := 0 mut cur_idx := idxs[idx_pos] @@ -532,7 +532,7 @@ fn (s string) < (a string) bool { fn (s string) + (a string) string { new_len := a.len + s.len mut res := string{ - str: unsafe { malloc(new_len + 1) } + str: unsafe { malloc_noscan(new_len + 1) } len: new_len } for j in 0 .. s.len { @@ -676,7 +676,7 @@ pub fn (s string) substr(start int, end int) string { return s.clone() } mut res := string{ - str: unsafe { malloc(len + 1) } + str: unsafe { malloc_noscan(len + 1) } len: len } for i in 0 .. len { @@ -948,7 +948,7 @@ pub fn (s string) ends_with(p string) bool { // TODO only works with ASCII pub fn (s string) to_lower() string { unsafe { - mut b := malloc(s.len + 1) + mut b := malloc_noscan(s.len + 1) for i in 0 .. s.len { if s.str[i] >= `A` && s.str[i] <= `Z` { b[i] = s.str[i] + 32 @@ -977,7 +977,7 @@ pub fn (s string) is_lower() bool { // Example: assert 'Hello V'.to_upper() == 'HELLO V' pub fn (s string) to_upper() string { unsafe { - mut b := malloc(s.len + 1) + mut b := malloc_noscan(s.len + 1) for i in 0 .. s.len { if s.str[i] >= `a` && s.str[i] <= `z` { b[i] = s.str[i] - 32 @@ -1262,7 +1262,11 @@ pub fn (s string) ustring() ustring { mut res := ustring{ s: s // runes will have at least s.len elements, save reallocations // TODO use VLA for small strings? - runes: __new_array(0, s.len, int(sizeof(int))) + } + $if gcboehm_opt ? { + res.runes = __new_array_noscan(0, s.len, int(sizeof(int))) + } $else { + res.runes = __new_array(0, s.len, int(sizeof(int))) } for i := 0; i < s.len; i++ { char_len := utf8_char_len(unsafe { s.str[i] }) @@ -1282,7 +1286,11 @@ __global ( pub fn (s string) ustring_tmp() ustring { if g_ustring_runes.len == 0 { - g_ustring_runes = __new_array(0, 128, int(sizeof(int))) + $if gcboehm_opt ? { + g_ustring_runes = __new_array_noscan(0, 128, int(sizeof(int))) + } $else { + g_ustring_runes = __new_array(0, 128, int(sizeof(int))) + } } mut res := ustring{ s: s @@ -1311,7 +1319,11 @@ fn (u ustring) < (a ustring) bool { fn (u ustring) + (a ustring) ustring { mut res := ustring{ s: u.s + a.s - runes: __new_array(0, u.s.len + a.s.len, int(sizeof(int))) + } + $if gcboehm_opt ? { + res.runes = __new_array_noscan(0, u.s.len + a.s.len, int(sizeof(int))) + } $else { + res.runes = __new_array(0, u.s.len + a.s.len, int(sizeof(int))) } mut j := 0 for i := 0; i < u.s.len; i++ { @@ -1586,7 +1598,7 @@ pub fn (a []string) join(sep string) string { len -= sep.len // Allocate enough memory mut res := string{ - str: unsafe { malloc(len + 1) } + str: unsafe { malloc_noscan(len + 1) } len: len } mut idx := 0 @@ -1621,7 +1633,7 @@ pub fn (s string) reverse() string { return s.clone() } mut res := string{ - str: unsafe { malloc(s.len + 1) } + str: unsafe { malloc_noscan(s.len + 1) } len: s.len } for i := s.len - 1; i >= 0; i-- { @@ -1676,7 +1688,7 @@ pub fn (s string) repeat(count int) string { } else if count == 1 { return s.clone() } - mut ret := unsafe { malloc(s.len * count + 1) } + mut ret := unsafe { malloc_noscan(s.len * count + 1) } for i in 0 .. count { for j in 0 .. s.len { unsafe { @@ -1753,7 +1765,7 @@ pub fn (s string) strip_margin_custom(del byte) string { } // don't know how much space the resulting string will be, but the max it // can be is this big - mut ret := unsafe { malloc(s.len + 1) } + mut ret := unsafe { malloc_noscan(s.len + 1) } mut count := 0 for i := 0; i < s.len; i++ { if s[i] in [10, 13] {