v2 / vlib / v / gen / wasm / tests / browser_empty_main_test.v
146 lines · 131 sloc · 3.85 KB · 85768336b5364752a0e5d07e31814d2f95f8e2ba
Raw
1import os
2
3struct WasmVarUint {
4 value u32
5 next_idx int
6}
7
8struct WasmModuleSummary {
9mut:
10 exports []string
11 has_start_section bool
12}
13
14fn test_wasm_browser_target_allows_empty_main() {
15 vexe := os.quoted_path(@VEXE)
16 wrkdir := os.join_path(os.vtmp_dir(), 'wasm_browser_tests')
17 os.mkdir_all(wrkdir)!
18 defer {
19 os.rmdir_all(wrkdir) or {}
20 }
21
22 source_path := os.join_path(wrkdir, 'empty_main.wasm.v')
23 os.write_file(source_path, 'pub fn main() {}\n')!
24
25 flags_sets := [
26 '-no-bounds-checking -b wasm -os browser',
27 '-no-bounds-checking -enable-globals -b wasm -os browser',
28 ]
29
30 for idx, flags in flags_sets {
31 output_path := os.join_path(wrkdir, 'empty_main_${idx}.wasm')
32 res :=
33 os.execute('${vexe} ${flags} -o ${os.quoted_path(output_path)} ${os.quoted_path(source_path)}')
34 assert res.exit_code == 0, 'compilation failed for `${flags}`: ${res.output}'
35 assert os.exists(output_path), 'missing output for `${flags}`'
36 }
37}
38
39fn test_wasm_shared_library_exports_custom_names_without_main() {
40 vexe := os.quoted_path(@VEXE)
41 wrkdir := os.join_path(os.vtmp_dir(), 'wasm_shared_library_tests')
42 os.mkdir_all(wrkdir)!
43 defer {
44 os.rmdir_all(wrkdir) or {}
45 }
46
47 source_path := os.join_path(wrkdir, 'my_wasm_lib.v')
48 output_path := os.join_path(wrkdir, 'my_wasm_lib.wasm')
49 source := [
50 'module my_wasm_lib',
51 '',
52 "@[export: 'myFunction']",
53 'fn my_function(a int, b int) int {',
54 '\treturn a + b',
55 '}',
56 ].join_lines()
57 os.write_file(source_path, source)!
58
59 res :=
60 os.execute('${vexe} -b wasm -shared -o ${os.quoted_path(output_path)} ${os.quoted_path(source_path)}')
61 assert res.exit_code == 0, 'compilation failed: ${res.output}'
62 assert os.exists(output_path), 'missing output for shared wasm library'
63
64 wasm_bytes := os.read_bytes(output_path)!
65 summary := inspect_wasm_module(wasm_bytes) or { panic(err) }
66
67 assert 'myFunction' in summary.exports
68 assert '_start' !in summary.exports
69 assert summary.has_start_section
70}
71
72fn inspect_wasm_module(wasm_bytes []u8) !WasmModuleSummary {
73 if wasm_bytes.len < 8 {
74 return error('wasm module is too short')
75 }
76 if wasm_bytes[0] != 0x00 || wasm_bytes[1] != 0x61 || wasm_bytes[2] != 0x73
77 || wasm_bytes[3] != 0x6d || wasm_bytes[4] != 0x01 || wasm_bytes[5] != 0x00
78 || wasm_bytes[6] != 0x00 || wasm_bytes[7] != 0x00 {
79 return error('invalid wasm header')
80 }
81
82 mut summary := WasmModuleSummary{}
83 mut idx := 8
84 for idx < wasm_bytes.len {
85 section_id := wasm_bytes[idx]
86 idx++
87 section_len := read_wasm_u32(wasm_bytes, idx)!
88 idx = section_len.next_idx
89 section_end := idx + int(section_len.value)
90 if section_end > wasm_bytes.len {
91 return error('wasm section exceeds module bounds')
92 }
93 match section_id {
94 u8(7) {
95 mut export_idx := idx
96 exports_len := read_wasm_u32(wasm_bytes, export_idx)!
97 export_idx = exports_len.next_idx
98 for _ in 0 .. int(exports_len.value) {
99 name_len := read_wasm_u32(wasm_bytes, export_idx)!
100 export_idx = name_len.next_idx
101 name_end := export_idx + int(name_len.value)
102 if name_end > section_end {
103 return error('wasm export name exceeds section bounds')
104 }
105 summary.exports << wasm_bytes[export_idx..name_end].bytestr()
106 export_idx = name_end
107 if export_idx >= section_end {
108 return error('wasm export kind is missing')
109 }
110 export_idx++
111 export_ref := read_wasm_u32(wasm_bytes, export_idx)!
112 export_idx = export_ref.next_idx
113 }
114 }
115 u8(8) {
116 summary.has_start_section = true
117 }
118 else {}
119 }
120
121 idx = section_end
122 }
123 return summary
124}
125
126fn read_wasm_u32(wasm_bytes []u8, start int) !WasmVarUint {
127 mut value := u32(0)
128 mut shift := u32(0)
129 mut idx := start
130 for idx < wasm_bytes.len {
131 b := wasm_bytes[idx]
132 value |= u32(b & 0x7f) << shift
133 idx++
134 if b & 0x80 == 0 {
135 return WasmVarUint{
136 value: value
137 next_idx: idx
138 }
139 }
140 shift += 7
141 if shift >= 35 {
142 break
143 }
144 }
145 return error('invalid wasm varuint32 encoding')
146}
147