GC-boehm: extend optimized mode to all `array` methods (#10406)
							parent
							
								
									9a9d539e6f
								
							
						
					
					
						commit
						0e2c86310a
					
				| 
						 | 
				
			
			@ -647,7 +647,11 @@ pub fn (data &byte) vbytes(len int) []byte {
 | 
			
		|||
	return unsafe { voidptr(data).vbytes(len) }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// non-pub "noscan" versions of some above functions
 | 
			
		||||
// non-pub versions of array functions
 | 
			
		||||
// that allocale new memory using `GC_MALLOC_ATOMIC()`
 | 
			
		||||
// when `-gc boehm_*_opt` is used. These memory areas are not
 | 
			
		||||
// scanned for pointers.
 | 
			
		||||
 | 
			
		||||
fn __new_array_noscan(mylen int, cap int, elm_size int) array {
 | 
			
		||||
	cap_ := if cap < mylen { mylen } else { cap }
 | 
			
		||||
	arr := array{
 | 
			
		||||
| 
						 | 
				
			
			@ -704,6 +708,26 @@ fn new_array_from_c_array_noscan(len int, cap int, elm_size int, c_array voidptr
 | 
			
		|||
	return arr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Private function. Doubles array capacity if needed.
 | 
			
		||||
fn (mut a array) ensure_cap_noscan(required int) {
 | 
			
		||||
	if required <= a.cap {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	mut cap := if a.cap > 0 { a.cap } else { 2 }
 | 
			
		||||
	for required > cap {
 | 
			
		||||
		cap *= 2
 | 
			
		||||
	}
 | 
			
		||||
	new_size := cap * a.element_size
 | 
			
		||||
	new_data := vcalloc_noscan(new_size)
 | 
			
		||||
	if a.data != voidptr(0) {
 | 
			
		||||
		unsafe { C.memcpy(new_data, a.data, a.len * a.element_size) }
 | 
			
		||||
		// TODO: the old data may be leaked when no GC is used (ref-counting?)
 | 
			
		||||
	}
 | 
			
		||||
	a.data = new_data
 | 
			
		||||
	a.offset = 0
 | 
			
		||||
	a.cap = cap
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// repeat returns a new array with the given array elements repeated given times.
 | 
			
		||||
// `cgen` will replace this with an apropriate call to `repeat_to_depth()`
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -737,14 +761,83 @@ fn (a array) repeat_to_depth_noscan(count int, depth int) array {
 | 
			
		|||
	return arr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn (a &array) clone_to_depth_noscan(depth int) array {
 | 
			
		||||
// insert inserts a value in the array at index `i`
 | 
			
		||||
fn (mut a array) insert_noscan(i int, val voidptr) {
 | 
			
		||||
	$if !no_bounds_checking ? {
 | 
			
		||||
		if i < 0 || i > a.len {
 | 
			
		||||
			panic('array.insert: index out of range (i == $i, a.len == $a.len)')
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	a.ensure_cap_noscan(a.len + 1)
 | 
			
		||||
	unsafe {
 | 
			
		||||
		C.memmove(a.get_unsafe(i + 1), a.get_unsafe(i), (a.len - i) * a.element_size)
 | 
			
		||||
		a.set_unsafe(i, val)
 | 
			
		||||
	}
 | 
			
		||||
	a.len++
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// insert_many inserts many values into the array from index `i`.
 | 
			
		||||
[unsafe]
 | 
			
		||||
fn (mut a array) insert_many_noscan(i int, val voidptr, size int) {
 | 
			
		||||
	$if !no_bounds_checking ? {
 | 
			
		||||
		if i < 0 || i > a.len {
 | 
			
		||||
			panic('array.insert_many: index out of range (i == $i, a.len == $a.len)')
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	a.ensure_cap_noscan(a.len + size)
 | 
			
		||||
	elem_size := a.element_size
 | 
			
		||||
	unsafe {
 | 
			
		||||
		iptr := a.get_unsafe(i)
 | 
			
		||||
		C.memmove(a.get_unsafe(i + size), iptr, (a.len - i) * elem_size)
 | 
			
		||||
		C.memcpy(iptr, val, size * elem_size)
 | 
			
		||||
	}
 | 
			
		||||
	a.len += size
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// prepend prepends one value to the array.
 | 
			
		||||
fn (mut a array) prepend_noscan(val voidptr) {
 | 
			
		||||
	a.insert_noscan(0, val)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// prepend_many prepends another array to this array.
 | 
			
		||||
[unsafe]
 | 
			
		||||
fn (mut a array) prepend_many_noscan(val voidptr, size int) {
 | 
			
		||||
	unsafe { a.insert_many_noscan(0, val, size) }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// pop returns the last element of the array, and removes it.
 | 
			
		||||
fn (mut a array) pop_noscan() voidptr {
 | 
			
		||||
	// in a sense, this is the opposite of `a << x`
 | 
			
		||||
	$if !no_bounds_checking ? {
 | 
			
		||||
		if a.len == 0 {
 | 
			
		||||
			panic('array.pop: array is empty')
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	new_len := a.len - 1
 | 
			
		||||
	last_elem := unsafe { &byte(a.data) + new_len * a.element_size }
 | 
			
		||||
	a.len = new_len
 | 
			
		||||
	// NB: a.cap is not changed here *on purpose*, so that
 | 
			
		||||
	// further << ops on that array will be more efficient.
 | 
			
		||||
	return unsafe { memdup_noscan(last_elem, a.element_size) }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// `clone_static_to_depth_noscan()` returns an independent copy of a given array.
 | 
			
		||||
// Unlike `clone_to_depth_noscan()` it has a value receiver and is used internally
 | 
			
		||||
// for slice-clone expressions like `a[2..4].clone()` and in -autofree generated code.
 | 
			
		||||
fn (a array) clone_static_to_depth_noscan(depth int) array {
 | 
			
		||||
	return unsafe { a.clone_to_depth_noscan(depth) }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// recursively clone given array - `unsafe` when called directly because depth is not checked
 | 
			
		||||
[unsafe]
 | 
			
		||||
fn (a &array) clone_to_depth_noscan(depth int) array {
 | 
			
		||||
	mut size := a.cap * a.element_size
 | 
			
		||||
	if size == 0 {
 | 
			
		||||
		size++
 | 
			
		||||
	}
 | 
			
		||||
	mut arr := array{
 | 
			
		||||
		element_size: a.element_size
 | 
			
		||||
		data: if depth > 0 { vcalloc(size) } else { vcalloc_noscan(size) }
 | 
			
		||||
		data: if depth == 0 { vcalloc_noscan(size) } else { vcalloc(size) }
 | 
			
		||||
		len: a.len
 | 
			
		||||
		cap: a.cap
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -765,6 +858,34 @@ pub fn (a &array) clone_to_depth_noscan(depth int) array {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn (mut a array) push_noscan(val voidptr) {
 | 
			
		||||
	a.ensure_cap_noscan(a.len + 1)
 | 
			
		||||
	unsafe { C.memmove(&byte(a.data) + a.element_size * a.len, val, a.element_size) }
 | 
			
		||||
	a.len++
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// push_many implements the functionality for pushing another array.
 | 
			
		||||
// `val` is array.data and user facing usage is `a << [1,2,3]`
 | 
			
		||||
[unsafe]
 | 
			
		||||
fn (mut a3 array) push_many_noscan(val voidptr, size int) {
 | 
			
		||||
	if a3.data == val && !isnil(a3.data) {
 | 
			
		||||
		// handle `arr << arr`
 | 
			
		||||
		copy := a3.clone()
 | 
			
		||||
		a3.ensure_cap_noscan(a3.len + size)
 | 
			
		||||
		unsafe {
 | 
			
		||||
			// C.memcpy(a.data, copy.data, copy.element_size * copy.len)
 | 
			
		||||
			C.memcpy(a3.get_unsafe(a3.len), copy.data, a3.element_size * size)
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		a3.ensure_cap_noscan(a3.len + size)
 | 
			
		||||
		if !isnil(a3.data) && !isnil(val) {
 | 
			
		||||
			unsafe { C.memcpy(a3.get_unsafe(a3.len), val, a3.element_size * size) }
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	a3.len += size
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// reverse returns a new array with the elements of the original array in reverse order.
 | 
			
		||||
fn (a array) reverse_noscan() array {
 | 
			
		||||
	if a.len < 2 {
 | 
			
		||||
		return a
 | 
			
		||||
| 
						 | 
				
			
			@ -780,3 +901,15 @@ fn (a array) reverse_noscan() array {
 | 
			
		|||
	}
 | 
			
		||||
	return arr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// grow_cap grows the array's capacity by `amount` elements.
 | 
			
		||||
fn (mut a array) grow_cap_noscan(amount int) {
 | 
			
		||||
	a.ensure_cap_noscan(a.cap + amount)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// grow_len ensures that an array has a.len + amount of length
 | 
			
		||||
[unsafe]
 | 
			
		||||
fn (mut a array) grow_len_noscan(amount int) {
 | 
			
		||||
	a.ensure_cap_noscan(a.len + amount)
 | 
			
		||||
	a.len += amount
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -408,6 +408,17 @@ pub fn memdup(src voidptr, sz int) voidptr {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[unsafe]
 | 
			
		||||
pub fn memdup_noscan(src voidptr, sz int) voidptr {
 | 
			
		||||
	if sz == 0 {
 | 
			
		||||
		return vcalloc_noscan(1)
 | 
			
		||||
	}
 | 
			
		||||
	unsafe {
 | 
			
		||||
		mem := vcalloc_noscan(sz)
 | 
			
		||||
		return C.memcpy(mem, src, sz)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
[inline]
 | 
			
		||||
fn v_fixed_index(i int, len int) int {
 | 
			
		||||
	$if !no_bounds_checking ? {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,10 +47,10 @@ fn (mut g Gen) array_init(node ast.ArrayInit) {
 | 
			
		|||
		return
 | 
			
		||||
	}
 | 
			
		||||
	elem_type_str := g.typ(node.elem_type)
 | 
			
		||||
	noscan := g.check_noscan(node.elem_type)
 | 
			
		||||
	if node.exprs.len == 0 {
 | 
			
		||||
		elem_sym := g.table.get_type_symbol(node.elem_type)
 | 
			
		||||
		is_default_array := elem_sym.kind == .array && node.has_default
 | 
			
		||||
		noscan := g.check_noscan(node.elem_type)
 | 
			
		||||
		if is_default_array {
 | 
			
		||||
			g.write('__new_array_with_array_default${noscan}(')
 | 
			
		||||
		} else {
 | 
			
		||||
| 
						 | 
				
			
			@ -104,7 +104,7 @@ fn (mut g Gen) array_init(node ast.ArrayInit) {
 | 
			
		|||
	if elem_sym.kind == .function {
 | 
			
		||||
		g.write('new_array_from_c_array($len, $len, sizeof(voidptr), _MOV((voidptr[$len]){')
 | 
			
		||||
	} else {
 | 
			
		||||
		g.write('new_array_from_c_array($len, $len, sizeof($elem_type_str), _MOV(($elem_type_str[$len]){')
 | 
			
		||||
		g.write('new_array_from_c_array${noscan}($len, $len, sizeof($elem_type_str), _MOV(($elem_type_str[$len]){')
 | 
			
		||||
	}
 | 
			
		||||
	if len > 8 {
 | 
			
		||||
		g.writeln('')
 | 
			
		||||
| 
						 | 
				
			
			@ -194,7 +194,7 @@ fn (mut g Gen) gen_array_map(node ast.CallExpr) {
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
	g.writeln(';')
 | 
			
		||||
	g.writeln('\tarray_push((array*)&$tmp, &ti);')
 | 
			
		||||
	g.writeln('\tarray_push${noscan}((array*)&$tmp, &ti);')
 | 
			
		||||
	g.writeln('}')
 | 
			
		||||
	if !is_embed_map_filter {
 | 
			
		||||
		g.stmt_path_pos << g.out.len
 | 
			
		||||
| 
						 | 
				
			
			@ -387,7 +387,7 @@ fn (mut g Gen) gen_array_filter(node ast.CallExpr) {
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
	g.writeln(') {')
 | 
			
		||||
	g.writeln('\t\tarray_push((array*)&$tmp, &it); \n\t\t}')
 | 
			
		||||
	g.writeln('\t\tarray_push${noscan}((array*)&$tmp, &it); \n\t\t}')
 | 
			
		||||
	g.writeln('}')
 | 
			
		||||
	if !is_embed_map_filter {
 | 
			
		||||
		g.stmt_path_pos << g.out.len
 | 
			
		||||
| 
						 | 
				
			
			@ -404,10 +404,11 @@ fn (mut g Gen) gen_array_insert(node ast.CallExpr) {
 | 
			
		|||
	elem_type_str := g.typ(left_info.elem_type)
 | 
			
		||||
	arg2_sym := g.table.get_type_symbol(node.args[1].typ)
 | 
			
		||||
	is_arg2_array := arg2_sym.kind == .array && node.args[1].typ == node.left_type
 | 
			
		||||
	noscan := g.check_noscan(left_info.elem_type)
 | 
			
		||||
	if is_arg2_array {
 | 
			
		||||
		g.write('array_insert_many(&')
 | 
			
		||||
		g.write('array_insert_many${noscan}(&')
 | 
			
		||||
	} else {
 | 
			
		||||
		g.write('array_insert(&')
 | 
			
		||||
		g.write('array_insert${noscan}(&')
 | 
			
		||||
	}
 | 
			
		||||
	g.expr(node.left)
 | 
			
		||||
	g.write(', ')
 | 
			
		||||
| 
						 | 
				
			
			@ -438,10 +439,11 @@ fn (mut g Gen) gen_array_prepend(node ast.CallExpr) {
 | 
			
		|||
	elem_type_str := g.typ(left_info.elem_type)
 | 
			
		||||
	arg_sym := g.table.get_type_symbol(node.args[0].typ)
 | 
			
		||||
	is_arg_array := arg_sym.kind == .array && node.args[0].typ == node.left_type
 | 
			
		||||
	noscan := g.check_noscan(left_info.elem_type)
 | 
			
		||||
	if is_arg_array {
 | 
			
		||||
		g.write('array_prepend_many(&')
 | 
			
		||||
		g.write('array_prepend_many${noscan}(&')
 | 
			
		||||
	} else {
 | 
			
		||||
		g.write('array_prepend(&')
 | 
			
		||||
		g.write('array_prepend${noscan}(&')
 | 
			
		||||
	}
 | 
			
		||||
	g.expr(node.left)
 | 
			
		||||
	if is_arg_array {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2274,16 +2274,17 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
 | 
			
		|||
					}
 | 
			
		||||
				}
 | 
			
		||||
				g.expr(lx)
 | 
			
		||||
				noscan := if is_auto_heap { g.check_noscan(return_type) } else { '' }
 | 
			
		||||
				if is_opt {
 | 
			
		||||
					mr_base_styp := g.base_type(return_type)
 | 
			
		||||
					if is_auto_heap {
 | 
			
		||||
						g.writeln(' = HEAP($mr_base_styp, *($mr_base_styp*)${mr_var_name}.data).arg$i);')
 | 
			
		||||
						g.writeln(' = HEAP${noscan}($mr_base_styp, *($mr_base_styp*)${mr_var_name}.data).arg$i);')
 | 
			
		||||
					} else {
 | 
			
		||||
						g.writeln(' = (*($mr_base_styp*)${mr_var_name}.data).arg$i;')
 | 
			
		||||
					}
 | 
			
		||||
				} else {
 | 
			
		||||
					if is_auto_heap {
 | 
			
		||||
						g.writeln(' = HEAP($styp, ${mr_var_name}.arg$i);')
 | 
			
		||||
						g.writeln(' = HEAP${noscan}($styp, ${mr_var_name}.arg$i);')
 | 
			
		||||
					} else {
 | 
			
		||||
						g.writeln(' = ${mr_var_name}.arg$i;')
 | 
			
		||||
					}
 | 
			
		||||
| 
						 | 
				
			
			@ -3750,9 +3751,10 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
 | 
			
		|||
		// arr << val
 | 
			
		||||
		tmp := g.new_tmp_var()
 | 
			
		||||
		info := left_final_sym.info as ast.Array
 | 
			
		||||
		noscan := g.check_noscan(info.elem_type)
 | 
			
		||||
		if right_final_sym.kind == .array && info.elem_type != g.unwrap_generic(node.right_type) {
 | 
			
		||||
			// push an array => PUSH_MANY, but not if pushing an array to 2d array (`[][]int << []int`)
 | 
			
		||||
			g.write('_PUSH_MANY(')
 | 
			
		||||
			g.write('_PUSH_MANY${noscan}(')
 | 
			
		||||
			mut expected_push_many_atype := left_type
 | 
			
		||||
			if !expected_push_many_atype.is_ptr() {
 | 
			
		||||
				// fn f(mut a []int) { a << [1,2,3] } -> type of `a` is `array_int*` -> no need for &
 | 
			
		||||
| 
						 | 
				
			
			@ -3769,7 +3771,7 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
 | 
			
		|||
			// push a single element
 | 
			
		||||
			elem_type_str := g.typ(info.elem_type)
 | 
			
		||||
			elem_sym := g.table.get_type_symbol(info.elem_type)
 | 
			
		||||
			g.write('array_push((array*)')
 | 
			
		||||
			g.write('array_push${noscan}((array*)')
 | 
			
		||||
			if !left_type.is_ptr() {
 | 
			
		||||
				g.write('&')
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -6653,6 +6655,15 @@ pub fn (mut g Gen) contains_ptr(el_typ ast.Type) bool {
 | 
			
		|||
			}
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		.multi_return {
 | 
			
		||||
			info := sym.info as ast.MultiReturn
 | 
			
		||||
			for mrtyp in info.types {
 | 
			
		||||
				if g.contains_ptr(mrtyp) {
 | 
			
		||||
					return true
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -201,7 +201,9 @@ const c_helper_macros = '//============================== HELPER C MACROS ======
 | 
			
		|||
#define ADDR(type, expr) (&((type[]){expr}[0]))
 | 
			
		||||
// copy something to the heap
 | 
			
		||||
#define HEAP(type, expr) ((type*)memdup((void*)&((type[]){expr}[0]), sizeof(type)))
 | 
			
		||||
#define HEAP_noscan(type, expr) ((type*)memdup_noscan((void*)&((type[]){expr}[0]), sizeof(type)))
 | 
			
		||||
#define _PUSH_MANY(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array_push_many(arr, tmp.data, tmp.len);}
 | 
			
		||||
#define _PUSH_MANY_noscan(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array_push_many_noscan(arr, tmp.data, tmp.len);}
 | 
			
		||||
'
 | 
			
		||||
 | 
			
		||||
const c_headers = c_helper_macros + c_unsigned_comparison_functions + c_common_macros +
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -650,11 +650,19 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
 | 
			
		|||
	}
 | 
			
		||||
	mut name := util.no_dots('${receiver_type_name}_$node.name')
 | 
			
		||||
	mut array_depth := -1
 | 
			
		||||
	mut noscan := ''
 | 
			
		||||
	if left_sym.kind == .array {
 | 
			
		||||
		if node.name in ['clone', 'repeat'] {
 | 
			
		||||
		needs_depth := node.name in ['clone', 'repeat']
 | 
			
		||||
		if needs_depth {
 | 
			
		||||
			elem_type := (left_sym.info as ast.Array).elem_type
 | 
			
		||||
			array_depth = g.get_array_depth(elem_type)
 | 
			
		||||
		}
 | 
			
		||||
		maybe_noscan := needs_depth
 | 
			
		||||
			|| node.name in ['pop', 'push', 'push_many', 'reverse', 'grow_cap', 'grow_len']
 | 
			
		||||
		if maybe_noscan {
 | 
			
		||||
			info := left_sym.info as ast.Array
 | 
			
		||||
			noscan = g.check_noscan(info.elem_type)
 | 
			
		||||
		}
 | 
			
		||||
	} else if left_sym.kind == .chan {
 | 
			
		||||
		if node.name in ['close', 'try_pop', 'try_push'] {
 | 
			
		||||
			name = 'sync__Channel_$node.name'
 | 
			
		||||
| 
						 | 
				
			
			@ -708,10 +716,14 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
 | 
			
		|||
	if !node.receiver_type.is_ptr() && node.left_type.is_ptr() && node.name == 'str' {
 | 
			
		||||
		g.write('ptr_str(')
 | 
			
		||||
	} else {
 | 
			
		||||
		if array_depth >= 0 {
 | 
			
		||||
			name = name + '_to_depth'
 | 
			
		||||
		if left_sym.kind == .array {
 | 
			
		||||
			if array_depth >= 0 {
 | 
			
		||||
				name = name + '_to_depth'
 | 
			
		||||
			}
 | 
			
		||||
			g.write('$name${noscan}(')
 | 
			
		||||
		} else {
 | 
			
		||||
			g.write('${name}(')
 | 
			
		||||
		}
 | 
			
		||||
		g.write('${name}(')
 | 
			
		||||
	}
 | 
			
		||||
	if node.receiver_type.is_ptr() && (!node.left_type.is_ptr()
 | 
			
		||||
		|| node.from_embed_type != 0 || (node.left_type.has_flag(.shared_f) && node.name != 'str')) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1167,7 +1179,8 @@ fn (mut g Gen) call_args(node ast.CallExpr) {
 | 
			
		|||
			g.expr(args[args.len - 1].expr)
 | 
			
		||||
		} else {
 | 
			
		||||
			if variadic_count > 0 {
 | 
			
		||||
				g.write('new_array_from_c_array($variadic_count, $variadic_count, sizeof($elem_type), _MOV(($elem_type[$variadic_count]){')
 | 
			
		||||
				noscan := g.check_noscan(arr_info.elem_type)
 | 
			
		||||
				g.write('new_array_from_c_array${noscan}($variadic_count, $variadic_count, sizeof($elem_type), _MOV(($elem_type[$variadic_count]){')
 | 
			
		||||
				for j in arg_nr .. args.len {
 | 
			
		||||
					g.ref_or_deref_arg(args[j], arr_info.elem_type, node.language)
 | 
			
		||||
					if j < args.len - 1 {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -54,7 +54,8 @@ fn (mut g Gen) range_expr(node ast.IndexExpr, range ast.RangeExpr) {
 | 
			
		|||
	} else if sym.kind == .array_fixed {
 | 
			
		||||
		// Convert a fixed array to V array when doing `fixed_arr[start..end]`
 | 
			
		||||
		info := sym.info as ast.ArrayFixed
 | 
			
		||||
		g.write('array_slice(new_array_from_c_array(')
 | 
			
		||||
		noscan := g.check_noscan(info.elem_type)
 | 
			
		||||
		g.write('array_slice(new_array_from_c_array${noscan}(')
 | 
			
		||||
		g.write('$info.size')
 | 
			
		||||
		g.write(', $info.size')
 | 
			
		||||
		g.write(', sizeof(')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -232,7 +232,7 @@ fn (mut g Gen) decode_array(value_type ast.Type) string {
 | 
			
		|||
	cJSON_ArrayForEach(jsval, root)
 | 
			
		||||
	{
 | 
			
		||||
	$s
 | 
			
		||||
		array_push((array*)&res, &val);
 | 
			
		||||
		array_push${noscan}((array*)&res, &val);
 | 
			
		||||
	}
 | 
			
		||||
'
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -121,10 +121,25 @@ pub fn mark_used(mut table ast.Table, pref &pref.Preferences, ast_files []&ast.F
 | 
			
		|||
 | 
			
		||||
	if pref.gc_mode in [.boehm_full_opt, .boehm_incr_opt] {
 | 
			
		||||
		all_fn_root_names << [
 | 
			
		||||
			'memdup_noscan',
 | 
			
		||||
			'__new_array_noscan',
 | 
			
		||||
			'__new_array_with_default_noscan',
 | 
			
		||||
			'__new_array_with_array_default_noscan',
 | 
			
		||||
			'new_array_from_c_array_noscan',
 | 
			
		||||
			'21.clone_static_to_depth_noscan',
 | 
			
		||||
			'21.clone_to_depth_noscan',
 | 
			
		||||
			'21.reverse_noscan',
 | 
			
		||||
			'21.repeat_to_depth_noscan',
 | 
			
		||||
			'65557.pop_noscan',
 | 
			
		||||
			'65557.push_noscan',
 | 
			
		||||
			'65557.push_many_noscan',
 | 
			
		||||
			'65557.insert_noscan',
 | 
			
		||||
			'65557.insert_many_noscan',
 | 
			
		||||
			'65557.prepend_noscan',
 | 
			
		||||
			'65557.prepend_many_noscan',
 | 
			
		||||
			'65557.reverse_noscan',
 | 
			
		||||
			'65557.grow_cap_noscan',
 | 
			
		||||
			'65557.grow_len_noscan',
 | 
			
		||||
		]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue