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 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 for (id, instrs) in instrs {
69 let mut list = Vec::new();
70 for instr in instrs {
71 use wit_parser::Instruction as R; use Instruction as W; use walrus::ValType as RVT; 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 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 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 pub fn get(&self, id: FuncId) -> &Func {
270 &self.arena[id]
271 }
272
273 pub fn get_mut(&mut self, id: FuncId) -> &mut Func {
275 &mut self.arena[id]
276 }
277
278 pub fn iter(&self) -> impl Iterator<Item = &Func> {
288 self.arena.iter().map(|(_, f)| f)
289 }
290
291 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Func> {
293 self.arena.iter_mut().map(|(_, f)| f)
294 }
295
296 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 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 pub fn id(&self) -> FuncId {
318 self.id
319 }
320}