gc: extend optimized mode to maps (#10426)
parent
2ac39d9112
commit
5ee1ded3fb
|
@ -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
|
cached_hashbits: max_cached_hashbits
|
||||||
shift: init_log_capicity
|
shift: init_log_capicity
|
||||||
key_values: new_dense_array(key_bytes, value_bytes)
|
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
|
extra_metas: extra_metas_inc
|
||||||
len: 0
|
len: 0
|
||||||
has_string_keys: has_string_keys
|
has_string_keys: has_string_keys
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -4335,11 +4335,22 @@ fn (mut g Gen) map_init(node ast.MapInit) {
|
||||||
styp = g.typ(node.typ)
|
styp = g.typ(node.typ)
|
||||||
g.write('($styp*)memdup(ADDR($styp, ')
|
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 size > 0 {
|
||||||
if value_typ.kind == .function {
|
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 {
|
} 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 {
|
for expr in node.keys {
|
||||||
g.expr(expr)
|
g.expr(expr)
|
||||||
|
@ -4359,7 +4370,7 @@ fn (mut g Gen) map_init(node ast.MapInit) {
|
||||||
}
|
}
|
||||||
g.write('}))')
|
g.write('}))')
|
||||||
} else {
|
} 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 {
|
if g.is_shared {
|
||||||
g.write('}, sizeof($shared_styp))')
|
g.write('}, sizeof($shared_styp))')
|
||||||
|
@ -6076,7 +6087,18 @@ fn (mut g Gen) type_default(typ_ ast.Type) string {
|
||||||
info := sym.map_info()
|
info := sym.map_info()
|
||||||
key_typ := g.table.get_type_symbol(info.key_type)
|
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)
|
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) {
|
if typ.has_flag(.shared_f) {
|
||||||
mtyp := '__shared__Map_${key_typ.cname}_${g.table.get_type_symbol(info.value_type).cname}'
|
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))'
|
return '($mtyp*)__dup_shared_map(&($mtyp){.mtx = {0}, .val =$init_str}, sizeof($mtyp))'
|
||||||
|
|
|
@ -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_default',
|
||||||
'__new_array_with_array_default',
|
'__new_array_with_array_default',
|
||||||
'v_realloc' /* needed for _STR */,
|
'v_realloc' /* needed for _STR */,
|
||||||
'v_malloc' /* needed for _STR */,
|
'malloc',
|
||||||
|
'malloc_noscan',
|
||||||
|
'vcalloc',
|
||||||
|
'vcalloc_noscan',
|
||||||
'new_array_from_c_array',
|
'new_array_from_c_array',
|
||||||
'v_fixed_index',
|
'v_fixed_index',
|
||||||
'memdup',
|
'memdup',
|
||||||
|
|
Loading…
Reference in New Issue