v2 / vlib / wasm / module.v
280 lines · 241 sloc · 6.23 KB · c51d30bf5309653c6b573ec815268e69a78ea8cc
Raw
1// Copyright (c) 2023 l-m.dev. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4module wasm
5
6enum Section as u8 {
7 custom_section
8 type_section
9 import_section
10 function_section
11 table_section
12 memory_section
13 global_section
14 export_section
15 start_section
16 element_section
17 code_section
18 data_section
19 data_count_section
20}
21
22enum Subsection as u8 {
23 name_module
24 name_function
25 name_local
26 // see: https://github.com/WebAssembly/extended-name-section
27 name_label
28 name_type
29 name_table
30 name_memory
31 name_global
32 name_elem
33 name_data
34}
35
36pub enum NumType as u8 {
37 i32_t = 0x7f
38 i64_t = 0x7e
39 f32_t = 0x7d
40 f64_t = 0x7c
41}
42
43pub enum ValType as u8 {
44 i32_t = 0x7f
45 i64_t = 0x7e
46 f32_t = 0x7d
47 f64_t = 0x7c
48 v128_t = 0x7b
49 funcref_t = 0x70
50 externref_t = 0x6f
51}
52
53pub enum RefType as u8 {
54 funcref_t = 0x70
55 externref_t = 0x6f
56}
57
58// Module contains the WebAssembly module.
59// Use the `compile` method to compile the module into a pure byte array.
60@[heap]
61pub struct Module {
62mut:
63 buf []u8
64 functypes []FuncType
65 functions map[string]Function
66 globals []Global
67 memory ?Memory
68 start ?string
69 fn_imports []FunctionImport
70 global_imports []GlobalImport
71 segments []DataSegment
72 debug bool
73 mod_name ?string
74}
75
76struct Global {
77 typ ValType
78 is_mut bool
79 name string
80 export bool
81mut:
82 init ConstExpression
83}
84
85struct GlobalImport {
86 mod string
87 name string
88 typ ValType
89 is_mut bool
90}
91
92struct FunctionImport {
93 mod string
94 name string
95 tidx int
96}
97
98struct Memory {
99 name string
100 export bool
101 min u32
102 max ?u32
103}
104
105struct DataSegment {
106 idx ?int
107 data []u8
108 name ?string
109}
110
111pub type LocalIndex = int
112pub type GlobalIndex = int
113pub type GlobalImportIndex = int
114pub type DataSegmentIndex = int
115
116pub struct FuncType {
117pub:
118 parameters []ValType
119 results []ValType
120 name ?string
121}
122
123fn (mut mod Module) new_functype(ft FuncType) int {
124 // interns existing types
125 mut idx := mod.functypes.index(ft)
126
127 if idx == -1 {
128 idx = mod.functypes.len
129 mod.functypes << ft
130 }
131
132 return idx
133}
134
135// new_function creates a function struct.
136pub fn (mut mod Module) new_function(name string, parameters []ValType, results []ValType) Function {
137 assert name !in mod.functions.keys()
138
139 idx := mod.functions.len
140 tidx := mod.new_functype(FuncType{parameters, results, none})
141
142 return Function{
143 name: name
144 tidx: tidx
145 idx: idx
146 mod: mod
147 locals: parameters.map(FunctionLocal{}) // specifying it's ValType doesn't matter
148 }
149}
150
151// new_debug_function creates a function struct with extra debug information.
152// `argument_names` must be the same length as the parameters in the function type `typ`.
153pub fn (mut mod Module) new_debug_function(name string, typ FuncType, argument_names []?string) Function {
154 assert name !in mod.functions.keys()
155 assert typ.parameters.len == argument_names.len
156
157 idx := mod.functions.len
158 tidx := mod.new_functype(typ)
159
160 return Function{
161 name: name
162 tidx: tidx
163 idx: idx
164 mod: mod
165 locals: argument_names.map(FunctionLocal{ name: it }) // specifying it's ValType doesn't matter
166 }
167}
168
169// enable_debug sets whether to emit debug information for not.
170pub fn (mut mod Module) enable_debug(mod_name ?string) {
171 mod.debug = true
172 mod.mod_name = mod_name
173}
174
175// assign_memory assigns memory to the current module.
176pub fn (mut mod Module) assign_memory(name string, export bool, min u32, max ?u32) {
177 mod.memory = Memory{
178 name: name
179 export: export
180 min: min
181 max: max
182 }
183}
184
185// assign_start assigns the start function to the current module.
186pub fn (mut mod Module) assign_start(name string) {
187 mod.start = name
188}
189
190// new_function_import imports a new function into the current module.
191pub fn (mut mod Module) new_function_import(modn string, name string, parameters []ValType, results []ValType) {
192 assert !mod.fn_imports.any(it.mod == modn && it.name == name)
193
194 tidx := mod.new_functype(FuncType{parameters, results, none})
195
196 mod.fn_imports << FunctionImport{
197 mod: modn
198 name: name
199 tidx: tidx
200 }
201}
202
203// new_function_import_debug imports a new function into the current module with extra debug information.
204pub fn (mut mod Module) new_function_import_debug(modn string, name string, typ FuncType) {
205 assert !mod.fn_imports.any(it.mod == modn && it.name == name)
206
207 tidx := mod.new_functype(typ)
208
209 mod.fn_imports << FunctionImport{
210 mod: modn
211 name: name
212 tidx: tidx
213 }
214}
215
216// commit commits a function to the module, use `export` to export the function.
217pub fn (mut mod Module) commit(func Function, export bool) {
218 assert func.name !in mod.functions.keys()
219
220 mod.functions[func.name] = Function{
221 ...func
222 export: export
223 }
224}
225
226// new_data_segment inserts a new data segment at the memory index `pos`.
227// `name` is optional, it is used for debug info.
228pub fn (mut mod Module) new_data_segment(name ?string, pos int, data []u8) DataSegmentIndex {
229 len := mod.segments.len
230 mod.segments << DataSegment{
231 idx: pos
232 data: data
233 name: name
234 }
235 return len
236}
237
238// new_passive_data_segment inserts a new passive data segment.
239// `name` is optional, it is used for debug info.
240pub fn (mut mod Module) new_passive_data_segment(name ?string, data []u8) {
241 mod.segments << DataSegment{
242 data: data
243 name: name
244 }
245}
246
247// new_global creates a global and returns it's index.
248// See `global_get`, `global_set`.
249pub fn (mut mod Module) new_global(name string, export bool, typ ValType, is_mut bool, init ConstExpression) GlobalIndex {
250 len := mod.globals.len
251 mod.globals << Global{
252 typ: typ
253 is_mut: is_mut
254 name: name
255 export: export
256 init: init
257 }
258 return len
259}
260
261// new_global_import imports a new global into the current module and returns it's index.
262// See `global_get`, `global_set`.
263pub fn (mut mod Module) new_global_import(modn string, name string, typ ValType, is_mut bool) GlobalImportIndex {
264 assert !mod.fn_imports.any(it.mod == modn && it.name == name)
265
266 len := mod.global_imports.len
267 mod.global_imports << GlobalImport{
268 mod: modn
269 name: name
270 typ: typ
271 is_mut: is_mut
272 }
273 return len
274}
275
276// assign_global_init assigns a global with the constant expression `init`.
277// See `new_global`.
278pub fn (mut mod Module) assign_global_init(global GlobalIndex, init ConstExpression) {
279 mod.globals[global].init = init
280}
281