Skip to main content

wit_component/
dummy.rs

1use wit_parser::abi::WasmType;
2use wit_parser::{
3    Function, FutureIntrinsic, LiftLowerAbi, ManglingAndAbi, Resolve, ResourceIntrinsic,
4    StreamIntrinsic, TypeDefKind, TypeId, WasmExport, WasmExportKind, WasmImport, WorldId,
5    WorldItem, WorldKey,
6};
7
8/// Generate a dummy implementation core Wasm module for a given WIT document
9pub fn dummy_module(resolve: &Resolve, world: WorldId, mangling: ManglingAndAbi) -> Vec<u8> {
10    let world = &resolve.worlds[world];
11    let mut wat = String::new();
12    wat.push_str("(module\n");
13    for (name, import) in world.imports.iter() {
14        match import {
15            WorldItem::Function(func) => {
16                push_imported_func(&mut wat, resolve, None, func, mangling);
17            }
18            WorldItem::Interface { id: import, .. } => {
19                for (_, func) in resolve.interfaces[*import].functions.iter() {
20                    push_imported_func(&mut wat, resolve, Some(name), func, mangling);
21                }
22                for (_, ty) in resolve.interfaces[*import].types.iter() {
23                    push_imported_type_intrinsics(&mut wat, resolve, Some(name), *ty, mangling);
24                }
25            }
26            WorldItem::Type { id, .. } => {
27                push_imported_type_intrinsics(&mut wat, resolve, None, *id, mangling);
28            }
29        }
30    }
31
32    if mangling.is_async() {
33        push_root_async_intrinsics(&mut wat);
34    }
35
36    // Append any intrinsics which are imported but used in exported items
37    // (e.g. resources)
38    for (name, export) in world.exports.iter() {
39        match export {
40            WorldItem::Function(func) => {
41                push_exported_func_intrinsics(&mut wat, resolve, None, func, mangling);
42            }
43            WorldItem::Interface { id: export, .. } => {
44                for (_, func) in resolve.interfaces[*export].functions.iter() {
45                    push_exported_func_intrinsics(&mut wat, resolve, Some(name), func, mangling);
46                }
47                for (_, ty) in resolve.interfaces[*export].types.iter() {
48                    push_exported_type_intrinsics(&mut wat, resolve, Some(name), *ty, mangling);
49                }
50            }
51            WorldItem::Type { .. } => {}
52        }
53    }
54
55    for (name, export) in world.exports.iter() {
56        match export {
57            WorldItem::Function(func) => {
58                push_func_export(&mut wat, resolve, None, func, mangling);
59            }
60            WorldItem::Interface { id: export, .. } => {
61                for (_, func) in resolve.interfaces[*export].functions.iter() {
62                    push_func_export(&mut wat, resolve, Some(name), func, mangling);
63                }
64                for (_, ty) in resolve.interfaces[*export].types.iter() {
65                    push_exported_resource_functions(&mut wat, resolve, name, *ty, mangling);
66                }
67            }
68            WorldItem::Type { .. } => {}
69        }
70    }
71
72    let memory = resolve.wasm_export_name(mangling, WasmExport::Memory);
73    wat.push_str(&format!("(memory (export {memory:?}) 0)\n"));
74    let realloc = resolve.wasm_export_name(mangling, WasmExport::Realloc);
75    wat.push_str(&format!(
76        "(func (export {realloc:?}) (param i32 i32 i32 i32) (result i32) unreachable)\n"
77    ));
78
79    let initialize = resolve.wasm_export_name(mangling, WasmExport::Initialize);
80    wat.push_str(&format!("(func (export {initialize:?}))"));
81    wat.push_str(")\n");
82
83    return wat::parse_str(&wat).unwrap();
84}
85
86fn push_imported_func(
87    wat: &mut String,
88    resolve: &Resolve,
89    interface: Option<&WorldKey>,
90    func: &Function,
91    mangling: ManglingAndAbi,
92) {
93    let mangling = mangling.for_func(func);
94    let sig = resolve.wasm_signature(mangling.import_variant(), func);
95
96    let (module, name) = resolve.wasm_import_name(mangling, WasmImport::Func { interface, func });
97    wat.push_str(&format!("(import {module:?} {name:?} (func"));
98    push_tys(wat, "param", &sig.params);
99    push_tys(wat, "result", &sig.results);
100    wat.push_str("))\n");
101
102    if mangling.is_async() {
103        push_imported_future_and_stream_intrinsics(wat, resolve, mangling, false, interface, func);
104    }
105}
106
107fn push_imported_type_intrinsics(
108    wat: &mut String,
109    resolve: &Resolve,
110    interface: Option<&WorldKey>,
111    resource: TypeId,
112    mangling: ManglingAndAbi,
113) {
114    let ty = &resolve.types[resource];
115    match ty.kind {
116        TypeDefKind::Resource => {
117            let (module, name) = resolve.wasm_import_name(
118                // Force using a sync ABI here at this time as support for async
119                // resource drop isn't implemented yet.
120                mangling.sync(),
121                WasmImport::ResourceIntrinsic {
122                    interface,
123                    resource,
124                    intrinsic: ResourceIntrinsic::ImportedDrop,
125                },
126            );
127            wat.push_str(&format!("(import {module:?} {name:?} (func (param i32)))"));
128
129            if mangling.is_async() {
130                // TODO: when wit-component supports async resource drop,
131                // implement it here too.
132                // let name = format!("[async-lower]{name}");
133                // wat.push_str(&format!("(import {module:?} {name:?} (func (param i32)))"));
134            }
135        }
136
137        // No other types with intrinsics at this time (futures/streams are
138        // relative to where they show up in function types.
139        _ => {}
140    }
141}
142
143fn push_exported_func_intrinsics(
144    wat: &mut String,
145    resolve: &Resolve,
146    interface: Option<&WorldKey>,
147    func: &Function,
148    mangling: ManglingAndAbi,
149) {
150    if !mangling.is_async() {
151        return;
152    }
153
154    // For exported async functions, generate a `task.return` intrinsic.
155    let (module, name, sig) = func.task_return_import(resolve, interface, mangling.mangling());
156    wat.push_str(&format!("(import {module:?} {name:?} (func"));
157    push_tys(wat, "param", &sig.params);
158    push_tys(wat, "result", &sig.results);
159    wat.push_str("))\n");
160
161    push_imported_future_and_stream_intrinsics(wat, resolve, mangling, true, interface, func);
162}
163
164fn push_imported_future_and_stream_intrinsics(
165    wat: &mut String,
166    resolve: &Resolve,
167    mangling: ManglingAndAbi,
168    exported: bool,
169    interface: Option<&WorldKey>,
170    func: &Function,
171) {
172    for id in func.find_futures_and_streams(resolve).into_iter() {
173        match &resolve.types[id].kind {
174            TypeDefKind::Future(_) => {
175                let mut module = None;
176                let mut intrinsic_name = |intrinsic, async_| {
177                    let (m, name) = resolve.wasm_import_name(
178                        mangling,
179                        WasmImport::FutureIntrinsic {
180                            interface,
181                            func,
182                            ty: Some(id),
183                            intrinsic,
184                            exported,
185                            async_,
186                        },
187                    );
188                    if let Some(prev) = &module {
189                        debug_assert_eq!(prev, &m);
190                    } else {
191                        module = Some(m);
192                    }
193                    name
194                };
195
196                let new = intrinsic_name(FutureIntrinsic::New, false);
197                let read = intrinsic_name(FutureIntrinsic::Read, false);
198                let write = intrinsic_name(FutureIntrinsic::Write, false);
199                let cancel_read = intrinsic_name(FutureIntrinsic::CancelRead, false);
200                let cancel_write = intrinsic_name(FutureIntrinsic::CancelWrite, false);
201                let drop_readable = intrinsic_name(FutureIntrinsic::DropReadable, false);
202                let drop_writable = intrinsic_name(FutureIntrinsic::DropWritable, false);
203                let async_read = intrinsic_name(FutureIntrinsic::Read, true);
204                let async_write = intrinsic_name(FutureIntrinsic::Write, true);
205                let async_cancel_read = intrinsic_name(FutureIntrinsic::CancelRead, true);
206                let async_cancel_write = intrinsic_name(FutureIntrinsic::CancelWrite, true);
207                let module = module.unwrap();
208
209                wat.push_str(&format!(
210                    r#"
211(import {module:?} {new:?} (func (result i64)))
212(import {module:?} {cancel_read:?} (func (param i32) (result i32)))
213(import {module:?} {cancel_write:?} (func (param i32) (result i32)))
214(import {module:?} {drop_readable:?} (func (param i32)))
215(import {module:?} {drop_writable:?} (func (param i32)))
216(import {module:?} {async_read:?} (func (param i32 i32) (result i32)))
217(import {module:?} {async_write:?} (func (param i32 i32) (result i32)))
218
219;; deferred behind ๐Ÿš
220;;(import {module:?} {read:?} (func (param i32 i32) (result i32)))
221;;(import {module:?} {write:?} (func (param i32 i32) (result i32)))
222;;(import {module:?} {async_cancel_read:?} (func (param i32) (result i32)))
223;;(import {module:?} {async_cancel_write:?} (func (param i32) (result i32)))
224"#
225                ));
226            }
227            TypeDefKind::Stream(_) => {
228                let mut module = None;
229                let mut intrinsic_name = |intrinsic, async_| {
230                    let (m, name) = resolve.wasm_import_name(
231                        mangling,
232                        WasmImport::StreamIntrinsic {
233                            interface,
234                            func,
235                            ty: Some(id),
236                            intrinsic,
237                            exported,
238                            async_,
239                        },
240                    );
241                    if let Some(prev) = &module {
242                        debug_assert_eq!(prev, &m);
243                    } else {
244                        module = Some(m);
245                    }
246                    name
247                };
248
249                let new = intrinsic_name(StreamIntrinsic::New, false);
250                let read = intrinsic_name(StreamIntrinsic::Read, false);
251                let write = intrinsic_name(StreamIntrinsic::Write, false);
252                let cancel_read = intrinsic_name(StreamIntrinsic::CancelRead, false);
253                let cancel_write = intrinsic_name(StreamIntrinsic::CancelWrite, false);
254                let drop_readable = intrinsic_name(StreamIntrinsic::DropReadable, false);
255                let drop_writable = intrinsic_name(StreamIntrinsic::DropWritable, false);
256                let async_read = intrinsic_name(StreamIntrinsic::Read, true);
257                let async_write = intrinsic_name(StreamIntrinsic::Write, true);
258                let async_cancel_read = intrinsic_name(StreamIntrinsic::CancelRead, true);
259                let async_cancel_write = intrinsic_name(StreamIntrinsic::CancelWrite, true);
260                let module = module.unwrap();
261
262                wat.push_str(&format!(
263                    r#"
264(import {module:?} {new:?} (func (result i64)))
265(import {module:?} {cancel_read:?} (func (param i32) (result i32)))
266(import {module:?} {cancel_write:?} (func (param i32) (result i32)))
267(import {module:?} {drop_readable:?} (func (param i32)))
268(import {module:?} {drop_writable:?} (func (param i32)))
269(import {module:?} {async_read:?} (func (param i32 i32 i32) (result i32)))
270(import {module:?} {async_write:?} (func (param i32 i32 i32) (result i32)))
271
272;; deferred behind ๐Ÿš
273;;(import {module:?} {read:?} (func (param i32 i32 i32) (result i32)))
274;;(import {module:?} {write:?} (func (param i32 i32 i32) (result i32)))
275;;(import {module:?} {async_cancel_read:?} (func (param i32) (result i32)))
276;;(import {module:?} {async_cancel_write:?} (func (param i32) (result i32)))
277"#
278                ));
279            }
280            _ => unreachable!(),
281        }
282    }
283}
284
285fn push_exported_type_intrinsics(
286    wat: &mut String,
287    resolve: &Resolve,
288    interface: Option<&WorldKey>,
289    resource: TypeId,
290    mangling: ManglingAndAbi,
291) {
292    let ty = &resolve.types[resource];
293    match ty.kind {
294        TypeDefKind::Resource => {
295            let intrinsics = [
296                (ResourceIntrinsic::ExportedDrop, "(func (param i32))"),
297                (
298                    ResourceIntrinsic::ExportedNew,
299                    "(func (param i32) (result i32))",
300                ),
301                (
302                    ResourceIntrinsic::ExportedRep,
303                    "(func (param i32) (result i32))",
304                ),
305            ];
306            for (intrinsic, sig) in intrinsics {
307                let (module, name) = resolve.wasm_import_name(
308                    mangling.sync(),
309                    WasmImport::ResourceIntrinsic {
310                        interface,
311                        resource,
312                        intrinsic,
313                    },
314                );
315                wat.push_str(&format!("(import {module:?} {name:?} {sig})\n"));
316            }
317        }
318
319        // No other types with intrinsics at this time (futures/streams
320        // relative to where they are in a function).
321        _ => {}
322    }
323}
324
325fn push_exported_resource_functions(
326    wat: &mut String,
327    resolve: &Resolve,
328    interface: &WorldKey,
329    resource: TypeId,
330    mangling: ManglingAndAbi,
331) {
332    let ty = &resolve.types[resource];
333    match ty.kind {
334        TypeDefKind::Resource => {}
335        _ => return,
336    }
337    // Feign destructors for any resource that this interface
338    // exports
339    let name = resolve.wasm_export_name(
340        mangling,
341        WasmExport::ResourceDtor {
342            interface,
343            resource,
344        },
345    );
346    wat.push_str(&format!("(func (export {name:?}) (param i32))"));
347}
348
349fn push_func_export(
350    wat: &mut String,
351    resolve: &Resolve,
352    interface: Option<&WorldKey>,
353    func: &Function,
354    mangling: ManglingAndAbi,
355) {
356    let mangling = mangling.for_func(func);
357    let sig = resolve.wasm_signature(mangling.export_variant(), func);
358    let name = resolve.wasm_export_name(
359        mangling,
360        WasmExport::Func {
361            interface,
362            func,
363            kind: WasmExportKind::Normal,
364        },
365    );
366    wat.push_str(&format!("(func (export \"{name}\")"));
367    push_tys(wat, "param", &sig.params);
368    push_tys(wat, "result", &sig.results);
369    wat.push_str(" unreachable)\n");
370
371    match mangling {
372        ManglingAndAbi::Standard32 | ManglingAndAbi::Legacy(LiftLowerAbi::Sync) => {
373            let name = resolve.wasm_export_name(
374                mangling,
375                WasmExport::Func {
376                    interface,
377                    func,
378                    kind: WasmExportKind::PostReturn,
379                },
380            );
381            wat.push_str(&format!("(func (export \"{name}\")"));
382            push_tys(wat, "param", &sig.results);
383            wat.push_str(")\n");
384        }
385        ManglingAndAbi::Legacy(LiftLowerAbi::AsyncCallback) => {
386            let name = resolve.wasm_export_name(
387                mangling,
388                WasmExport::Func {
389                    interface,
390                    func,
391                    kind: WasmExportKind::Callback,
392                },
393            );
394            wat.push_str(&format!(
395                "(func (export \"{name}\") (param i32 i32 i32) (result i32) unreachable)\n"
396            ));
397        }
398        ManglingAndAbi::Legacy(LiftLowerAbi::AsyncStackful) => {}
399    }
400}
401
402fn push_tys(dst: &mut String, desc: &str, params: &[WasmType]) {
403    if params.is_empty() {
404        return;
405    }
406    dst.push_str(" (");
407    dst.push_str(desc);
408    for ty in params {
409        dst.push(' ');
410        match ty {
411            WasmType::I32 => dst.push_str("i32"),
412            WasmType::I64 => dst.push_str("i64"),
413            WasmType::F32 => dst.push_str("f32"),
414            WasmType::F64 => dst.push_str("f64"),
415            WasmType::Pointer => dst.push_str("i32"),
416            WasmType::PointerOrI64 => dst.push_str("i64"),
417            WasmType::Length => dst.push_str("i32"),
418        }
419    }
420    dst.push(')');
421}
422
423fn push_root_async_intrinsics(dst: &mut String) {
424    dst.push_str(
425        r#"
426(import "[export]$root" "[task-cancel]" (func))
427(import "$root" "[backpressure-inc]" (func))
428(import "$root" "[backpressure-dec]" (func))
429(import "$root" "[waitable-set-new]" (func (result i32)))
430(import "$root" "[waitable-set-wait]" (func (param i32 i32) (result i32)))
431(import "$root" "[waitable-set-poll]" (func (param i32 i32) (result i32)))
432(import "$root" "[waitable-set-drop]" (func (param i32)))
433(import "$root" "[waitable-join]" (func (param i32 i32)))
434(import "$root" "[thread-yield]" (func (result i32)))
435(import "$root" "[subtask-drop]" (func (param i32)))
436(import "$root" "[subtask-cancel]" (func (param i32) (result i32)))
437(import "$root" "[context-get-0]" (func (result i32)))
438(import "$root" "[context-set-0]" (func (param i32)))
439
440;; deferred behind ๐Ÿงต upstream
441;;(import "$root" "[cancellable][waitable-set-wait]" (func (param i32 i32) (result i32)))
442;;(import "$root" "[cancellable][waitable-set-poll]" (func (param i32 i32) (result i32)))
443;;(import "$root" "[cancellable][thread-yield]" (func (result i32)))
444;;(import "$root" "[context-get-1]" (func (result i32)))
445;;(import "$root" "[context-set-1]" (func (param i32)))
446
447;; deferred behind ๐Ÿ“ upstream
448;;(import "$root" "[error-context-new-utf8]" (func (param i32 i32) (result i32)))
449;;(import "$root" "[error-context-new-utf16]" (func (param i32 i32) (result i32)))
450;;(import "$root" "[error-context-new-latin1+utf16]" (func (param i32 i32) (result i32)))
451;;(import "$root" "[error-context-debug-message-utf8]" (func (param i32 i32)))
452;;(import "$root" "[error-context-debug-message-utf16]" (func (param i32 i32)))
453;;(import "$root" "[error-context-debug-message-latin1+utf16]" (func (param i32 i32)))
454;;(import "$root" "[error-context-drop]" (func (param i32)))
455"#,
456    );
457}