From 6806086bf1b1dd9207ee86abefb4a40dc8207cdf Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Wed, 14 Jun 2023 15:00:36 +0300 Subject: [PATCH] builtin: zero out internal map/array pointers on m.free(), to reduce the work for the GC mark phase for non escaping maps/arrays, used in hot loops (#18415) --- vlib/builtin/array.v | 9 ++++++--- vlib/builtin/map.v | 26 +++++++++++++++++++++++--- vlib/builtin/string.v | 1 + 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/vlib/builtin/array.v b/vlib/builtin/array.v index 280fd475a7401e..2fa592c96149db 100644 --- a/vlib/builtin/array.v +++ b/vlib/builtin/array.v @@ -750,6 +750,9 @@ pub fn (a &array) free() { } mblock_ptr := &u8(u64(a.data) - u64(a.offset)) unsafe { free(mblock_ptr) } + unsafe { + a.data = nil + } } // Some of the following functions have no implementation in V and exist here @@ -867,12 +870,12 @@ pub fn (a array) contains(value voidptr) bool // or `-1` if the value is not found. pub fn (a array) index(value voidptr) int -[unsafe] +[direct_array_access; unsafe] pub fn (mut a []string) free() { $if prealloc { return } - for s in a { + for mut s in a { unsafe { s.free() } } unsafe { (&array(&a)).free() } @@ -883,7 +886,7 @@ pub fn (mut a []string) free() { // str returns a string representation of an array of strings // Example: ['a', 'b', 'c'].str() // => "['a', 'b', 'c']". -[manualfree] +[direct_array_access; manualfree] pub fn (a []string) str() string { mut sb_len := 4 // 2x" + 1x, + 1xspace if a.len > 0 { diff --git a/vlib/builtin/map.v b/vlib/builtin/map.v index 32cb33f9cfc016..8717a4599f4463 100644 --- a/vlib/builtin/map.v +++ b/vlib/builtin/map.v @@ -728,11 +728,15 @@ pub fn (m &map) clone() map { [unsafe] pub fn (m &map) free() { unsafe { free(m.metas) } + unsafe { + m.metas = nil + } if m.key_values.deletes == 0 { for i := 0; i < m.key_values.len; i++ { unsafe { pkey := m.key_values.key(i) m.free_fn(pkey) + vmemset(pkey, 0, m.key_bytes) } } } else { @@ -743,12 +747,28 @@ pub fn (m &map) free() { unsafe { pkey := m.key_values.key(i) m.free_fn(pkey) + vmemset(pkey, 0, m.key_bytes) } } - unsafe { free(m.key_values.all_deleted) } } unsafe { - free(m.key_values.keys) - free(m.key_values.values) + if m.key_values.all_deleted != nil { + free(m.key_values.all_deleted) + m.key_values.all_deleted = nil + } + if m.key_values.keys != nil { + free(m.key_values.keys) + m.key_values.keys = nil + } + if m.key_values.values != nil { + free(m.key_values.values) + m.key_values.values = nil + } + // TODO: the next lines assume that callback functions are static and independent from each particular + // map instance. Closures may invalidate that assumption, so revisit when RC for closures works. + m.hash_fn = nil + m.key_eq_fn = nil + m.clone_fn = nil + m.free_fn = nil } } diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index f47330bd0058f0..1d7cfd6c29516b 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -1838,6 +1838,7 @@ pub fn (s &string) free() { unsafe { // C.printf(c's: %x %s\n', s.str, s.str) free(s.str) + s.str = nil } s.is_lit = -98761234 }