v4 / vlib / v3 / tests / spawn_args_test.v
98 lines · 86 sloc · 2.55 KB · 7a89e581dace12716ed47d2e665fd337d9820870
Raw
1import os
2
3const vexe = @VEXE
4const tests_dir = os.dir(@FILE)
5const v3_dir = os.dir(tests_dir)
6const v3_src = os.join_path(v3_dir, 'v3.v')
7
8fn build_v3() string {
9 v3_bin := os.join_path(os.temp_dir(), 'v3_spawn_args_test')
10 build := os.execute('${vexe} -o ${v3_bin} ${v3_src}')
11 assert build.exit_code == 0, build.output
12 return v3_bin
13}
14
15fn gen_c(v3_bin string, name string, src string) string {
16 src_file := os.join_path(os.temp_dir(), '${name}.v')
17 os.write_file(src_file, src) or { panic(err) }
18 c_out := os.join_path(os.temp_dir(), '${name}.c')
19 os.rm(c_out) or {}
20 compile := os.execute('${v3_bin} ${src_file} -o ${c_out}')
21 assert compile.exit_code == 0, compile.output
22 return os.read_file(c_out) or { '' }
23}
24
25// A `spawn` of a free function with arguments must pack the arguments into a heap
26// struct and run the real function through a wrapper, instead of emitting a
27// `(void*)0` no-op that silently drops the call and its arguments.
28fn test_spawn_free_function_with_arguments_packs_args() {
29 v3_bin := build_v3()
30 c_code := gen_c(v3_bin, 'v3_spawn_args_free', '
31struct Counter {
32mut:
33 total int
34}
35
36fn add(mut c Counter, a int, b int) {
37 c.total = a + b
38}
39
40fn main() {
41 mut c := Counter{}
42 _ := spawn add(mut c, 3, 4)
43 println("ok")
44}
45')
46 assert c_code.contains('add_thread_args'), c_code
47 assert c_code.contains('pthread_create'), c_code
48 assert c_code.contains('add(p->a0, p->a1, p->a2)'), c_code
49}
50
51// A `spawn` of a method with arguments must pack the receiver and arguments and
52// dispatch the real method instead of dropping the call.
53fn test_spawn_method_with_arguments_packs_receiver_and_args() {
54 v3_bin := build_v3()
55 c_code := gen_c(v3_bin, 'v3_spawn_args_method', '
56struct Counter {
57mut:
58 total int
59}
60
61fn (mut c Counter) bump(x int) {
62 c.total += x
63}
64
65fn main() {
66 mut c := Counter{}
67 _ := spawn c.bump(10)
68 println("ok")
69}
70')
71 assert c_code.contains('pthread_create'), c_code
72 assert c_code.contains('Counter__bump(p->a0, p->a1)'), c_code
73}
74
75// A no-arg `spawn` of a by-value receiver method must copy the receiver into the
76// heap arg struct; casting the void* thread argument straight to the struct type
77// (`(Greeter)arg`) is invalid C.
78fn test_spawn_value_receiver_copies_receiver() {
79 v3_bin := build_v3()
80 c_code := gen_c(v3_bin, 'v3_spawn_value_receiver', '
81struct Greeter {
82 name string
83}
84
85fn (g Greeter) greet() {
86 println(g.name)
87}
88
89fn main() {
90 g := Greeter{name: "world"}
91 _ := spawn g.greet()
92 println("ok")
93}
94')
95 assert c_code.contains('pthread_create'), c_code
96 assert c_code.contains('Greeter__greet(p->a0)'), c_code
97 assert !c_code.contains('(Greeter)arg'), c_code
98}
99