Skip to content

Commit 22a46d9

Browse files
committed
v3: lower runtime calls in transformer
1 parent 1498e02 commit 22a46d9

12 files changed

Lines changed: 307 additions & 136 deletions

File tree

vlib/v3/gen/c/array.v

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -477,16 +477,6 @@ fn (mut g FlatGen) gen_map_ref_arg(base_id flat.NodeId, base_type types.Type) {
477477
}
478478
}
479479

480-
// gen_map_delete emits map delete output for c.
481-
fn (mut g FlatGen) gen_map_delete(node flat.Node, fn_node &flat.Node, m types.Map, base_type types.Type) {
482-
c_key := g.tc.c_type(m.key_type)
483-
g.write('map__delete(')
484-
g.gen_map_ref_arg(g.a.child(fn_node, 0), base_type)
485-
g.write(', &(${c_key}[]){')
486-
g.gen_expr(g.a.child(&node, 1))
487-
g.write('})')
488-
}
489-
490480
// gen_index_assign emits index assign output for c.
491481
fn (mut g FlatGen) gen_index_assign(node flat.Node) {
492482
lhs_id := g.a.child(&node, 0)

vlib/v3/gen/c/cleanc.v

Lines changed: 10 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2889,6 +2889,14 @@ fn (mut g FlatGen) preamble() {
28892889
g.writeln('#include <sys/syscall.h>')
28902890
g.writeln('#endif')
28912891
}
2892+
if g.libc_compat_fns['filelock'] {
2893+
if g.compiler_vroot.len > 0 {
2894+
helper := c_escape(g.compiler_vroot + '/vlib/os/filelock/filelock_helpers.h')
2895+
g.writeln('#include "${helper}"')
2896+
} else {
2897+
g.writeln('#include "vlib/os/filelock/filelock_helpers.h"')
2898+
}
2899+
}
28922900
for directive in g.ordered_c_directives() {
28932901
g.writeln(directive)
28942902
}
@@ -3137,48 +3145,8 @@ fn (mut g FlatGen) builtin_abi_decls() {
31373145
}
31383146

31393147
fn (mut g FlatGen) filelock_compat_decls() {
3140-
g.writeln('#ifdef _WIN32')
3141-
g.writeln('#include <windows.h>')
3142-
g.writeln('int v_filelock_lock(void* handle, int exclusive, int immediate, u64 start, u64 len) {')
3143-
g.writeln('\tOVERLAPPED overlap;')
3144-
g.writeln('\tmemset(&overlap, 0, sizeof(overlap));')
3145-
g.writeln('\toverlap.Offset = (DWORD)(start & 0xffffffffULL);')
3146-
g.writeln('\toverlap.OffsetHigh = (DWORD)(start >> 32);')
3147-
g.writeln('\tDWORD flags = immediate ? LOCKFILE_FAIL_IMMEDIATELY : 0;')
3148-
g.writeln('\tif (exclusive) { flags |= LOCKFILE_EXCLUSIVE_LOCK; }')
3149-
g.writeln('\tDWORD low = len == 0 ? MAXDWORD : (DWORD)(len & 0xffffffffULL);')
3150-
g.writeln('\tDWORD high = len == 0 ? MAXDWORD : (DWORD)(len >> 32);')
3151-
g.writeln('\treturn LockFileEx((HANDLE)handle, flags, 0, low, high, &overlap) ? 0 : -1;')
3152-
g.writeln('}')
3153-
g.writeln('int v_filelock_unlock(void* handle, u64 start, u64 len) {')
3154-
g.writeln('\tOVERLAPPED overlap;')
3155-
g.writeln('\tmemset(&overlap, 0, sizeof(overlap));')
3156-
g.writeln('\toverlap.Offset = (DWORD)(start & 0xffffffffULL);')
3157-
g.writeln('\toverlap.OffsetHigh = (DWORD)(start >> 32);')
3158-
g.writeln('\tDWORD low = len == 0 ? MAXDWORD : (DWORD)(len & 0xffffffffULL);')
3159-
g.writeln('\tDWORD high = len == 0 ? MAXDWORD : (DWORD)(len >> 32);')
3160-
g.writeln('\treturn UnlockFileEx((HANDLE)handle, 0, low, high, &overlap) ? 0 : -1;')
3161-
g.writeln('}')
3162-
g.writeln('#else')
3163-
g.writeln('int v_filelock_lock(i32 fd, i32 exclusive, i32 immediate, u64 start, u64 len) {')
3164-
g.writeln('\tstruct flock fl;')
3165-
g.writeln('\tmemset(&fl, 0, sizeof(fl));')
3166-
g.writeln('\tfl.l_type = exclusive ? F_WRLCK : F_RDLCK;')
3167-
g.writeln('\tfl.l_whence = SEEK_SET;')
3168-
g.writeln('\tfl.l_start = (off_t)start;')
3169-
g.writeln('\tfl.l_len = len == 0 ? 0 : (off_t)len;')
3170-
g.writeln('\treturn fcntl(fd, immediate ? F_SETLK : F_SETLKW, &fl);')
3171-
g.writeln('}')
3172-
g.writeln('int v_filelock_unlock(i32 fd, u64 start, u64 len) {')
3173-
g.writeln('\tstruct flock fl;')
3174-
g.writeln('\tmemset(&fl, 0, sizeof(fl));')
3175-
g.writeln('\tfl.l_type = F_UNLCK;')
3176-
g.writeln('\tfl.l_whence = SEEK_SET;')
3177-
g.writeln('\tfl.l_start = (off_t)start;')
3178-
g.writeln('\tfl.l_len = len == 0 ? 0 : (off_t)len;')
3179-
g.writeln('\treturn fcntl(fd, F_SETLK, &fl);')
3180-
g.writeln('}')
3181-
g.writeln('#endif')
3148+
// The implementation is provided by vlib/os/filelock/filelock_helpers.h.
3149+
// V3 includes that header when these compatibility calls are used.
31823150
}
31833151

31843152
fn (mut g FlatGen) collect_fixed_array_typedefs_needed() map[string]FixedArrayTypedefInfo {

vlib/v3/gen/c/fn.v

Lines changed: 24 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,10 @@ fn (mut g FlatGen) libc_compat_call_name(name string) ?string {
346346
g.libc_compat_fns['gettid'] = true
347347
return 'v3_gettid'
348348
}
349+
if name in ['C.v_filelock_lock', 'C.v_filelock_unlock', 'v_filelock_lock', 'v_filelock_unlock'] {
350+
g.libc_compat_fns['filelock'] = true
351+
return c_name(name)
352+
}
349353
return none
350354
}
351355

@@ -1540,10 +1544,7 @@ fn (mut g FlatGen) gen_call(id flat.NodeId, node flat.Node) {
15401544
base_id := g.a.child(fn_node, 0)
15411545
base_type := g.tc.resolve_type(base_id)
15421546
if base_type is types.Channel {
1543-
g.write('sync__Channel__close(')
1544-
g.gen_expr(base_id)
1545-
g.write(', array_new(sizeof(IError), 0, 0))')
1546-
return
1547+
panic('channel close should be lowered by v3 transform')
15471548
}
15481549
}
15491550
match fn_name {
@@ -1689,31 +1690,14 @@ fn (mut g FlatGen) gen_call(id flat.NodeId, node flat.Node) {
16891690
g.write(', ${len_expr})')
16901691
return
16911692
}
1692-
if clean_type is types.Map {
1693-
if fn_node.value == 'delete' {
1694-
g.gen_map_delete(node, fn_node, clean_type, base_type)
1695-
return
1696-
} else if fn_node.value == 'clone' {
1697-
g.write('map__clone(')
1698-
g.gen_map_ref_arg(g.a.child(fn_node, 0), base_type)
1699-
g.write(')')
1700-
return
1701-
} else if fn_node.value == 'clear' {
1702-
g.write('map__clear(')
1703-
g.gen_map_ref_arg(g.a.child(fn_node, 0), base_type)
1704-
g.write(')')
1705-
return
1706-
} else if fn_node.value == 'free' {
1707-
g.write('map__free(')
1708-
if base_type is types.Pointer {
1709-
g.gen_expr(g.a.child(fn_node, 0))
1710-
} else {
1711-
g.write('&')
1712-
g.gen_expr(g.a.child(fn_node, 0))
1713-
}
1714-
g.write(')')
1715-
return
1716-
}
1693+
if clean_type is types.Map && fn_node.value == 'clone' {
1694+
g.write('map__clone(')
1695+
g.gen_map_ref_arg(g.a.child(fn_node, 0), base_type)
1696+
g.write(')')
1697+
return
1698+
}
1699+
if clean_type is types.Map && fn_node.value in ['delete', 'clear', 'free'] {
1700+
panic('map method `${fn_node.value}` should be lowered by v3 transform')
17171701
}
17181702
if clean_type is types.String {
17191703
method_name = 'string.${fn_node.value}'
@@ -1844,31 +1828,14 @@ fn (mut g FlatGen) gen_call(id flat.NodeId, node flat.Node) {
18441828
g.write(', ${len_expr})')
18451829
return
18461830
}
1847-
if clean_type is types.Map {
1848-
if fn_node.value == 'delete' {
1849-
g.gen_map_delete(node, fn_node, clean_type, base_type)
1850-
return
1851-
} else if fn_node.value == 'clone' {
1852-
g.write('map__clone(')
1853-
g.gen_map_ref_arg(g.a.child(fn_node, 0), base_type)
1854-
g.write(')')
1855-
return
1856-
} else if fn_node.value == 'clear' {
1857-
g.write('map__clear(')
1858-
g.gen_map_ref_arg(g.a.child(fn_node, 0), base_type)
1859-
g.write(')')
1860-
return
1861-
} else if fn_node.value == 'free' {
1862-
g.write('map__free(')
1863-
if base_type is types.Pointer {
1864-
g.gen_expr(g.a.child(fn_node, 0))
1865-
} else {
1866-
g.write('&')
1867-
g.gen_expr(g.a.child(fn_node, 0))
1868-
}
1869-
g.write(')')
1870-
return
1871-
}
1831+
if clean_type is types.Map && fn_node.value == 'clone' {
1832+
g.write('map__clone(')
1833+
g.gen_map_ref_arg(g.a.child(fn_node, 0), base_type)
1834+
g.write(')')
1835+
return
1836+
}
1837+
if clean_type is types.Map && fn_node.value in ['delete', 'clear', 'free'] {
1838+
panic('map method `${fn_node.value}` should be lowered by v3 transform')
18721839
}
18731840
if clean_type is types.String {
18741841
method_name = 'string.${fn_node.value}'
@@ -3803,6 +3770,9 @@ fn (mut g FlatGen) forward_decls() {
38033770
}
38043771
} else if kind_id == 76
38053772
&& (node.value.starts_with('C.v_filelock_') || node.value.starts_with('v_filelock_')) {
3773+
if g.libc_compat_fns['filelock'] {
3774+
continue
3775+
}
38063776
g.tc.cur_file = cur_file
38073777
g.tc.cur_module = cur_module
38083778
ret_type := g.tc.parse_type(node.typ)

vlib/v3/markused/markused.v

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2720,9 +2720,15 @@ fn resolve_type_name(t types.Type) string {
27202720
} else if t is types.String {
27212721
return 'string'
27222722
} else if t is types.Array {
2723-
return 'Array'
2723+
return '[]${markused_nested_type_name(t.elem_type)}'
2724+
} else if t is types.ArrayFixed {
2725+
mut len_text := t.len.str()
2726+
if t.len_expr.len > 0 {
2727+
len_text = t.len_expr
2728+
}
2729+
return '${markused_nested_type_name(t.elem_type)}[${len_text}]'
27242730
} else if t is types.Map {
2725-
return 'map[${t.key_type.name()}]${t.value_type.name()}'
2731+
return 'map[${markused_nested_type_name(t.key_type)}]${markused_nested_type_name(t.value_type)}'
27262732
} else if t is types.Pointer {
27272733
return resolve_type_name(t.base_type)
27282734
} else if t is types.Primitive {
@@ -2768,6 +2774,10 @@ fn resolve_type_name(t types.Type) string {
27682774
return ''
27692775
}
27702776

2777+
fn markused_nested_type_name(t types.Type) string {
2778+
return t.name()
2779+
}
2780+
27712781
// markused_c_name converts markused c name data for markused.
27722782
fn markused_c_name(name string) string {
27732783
if name.starts_with('C.') {

vlib/v3/tests/transformer_parity_test.v

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,22 @@ fn parse_transform_file(src string, source string) &flat.FlatAst {
2424
return a
2525
}
2626

27+
// parse_checked_transform_source reads parse checked transform source input for v3 tests.
28+
fn parse_checked_transform_source(source string) &flat.FlatAst {
29+
src := os.join_path(os.temp_dir(), 'v3_transformer_checked_parity_test.v')
30+
os.write_file(src, source) or { panic(err) }
31+
prefs := pref.new_preferences()
32+
mut p := parser.Parser.new(prefs)
33+
mut a := p.parse_file(src)
34+
mut tc := types.TypeChecker.new(a)
35+
tc.diagnose_unknown_calls = true
36+
tc.collect(a)
37+
tc.check_semantics()
38+
assert tc.errors.len == 0, tc.errors.str()
39+
transform.transform(mut a, &tc)
40+
return a
41+
}
42+
2743
// find_fn resolves find fn information for v3 tests.
2844
fn find_fn(a &flat.FlatAst, name string) flat.Node {
2945
for node in a.nodes {
@@ -601,3 +617,71 @@ fn main() {
601617
assert or_count == 0
602618
assert get_check_count == 1
603619
}
620+
621+
fn test_map_methods_lower_to_runtime_calls() {
622+
a := parse_transform_source('
623+
fn main() {
624+
mut m := map[string]int{}
625+
m.delete("a")
626+
m.clear()
627+
m.free()
628+
}
629+
')
630+
main_fn := find_fn(a, 'main')
631+
mut delete_count := 0
632+
mut clear_count := 0
633+
mut free_count := 0
634+
mut selector_count := 0
635+
for i in 0 .. main_fn.children_count {
636+
child_id := a.child(&main_fn, i)
637+
delete_count += count_call_name(a, child_id, 'map__delete')
638+
clear_count += count_call_name(a, child_id, 'map__clear')
639+
free_count += count_call_name(a, child_id, 'map__free')
640+
selector_count += count_selector_value(a, child_id, 'delete')
641+
selector_count += count_selector_value(a, child_id, 'clear')
642+
selector_count += count_selector_value(a, child_id, 'free')
643+
}
644+
assert delete_count == 1
645+
assert clear_count == 1
646+
assert free_count == 1
647+
assert selector_count == 0
648+
}
649+
650+
fn test_channel_close_lowers_to_runtime_call() {
651+
a := parse_transform_source('
652+
fn main() {
653+
ch := chan bool{cap: 1}
654+
ch.close()
655+
}
656+
')
657+
main_fn := find_fn(a, 'main')
658+
mut close_count := 0
659+
mut selector_count := 0
660+
for i in 0 .. main_fn.children_count {
661+
child_id := a.child(&main_fn, i)
662+
close_count += count_call_name(a, child_id, 'sync__Channel__close')
663+
close_count += count_selector_value(a, child_id, 'sync__Channel__close')
664+
selector_count += count_selector_value(a, child_id, 'close')
665+
}
666+
assert close_count == 1
667+
assert selector_count == 0
668+
}
669+
670+
fn test_map_values_membership_lowers_without_type_annotation() {
671+
a := parse_checked_transform_source('
672+
fn main() {
673+
mut names := map[string]string{}
674+
found := "alex" in names.values()
675+
}
676+
')
677+
main_fn := find_fn(a, 'main')
678+
mut in_count := 0
679+
mut for_count := 0
680+
for i in 0 .. main_fn.children_count {
681+
child_id := a.child(&main_fn, i)
682+
in_count += count_kind(a, child_id, .in_expr)
683+
for_count += count_kind(a, child_id, .for_stmt)
684+
}
685+
assert in_count == 0
686+
assert for_count == 1
687+
}

vlib/v3/transform/array.v

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ fn (mut t Transformer) make_array_new_call(elem_type string, len_expr flat.NodeI
1010
}
1111

1212
fn (mut t Transformer) make_array_push_many_call(lhs_addr flat.NodeId, rhs flat.NodeId, rhs_type string) flat.NodeId {
13+
t.mark_fn_used('array__push_many')
1314
rhs_value := t.stable_transformed_expr_for_reuse(rhs, rhs_type, 'push_many')
1415
return t.make_call_typed('array__push_many', arr3(lhs_addr, t.make_selector(rhs_value, 'data',
1516
'voidptr'), t.make_selector(rhs_value, 'len', 'int')), 'void')
1617
}
1718

1819
fn (mut t Transformer) make_array_clone_call(base_id flat.NodeId, base_type string) flat.NodeId {
20+
t.mark_fn_used('array__clone')
1921
receiver := t.transform_expr(base_id)
2022
return t.make_call_typed('array__clone', arr1(t.runtime_addr(receiver, base_type)), base_type)
2123
}
@@ -304,6 +306,9 @@ fn (mut t Transformer) lower_array_prepend_call(node flat.Node, fn_node flat.Nod
304306
}
305307
value_name := t.new_temp('arr_val')
306308
t.pending_stmts << t.make_decl_assign_typed(value_name, value, elem_type)
309+
t.mark_fn_used('array__prepend')
310+
t.mark_fn_used('array__insert')
311+
t.mark_fn_used('array__needs_unique_shift')
307312
return t.make_call_typed('array__prepend', arr2(t.runtime_addr(base, base_type), t.make_prefix(.amp,
308313
t.make_ident(value_name))), 'void')
309314
}
@@ -325,6 +330,8 @@ fn (mut t Transformer) lower_array_insert_call(node flat.Node, fn_node flat.Node
325330
}
326331
value_name := t.new_temp('arr_val')
327332
t.pending_stmts << t.make_decl_assign_typed(value_name, value, elem_type)
333+
t.mark_fn_used('array__insert')
334+
t.mark_fn_used('array__needs_unique_shift')
328335
return t.make_call_typed('array__insert', arr3(t.runtime_addr(base, base_type), index, t.make_prefix(.amp,
329336
t.make_ident(value_name))), 'void')
330337
}
@@ -338,6 +345,7 @@ fn (mut t Transformer) lower_array_push_many_call(node flat.Node, fn_node flat.N
338345
count_id := t.a.child(&node, 2)
339346
base := t.transform_lvalue(base_id)
340347
base_addr := t.runtime_addr(base, base_type)
348+
t.mark_fn_used('array__push_many')
341349
if t.push_many_count_is_type_name(count_id) {
342350
value := if elem_type in t.sum_types || t.resolve_sum_name(elem_type) in t.sum_types {
343351
t.wrap_sum_value(value_id, elem_type)

vlib/v3/transform/expr.v

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,6 +1296,14 @@ pub fn (mut t Transformer) make_call_typed(fn_name string, args []flat.NodeId, t
12961296
return t.make_call_expr_typed(fn_ident, args, typ)
12971297
}
12981298

1299+
fn (mut t Transformer) mark_fn_used(fn_name string) {
1300+
if fn_name.len == 0 || t.used_fns.len == 0 {
1301+
return
1302+
}
1303+
t.used_fns[fn_name] = true
1304+
t.used_fns[c_name(fn_name)] = true
1305+
}
1306+
12991307
// make_call_expr_typed builds make call expr typed data for transform.
13001308
pub fn (mut t Transformer) make_call_expr_typed(fn_expr flat.NodeId, args []flat.NodeId, typ string) flat.NodeId {
13011309
start := t.a.children.len

0 commit comments

Comments
 (0)