wit_walrus/
funcs.rs

1use crate::WitIdsToIndices;
2use crate::{ImportId, TypeId, ValType, WasmInterfaceTypes, WitIndicesToIds};
3use anyhow::Result;
4use id_arena::{Arena, Id};
5use walrus::IndicesToIds;
6
7#[derive(Debug, Default)]
8pub struct Funcs {
9    arena: Arena<Func>,
10}
11
12#[derive(Debug)]
13pub struct Func {
14    id: FuncId,
15    pub ty: TypeId,
16    pub kind: FuncKind,
17}
18
19#[derive(Debug)]
20pub enum FuncKind {
21    Import(ImportId),
22    Local(Vec<Instruction>),
23}
24
25#[derive(Debug, Clone)]
26pub enum Instruction {
27    CallCore(walrus::FunctionId),
28    DeferCallCore(walrus::FunctionId),
29    CallAdapter(FuncId),
30    ArgGet(u32),
31    MemoryToString(walrus::MemoryId),
32    StringToMemory {
33        mem: walrus::MemoryId,
34        malloc: walrus::FunctionId,
35    },
36    IntToWasm {
37        input: ValType,
38        output: walrus::ValType,
39        trap: bool,
40    },
41    WasmToInt {
42        input: walrus::ValType,
43        output: ValType,
44        trap: bool,
45    },
46}
47
48pub type FuncId = Id<Func>;
49
50impl WasmInterfaceTypes {
51    pub(crate) fn parse_funcs(
52        &mut self,
53        funcs: wit_parser::Funcs,
54        ids: &IndicesToIds,
55        wids: &mut WitIndicesToIds,
56    ) -> Result<()> {
57        // assign an id to everything first ...
58        let mut instrs = Vec::new();
59        for func in funcs {
60            let func = func?;
61            let ty = wids.ty(func.ty)?;
62            let id = self.funcs.add_local(ty, Vec::new());
63            wids.funcs.push(id);
64            instrs.push((id, func.instrs()));
65        }
66
67        // ... and then parse all the instructions
68        for (id, instrs) in instrs {
69            let mut list = Vec::new();
70            for instr in instrs {
71                use wit_parser::Instruction as R; // "raw"
72                use Instruction as W; // "walrus"
73                use walrus::ValType as RVT; // "raw value type"
74                use crate::ValType as VT;
75
76                fn w2i(input: walrus::ValType, output: ValType, trap: bool) -> W {
77                    W::WasmToInt { input, output, trap }
78                }
79
80                fn i2w(input: ValType, output: walrus::ValType, trap: bool) -> W {
81                    W::IntToWasm { input, output, trap }
82                }
83
84                list.push(match instr? {
85                    R::CallCore(id) => W::CallCore(ids.get_func(id)?),
86                    R::CallAdapter(id) => W::CallAdapter(wids.func(id)?),
87                    R::ArgGet(idx) => W::ArgGet(idx),
88                    R::MemoryToString(mem) => W::MemoryToString(ids.get_memory(mem)?),
89                    R::StringToMemory(args) => W::StringToMemory {
90                        mem: ids.get_memory(args.mem)?,
91                        malloc: ids.get_func(args.malloc)?,
92                    },
93                    R::DeferCallCore(id) => W::DeferCallCore(ids.get_func(id)?),
94
95                    R::I32ToS8 => w2i(RVT::I32, VT::S8, false),
96                    R::I32ToS8X => w2i(RVT::I32, VT::S8, true),
97                    R::I32ToU8 => w2i(RVT::I32, VT::U8, false),
98                    R::I32ToS16 => w2i(RVT::I32, VT::S16, false),
99                    R::I32ToS16X => w2i(RVT::I32, VT::S16, true),
100                    R::I32ToU16 => w2i(RVT::I32, VT::U16, false),
101                    R::I32ToS32 => w2i(RVT::I32, VT::S32, false),
102                    R::I32ToU32 => w2i(RVT::I32, VT::U32, false),
103                    R::I32ToS64 => w2i(RVT::I32, VT::S64, false),
104                    R::I32ToU64 => w2i(RVT::I32, VT::U64, false),
105
106                    R::I64ToS8 => w2i(RVT::I64, VT::S8, false),
107                    R::I64ToS8X => w2i(RVT::I64, VT::S8, true),
108                    R::I64ToU8 => w2i(RVT::I64, VT::U8, false),
109                    R::I64ToS16 => w2i(RVT::I64, VT::S16, false),
110                    R::I64ToS16X => w2i(RVT::I64, VT::S16, true),
111                    R::I64ToU16 => w2i(RVT::I64, VT::U16, false),
112                    R::I64ToS32 => w2i(RVT::I64, VT::S32, false),
113                    R::I64ToS32X => w2i(RVT::I64, VT::S32, true),
114                    R::I64ToU32 => w2i(RVT::I64, VT::U32, false),
115                    R::I64ToS64 => w2i(RVT::I64, VT::S64, false),
116                    R::I64ToU64 => w2i(RVT::I64, VT::U64, false),
117
118                    R::S8ToI32 => i2w(VT::S8, RVT::I32, false),
119                    R::U8ToI32 => i2w(VT::U8, RVT::I32, false),
120                    R::S16ToI32 => i2w(VT::S16, RVT::I32, false),
121                    R::U16ToI32 => i2w(VT::U16, RVT::I32, false),
122                    R::S32ToI32 => i2w(VT::S32, RVT::I32, false),
123                    R::U32ToI32 => i2w(VT::U32, RVT::I32, false),
124                    R::S64ToI32 => i2w(VT::S64, RVT::I32, false),
125                    R::S64ToI32X => i2w(VT::S64, RVT::I32, true),
126                    R::U64ToI32 => i2w(VT::U64, RVT::I32, false),
127                    R::U64ToI32X => i2w(VT::U64, RVT::I32, true),
128
129                    R::S8ToI64 => i2w(VT::S8, RVT::I64, false),
130                    R::U8ToI64 => i2w(VT::U8, RVT::I64, false),
131                    R::S16ToI64 => i2w(VT::S16, RVT::I64, false),
132                    R::U16ToI64 => i2w(VT::U16, RVT::I64, false),
133                    R::S32ToI64 => i2w(VT::S32, RVT::I64, false),
134                    R::U32ToI64 => i2w(VT::U32, RVT::I64, false),
135                    R::S64ToI64 => i2w(VT::S64, RVT::I64, false),
136                    R::U64ToI64 => i2w(VT::U64, RVT::I64, false),
137
138                    R::End => continue,
139                });
140            }
141
142            match &mut self.funcs.arena.get_mut(id).unwrap().kind {
143                FuncKind::Local(i) => *i = list,
144                _ => unreachable!(),
145            }
146        }
147
148        Ok(())
149    }
150
151    pub(crate) fn encode_funcs(
152        &self,
153        writer: &mut wit_writer::Writer,
154        wids: &mut WitIdsToIndices,
155        ids: &walrus::IdsToIndices,
156    ) {
157        // Filter out imported functions since those went in the import section
158        let funcs = self
159            .funcs
160            .iter()
161            .filter_map(|f| match &f.kind {
162                FuncKind::Local(instrs) => Some((f, instrs)),
163                FuncKind::Import(_) => None,
164            })
165            .collect::<Vec<_>>();
166
167        // Assign an index for all functions first so inter-function references
168        // work.
169        for (func, _) in funcs.iter() {
170            wids.push_func(func.id());
171        }
172
173        let mut w = writer.funcs(funcs.len() as u32);
174        for (func, instrs) in funcs {
175            let mut w = w.add(wids.ty(func.ty));
176            for instr in instrs {
177                use Instruction::*;
178                match *instr {
179                    ArgGet(n) => w.arg_get(n),
180                    CallCore(f) => w.call_core(ids.get_func_index(f)),
181                    DeferCallCore(f) => w.defer_call_core(ids.get_func_index(f)),
182                    CallAdapter(f) => w.call_adapter(wids.func(f)),
183                    MemoryToString(m) => w.memory_to_string(ids.get_memory_index(m)),
184                    StringToMemory { mem, malloc } => {
185                        w.string_to_memory(ids.get_func_index(malloc), ids.get_memory_index(mem));
186                    }
187                    IntToWasm {
188                        input,
189                        output,
190                        trap,
191                    } => i2w(&mut w, input, output, trap),
192                    WasmToInt {
193                        input,
194                        output,
195                        trap,
196                    } => w2i(&mut w, input, output, trap),
197                }
198            }
199        }
200        fn w2i(
201            w: &mut wit_writer::Instructions<'_, '_>,
202            input: walrus::ValType,
203            output: ValType,
204            trap: bool,
205        ) {
206            match (input, output, trap) {
207                (walrus::ValType::I32, ValType::S8, false) => w.i32_to_s8(),
208                (walrus::ValType::I32, ValType::S8, true) => w.i32_to_s8x(),
209                (walrus::ValType::I32, ValType::U8, _) => w.i32_to_u8(),
210                (walrus::ValType::I32, ValType::S16, false) => w.i32_to_s16(),
211                (walrus::ValType::I32, ValType::S16, true) => w.i32_to_s16x(),
212                (walrus::ValType::I32, ValType::U16, _) => w.i32_to_u16(),
213                (walrus::ValType::I32, ValType::S32, _) => w.i32_to_s32(),
214                (walrus::ValType::I32, ValType::U32, _) => w.i32_to_u32(),
215                (walrus::ValType::I32, ValType::S64, _) => w.i32_to_s64(),
216                (walrus::ValType::I32, ValType::U64, _) => w.i32_to_u64(),
217
218                (walrus::ValType::I64, ValType::S8, false) => w.i64_to_s8(),
219                (walrus::ValType::I64, ValType::S8, true) => w.i64_to_s8x(),
220                (walrus::ValType::I64, ValType::U8, _) => w.i64_to_u8(),
221                (walrus::ValType::I64, ValType::S16, false) => w.i64_to_s16(),
222                (walrus::ValType::I64, ValType::S16, true) => w.i64_to_s16x(),
223                (walrus::ValType::I64, ValType::U16, _) => w.i64_to_u16(),
224                (walrus::ValType::I64, ValType::S32, false) => w.i64_to_s32(),
225                (walrus::ValType::I64, ValType::S32, true) => w.i64_to_s32x(),
226                (walrus::ValType::I64, ValType::U32, _) => w.i64_to_u32(),
227                (walrus::ValType::I64, ValType::S64, _) => w.i64_to_s64(),
228                (walrus::ValType::I64, ValType::U64, _) => w.i64_to_u64(),
229
230                _ => unreachable!(),
231            }
232        }
233
234        fn i2w(
235            w: &mut wit_writer::Instructions<'_, '_>,
236            input: ValType,
237            output: walrus::ValType,
238            trap: bool,
239        ) {
240            match (input, output, trap) {
241                (ValType::S8, walrus::ValType::I32, _) => w.s8_to_i32(),
242                (ValType::U8, walrus::ValType::I32, _) => w.u8_to_i32(),
243                (ValType::S16, walrus::ValType::I32, _) => w.s16_to_i32(),
244                (ValType::U16, walrus::ValType::I32, _) => w.u16_to_i32(),
245                (ValType::S32, walrus::ValType::I32, _) => w.s32_to_i32(),
246                (ValType::U32, walrus::ValType::I32, _) => w.u32_to_i32(),
247                (ValType::S64, walrus::ValType::I32, false) => w.s64_to_i32(),
248                (ValType::S64, walrus::ValType::I32, true) => w.s64_to_i32x(),
249                (ValType::U64, walrus::ValType::I32, false) => w.u64_to_i32(),
250                (ValType::U64, walrus::ValType::I32, true) => w.u64_to_i32x(),
251
252                (ValType::S8, walrus::ValType::I64, _) => w.s8_to_i64(),
253                (ValType::U8, walrus::ValType::I64, _) => w.u8_to_i64(),
254                (ValType::S16, walrus::ValType::I64, _) => w.s16_to_i64(),
255                (ValType::U16, walrus::ValType::I64, _) => w.u16_to_i64(),
256                (ValType::S32, walrus::ValType::I64, _) => w.s32_to_i64(),
257                (ValType::U32, walrus::ValType::I64, _) => w.u32_to_i64(),
258                (ValType::S64, walrus::ValType::I64, _) => w.s64_to_i64(),
259                (ValType::U64, walrus::ValType::I64, _) => w.u64_to_i64(),
260
261                _ => unreachable!(),
262            }
263        }
264    }
265}
266
267impl Funcs {
268    /// Gets a reference to an func given its id
269    pub fn get(&self, id: FuncId) -> &Func {
270        &self.arena[id]
271    }
272
273    /// Gets a reference to an func given its id
274    pub fn get_mut(&mut self, id: FuncId) -> &mut Func {
275        &mut self.arena[id]
276    }
277
278    // /// Removes an func from this module.
279    // ///
280    // /// It is up to you to ensure that any potential references to the deleted
281    // /// func are also removed, eg `get_global` expressions.
282    // pub fn delete(&mut self, id: FuncId) {
283    //     self.arena.delete(id);
284    // }
285
286    /// Get a shared reference to this section's funcs.
287    pub fn iter(&self) -> impl Iterator<Item = &Func> {
288        self.arena.iter().map(|(_, f)| f)
289    }
290
291    /// Get mutable references to this section's funcs.
292    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Func> {
293        self.arena.iter_mut().map(|(_, f)| f)
294    }
295
296    /// Create a new externally defined, imported function.
297    pub fn add_import(&mut self, ty: TypeId, import: ImportId) -> FuncId {
298        self.arena.alloc_with_id(|id| Func {
299            id,
300            ty,
301            kind: FuncKind::Import(import),
302        })
303    }
304
305    /// Adds a new local func to this section
306    pub fn add_local(&mut self, ty: TypeId, instrs: Vec<Instruction>) -> FuncId {
307        self.arena.alloc_with_id(|id| Func {
308            id,
309            ty,
310            kind: FuncKind::Local(instrs),
311        })
312    }
313}
314
315impl Func {
316    /// Returns the identifier for this `Func`
317    pub fn id(&self) -> FuncId {
318        self.id
319    }
320}