From 5ee1ded3fb9301c4dd67d1cf18fd520da4beb4c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kr=C3=BCger?= <45282134+UweKrueger@users.noreply.github.com> Date: Sun, 13 Jun 2021 05:26:43 +0200 Subject: [PATCH] gc: extend optimized mode to maps (#10426) --- vlib/builtin/map.v | 2 +- vlib/builtin/map_d_gcboehm_opt.v | 146 +++++++++++++++++++++++++++++++ vlib/v/gen/c/cgen.v | 30 ++++++- vlib/v/markused/markused.v | 5 +- 4 files changed, 177 insertions(+), 6 deletions(-) create mode 100644 vlib/builtin/map_d_gcboehm_opt.v diff --git a/vlib/builtin/map.v b/vlib/builtin/map.v index 91e473e9e7..37b2e49317 100644 --- a/vlib/builtin/map.v +++ b/vlib/builtin/map.v @@ -338,7 +338,7 @@ fn new_map(key_bytes int, value_bytes int, hash_fn MapHashFn, key_eq_fn MapEqFn, cached_hashbits: max_cached_hashbits shift: init_log_capicity key_values: new_dense_array(key_bytes, value_bytes) - metas: unsafe { &u32(vcalloc(metasize)) } + metas: unsafe { &u32(vcalloc_noscan(metasize)) } extra_metas: extra_metas_inc len: 0 has_string_keys: has_string_keys diff --git a/vlib/builtin/map_d_gcboehm_opt.v b/vlib/builtin/map_d_gcboehm_opt.v new file mode 100644 index 0000000000..93049b7212 --- /dev/null +++ b/vlib/builtin/map_d_gcboehm_opt.v @@ -0,0 +1,146 @@ +// "noscan" versions of `map` initialization routines +// +// They are used when the compiler can proof that either the keys or the values or both +// do not contain any pointers. Such objects can be placed in a memory area that is not +// scanned by the garbage collector + +module builtin + +[inline] +fn new_dense_array_noscan(key_bytes int, key_noscan bool, value_bytes int, value_noscan bool) DenseArray { + cap := 8 + keys := if key_noscan { + unsafe { malloc_noscan(cap * key_bytes) } + } else { + unsafe { malloc(cap * key_bytes) } + } + values := if value_noscan { + unsafe { malloc_noscan(cap * value_bytes) } + } else { + unsafe { malloc(cap * value_bytes) } + } + return DenseArray{ + key_bytes: key_bytes + value_bytes: value_bytes + cap: cap + len: 0 + deletes: 0 + all_deleted: 0 + keys: keys + values: values + } +} + +fn new_map_noscan_key(key_bytes int, value_bytes int, hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn, free_fn MapFreeFn) map { + metasize := int(sizeof(u32) * (init_capicity + extra_metas_inc)) + // for now assume anything bigger than a pointer is a string + has_string_keys := key_bytes > sizeof(voidptr) + return map{ + key_bytes: key_bytes + value_bytes: value_bytes + even_index: init_even_index + cached_hashbits: max_cached_hashbits + shift: init_log_capicity + key_values: new_dense_array_noscan(key_bytes, true, value_bytes, false) + metas: unsafe { &u32(vcalloc_noscan(metasize)) } + extra_metas: extra_metas_inc + len: 0 + has_string_keys: has_string_keys + hash_fn: hash_fn + key_eq_fn: key_eq_fn + clone_fn: clone_fn + free_fn: free_fn + } +} + +fn new_map_noscan_value(key_bytes int, value_bytes int, hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn, free_fn MapFreeFn) map { + metasize := int(sizeof(u32) * (init_capicity + extra_metas_inc)) + // for now assume anything bigger than a pointer is a string + has_string_keys := key_bytes > sizeof(voidptr) + return map{ + key_bytes: key_bytes + value_bytes: value_bytes + even_index: init_even_index + cached_hashbits: max_cached_hashbits + shift: init_log_capicity + key_values: new_dense_array_noscan(key_bytes, false, value_bytes, true) + metas: unsafe { &u32(vcalloc_noscan(metasize)) } + extra_metas: extra_metas_inc + len: 0 + has_string_keys: has_string_keys + hash_fn: hash_fn + key_eq_fn: key_eq_fn + clone_fn: clone_fn + free_fn: free_fn + } +} + +fn new_map_noscan_key_value(key_bytes int, value_bytes int, hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn, free_fn MapFreeFn) map { + metasize := int(sizeof(u32) * (init_capicity + extra_metas_inc)) + // for now assume anything bigger than a pointer is a string + has_string_keys := key_bytes > sizeof(voidptr) + return map{ + key_bytes: key_bytes + value_bytes: value_bytes + even_index: init_even_index + cached_hashbits: max_cached_hashbits + shift: init_log_capicity + key_values: new_dense_array_noscan(key_bytes, true, value_bytes, true) + metas: unsafe { &u32(vcalloc_noscan(metasize)) } + extra_metas: extra_metas_inc + len: 0 + has_string_keys: has_string_keys + hash_fn: hash_fn + key_eq_fn: key_eq_fn + clone_fn: clone_fn + free_fn: free_fn + } +} + +fn new_map_init_noscan_key(hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn, free_fn MapFreeFn, n int, key_bytes int, value_bytes int, keys voidptr, values voidptr) map { + mut out := new_map_noscan_key(key_bytes, value_bytes, hash_fn, key_eq_fn, clone_fn, + free_fn) + // TODO pre-allocate n slots + mut pkey := &byte(keys) + mut pval := &byte(values) + for _ in 0 .. n { + unsafe { + out.set(pkey, pval) + pkey = pkey + key_bytes + pval = pval + value_bytes + } + } + return out +} + +fn new_map_init_noscan_value(hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn, free_fn MapFreeFn, n int, key_bytes int, value_bytes int, keys voidptr, values voidptr) map { + mut out := new_map_noscan_value(key_bytes, value_bytes, hash_fn, key_eq_fn, clone_fn, + free_fn) + // TODO pre-allocate n slots + mut pkey := &byte(keys) + mut pval := &byte(values) + for _ in 0 .. n { + unsafe { + out.set(pkey, pval) + pkey = pkey + key_bytes + pval = pval + value_bytes + } + } + return out +} + +fn new_map_init_noscan_key_value(hash_fn MapHashFn, key_eq_fn MapEqFn, clone_fn MapCloneFn, free_fn MapFreeFn, n int, key_bytes int, value_bytes int, keys voidptr, values voidptr) map { + mut out := new_map_noscan_key_value(key_bytes, value_bytes, hash_fn, key_eq_fn, clone_fn, + free_fn) + // TODO pre-allocate n slots + mut pkey := &byte(keys) + mut pval := &byte(values) + for _ in 0 .. n { + unsafe { + out.set(pkey, pval) + pkey = pkey + key_bytes + pval = pval + value_bytes + } + } + return out +} diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index fc04e0e0d2..73ad9f4638 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -4335,11 +4335,22 @@ fn (mut g Gen) map_init(node ast.MapInit) { styp = g.typ(node.typ) g.write('($styp*)memdup(ADDR($styp, ') } + noscan_key := g.check_noscan(node.key_type) + noscan_value := g.check_noscan(node.value_type) + mut noscan := if noscan_key.len != 0 || noscan_value.len != 0 { '_noscan' } else { '' } + if noscan.len != 0 { + if noscan_key.len != 0 { + noscan += '_key' + } + if noscan_value.len != 0 { + noscan += '_value' + } + } if size > 0 { if value_typ.kind == .function { - g.write('new_map_init($hash_fn, $key_eq_fn, $clone_fn, $free_fn, $size, sizeof($key_typ_str), sizeof(voidptr), _MOV(($key_typ_str[$size]){') + g.write('new_map_init${noscan}($hash_fn, $key_eq_fn, $clone_fn, $free_fn, $size, sizeof($key_typ_str), sizeof(voidptr), _MOV(($key_typ_str[$size]){') } else { - g.write('new_map_init($hash_fn, $key_eq_fn, $clone_fn, $free_fn, $size, sizeof($key_typ_str), sizeof($value_typ_str), _MOV(($key_typ_str[$size]){') + g.write('new_map_init${noscan}($hash_fn, $key_eq_fn, $clone_fn, $free_fn, $size, sizeof($key_typ_str), sizeof($value_typ_str), _MOV(($key_typ_str[$size]){') } for expr in node.keys { g.expr(expr) @@ -4359,7 +4370,7 @@ fn (mut g Gen) map_init(node ast.MapInit) { } g.write('}))') } else { - g.write('new_map(sizeof($key_typ_str), sizeof($value_typ_str), $hash_fn, $key_eq_fn, $clone_fn, $free_fn)') + g.write('new_map${noscan}(sizeof($key_typ_str), sizeof($value_typ_str), $hash_fn, $key_eq_fn, $clone_fn, $free_fn)') } if g.is_shared { g.write('}, sizeof($shared_styp))') @@ -6076,7 +6087,18 @@ fn (mut g Gen) type_default(typ_ ast.Type) string { info := sym.map_info() key_typ := g.table.get_type_symbol(info.key_type) hash_fn, key_eq_fn, clone_fn, free_fn := g.map_fn_ptrs(key_typ) - init_str := 'new_map(sizeof(${g.typ(info.key_type)}), sizeof(${g.typ(info.value_type)}), $hash_fn, $key_eq_fn, $clone_fn, $free_fn)' + noscan_key := g.check_noscan(info.key_type) + noscan_value := g.check_noscan(info.value_type) + mut noscan := if noscan_key.len != 0 || noscan_value.len != 0 { '_noscan' } else { '' } + if noscan.len != 0 { + if noscan_key.len != 0 { + noscan += '_key' + } + if noscan_value.len != 0 { + noscan += '_value' + } + } + init_str := 'new_map${noscan}(sizeof(${g.typ(info.key_type)}), sizeof(${g.typ(info.value_type)}), $hash_fn, $key_eq_fn, $clone_fn, $free_fn)' if typ.has_flag(.shared_f) { mtyp := '__shared__Map_${key_typ.cname}_${g.table.get_type_symbol(info.value_type).cname}' return '($mtyp*)__dup_shared_map(&($mtyp){.mtx = {0}, .val =$init_str}, sizeof($mtyp))' diff --git a/vlib/v/markused/markused.v b/vlib/v/markused/markused.v index 21c081b4a3..989d41c6f7 100644 --- a/vlib/v/markused/markused.v +++ b/vlib/v/markused/markused.v @@ -21,7 +21,10 @@ pub fn mark_used(mut table ast.Table, pref &pref.Preferences, ast_files []&ast.F '__new_array_with_default', '__new_array_with_array_default', 'v_realloc' /* needed for _STR */, - 'v_malloc' /* needed for _STR */, + 'malloc', + 'malloc_noscan', + 'vcalloc', + 'vcalloc_noscan', 'new_array_from_c_array', 'v_fixed_index', 'memdup',