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 forward = intrinsic_name(FutureIntrinsic::Forward, false);
204                let async_read = intrinsic_name(FutureIntrinsic::Read, true);
205                let async_write = intrinsic_name(FutureIntrinsic::Write, true);
206                let async_cancel_read = intrinsic_name(FutureIntrinsic::CancelRead, true);
207                let async_cancel_write = intrinsic_name(FutureIntrinsic::CancelWrite, true);
208                let module = module.unwrap();
209
210                wat.push_str(&format!(
211                    r#"
212(import {module:?} {new:?} (func (result i64)))
213(import {module:?} {cancel_read:?} (func (param i32) (result i32)))
214(import {module:?} {cancel_write:?} (func (param i32) (result i32)))
215(import {module:?} {drop_readable:?} (func (param i32)))
216(import {module:?} {drop_writable:?} (func (param i32)))
217(import {module:?} {forward:?} (func (param i32 i32)))
218(import {module:?} {async_read:?} (func (param i32 i32) (result i32)))
219(import {module:?} {async_write:?} (func (param i32 i32) (result i32)))
220
221;; deferred behind ๐Ÿš
222;;(import {module:?} {read:?} (func (param i32 i32) (result i32)))
223;;(import {module:?} {write:?} (func (param i32 i32) (result i32)))
224;;(import {module:?} {async_cancel_read:?} (func (param i32) (result i32)))
225;;(import {module:?} {async_cancel_write:?} (func (param i32) (result i32)))
226"#
227                ));
228            }
229            TypeDefKind::Stream(_) => {
230                let mut module = None;
231                let mut intrinsic_name = |intrinsic, async_| {
232                    let (m, name) = resolve.wasm_import_name(
233                        mangling,
234                        WasmImport::StreamIntrinsic {
235                            interface,
236                            func,
237                            ty: Some(id),
238                            intrinsic,
239                            exported,
240                            async_,
241                        },
242                    );
243                    if let Some(prev) = &module {
244                        debug_assert_eq!(prev, &m);
245                    } else {
246                        module = Some(m);
247                    }
248                    name
249                };
250
251                let new = intrinsic_name(StreamIntrinsic::New, false);
252                let read = intrinsic_name(StreamIntrinsic::Read, false);
253                let write = intrinsic_name(StreamIntrinsic::Write, false);
254                let cancel_read = intrinsic_name(StreamIntrinsic::CancelRead, false);
255                let cancel_write = intrinsic_name(StreamIntrinsic::CancelWrite, false);
256                let drop_readable = intrinsic_name(StreamIntrinsic::DropReadable, false);
257                let drop_writable = intrinsic_name(StreamIntrinsic::DropWritable, false);
258                let forward = intrinsic_name(StreamIntrinsic::Forward, false);
259                let async_read = intrinsic_name(StreamIntrinsic::Read, true);
260                let async_write = intrinsic_name(StreamIntrinsic::Write, true);
261                let async_cancel_read = intrinsic_name(StreamIntrinsic::CancelRead, true);
262                let async_cancel_write = intrinsic_name(StreamIntrinsic::CancelWrite, true);
263                let module = module.unwrap();
264
265                wat.push_str(&format!(
266                    r#"
267(import {module:?} {new:?} (func (result i64)))
268(import {module:?} {cancel_read:?} (func (param i32) (result i32)))
269(import {module:?} {cancel_write:?} (func (param i32) (result i32)))
270(import {module:?} {drop_readable:?} (func (param i32)))
271(import {module:?} {drop_writable:?} (func (param i32)))
272(import {module:?} {forward:?} (func (param i32 i32)))
273(import {module:?} {async_read:?} (func (param i32 i32 i32) (result i32)))
274(import {module:?} {async_write:?} (func (param i32 i32 i32) (result i32)))
275
276;; deferred behind ๐Ÿš
277;;(import {module:?} {read:?} (func (param i32 i32 i32) (result i32)))
278;;(import {module:?} {write:?} (func (param i32 i32 i32) (result i32)))
279;;(import {module:?} {async_cancel_read:?} (func (param i32) (result i32)))
280;;(import {module:?} {async_cancel_write:?} (func (param i32) (result i32)))
281"#
282                ));
283            }
284            _ => unreachable!(),
285        }
286    }
287}
288
289fn push_exported_type_intrinsics(
290    wat: &mut String,
291    resolve: &Resolve,
292    interface: Option<&WorldKey>,
293    resource: TypeId,
294    mangling: ManglingAndAbi,
295) {
296    let ty = &resolve.types[resource];
297    match ty.kind {
298        TypeDefKind::Resource => {
299            let intrinsics = [
300                (ResourceIntrinsic::ExportedDrop, "(func (param i32))"),
301                (
302                    ResourceIntrinsic::ExportedNew,
303                    "(func (param i32) (result i32))",
304                ),
305                (
306                    ResourceIntrinsic::ExportedRep,
307                    "(func (param i32) (result i32))",
308                ),
309            ];
310            for (intrinsic, sig) in intrinsics {
311                let (module, name) = resolve.wasm_import_name(
312                    mangling.sync(),
313                    WasmImport::ResourceIntrinsic {
314                        interface,
315                        resource,
316                        intrinsic,
317                    },
318                );
319                wat.push_str(&format!("(import {module:?} {name:?} {sig})\n"));
320            }
321        }
322
323        // No other types with intrinsics at this time (futures/streams
324        // relative to where they are in a function).
325        _ => {}
326    }
327}
328
329fn push_exported_resource_functions(
330    wat: &mut String,
331    resolve: &Resolve,
332    interface: &WorldKey,
333    resource: TypeId,
334    mangling: ManglingAndAbi,
335) {
336    let ty = &resolve.types[resource];
337    match ty.kind {
338        TypeDefKind::Resource => {}
339        _ => return,
340    }
341    // Feign destructors for any resource that this interface
342    // exports
343    let name = resolve.wasm_export_name(
344        mangling,
345        WasmExport::ResourceDtor {
346            interface,
347            resource,
348        },
349    );
350    wat.push_str(&format!("(func (export {name:?}) (param i32))"));
351}
352
353fn push_func_export(
354    wat: &mut String,
355    resolve: &Resolve,
356    interface: Option<&WorldKey>,
357    func: &Function,
358    mangling: ManglingAndAbi,
359) {
360    let mangling = mangling.for_func(func);
361    let sig = resolve.wasm_signature(mangling.export_variant(), func);
362    let name = resolve.wasm_export_name(
363        mangling,
364        WasmExport::Func {
365            interface,
366            func,
367            kind: WasmExportKind::Normal,
368        },
369    );
370    wat.push_str(&format!("(func (export \"{name}\")"));
371    push_tys(wat, "param", &sig.params);
372    push_tys(wat, "result", &sig.results);
373    wat.push_str(" unreachable)\n");
374
375    match mangling {
376        ManglingAndAbi::Standard32 | ManglingAndAbi::Legacy(LiftLowerAbi::Sync) => {
377            let name = resolve.wasm_export_name(
378                mangling,
379                WasmExport::Func {
380                    interface,
381                    func,
382                    kind: WasmExportKind::PostReturn,
383                },
384            );
385            wat.push_str(&format!("(func (export \"{name}\")"));
386            push_tys(wat, "param", &sig.results);
387            wat.push_str(")\n");
388        }
389        ManglingAndAbi::Legacy(LiftLowerAbi::AsyncCallback) => {
390            let name = resolve.wasm_export_name(
391                mangling,
392                WasmExport::Func {
393                    interface,
394                    func,
395                    kind: WasmExportKind::Callback,
396                },
397            );
398            wat.push_str(&format!(
399                "(func (export \"{name}\") (param i32 i32 i32) (result i32) unreachable)\n"
400            ));
401        }
402        ManglingAndAbi::Legacy(LiftLowerAbi::AsyncStackful) => {}
403    }
404}
405
406fn push_tys(dst: &mut String, desc: &str, params: &[WasmType]) {
407    if params.is_empty() {
408        return;
409    }
410    dst.push_str(" (");
411    dst.push_str(desc);
412    for ty in params {
413        dst.push(' ');
414        match ty {
415            WasmType::I32 => dst.push_str("i32"),
416            WasmType::I64 => dst.push_str("i64"),
417            WasmType::F32 => dst.push_str("f32"),
418            WasmType::F64 => dst.push_str("f64"),
419            WasmType::Pointer => dst.push_str("i32"),
420            WasmType::PointerOrI64 => dst.push_str("i64"),
421            WasmType::Length => dst.push_str("i32"),
422        }
423    }
424    dst.push(')');
425}
426
427fn push_root_async_intrinsics(dst: &mut String) {
428    dst.push_str(
429        r#"
430(import "[export]$root" "[task-cancel]" (func))
431(import "$root" "[backpressure-inc]" (func))
432(import "$root" "[backpressure-dec]" (func))
433(import "$root" "[waitable-set-new]" (func (result i32)))
434(import "$root" "[waitable-set-wait]" (func (param i32 i32) (result i32)))
435(import "$root" "[waitable-set-poll]" (func (param i32 i32) (result i32)))
436(import "$root" "[waitable-set-drop]" (func (param i32)))
437(import "$root" "[waitable-join]" (func (param i32 i32)))
438(import "$root" "[thread-yield]" (func (result i32)))
439(import "$root" "[subtask-drop]" (func (param i32)))
440(import "$root" "[subtask-cancel]" (func (param i32) (result i32)))
441(import "$root" "[context-get-0]" (func (result i32)))
442(import "$root" "[context-set-0]" (func (param i32)))
443
444;; deferred behind ๐Ÿงต upstream
445;;(import "$root" "[cancellable][waitable-set-wait]" (func (param i32 i32) (result i32)))
446;;(import "$root" "[cancellable][waitable-set-poll]" (func (param i32 i32) (result i32)))
447;;(import "$root" "[cancellable][thread-yield]" (func (result i32)))
448;;(import "$root" "[context-get-1]" (func (result i32)))
449;;(import "$root" "[context-set-1]" (func (param i32)))
450
451;; deferred behind ๐Ÿ“ upstream
452;;(import "$root" "[error-context-new-utf8]" (func (param i32 i32) (result i32)))
453;;(import "$root" "[error-context-new-utf16]" (func (param i32 i32) (result i32)))
454;;(import "$root" "[error-context-new-latin1+utf16]" (func (param i32 i32) (result i32)))
455;;(import "$root" "[error-context-debug-message-utf8]" (func (param i32 i32)))
456;;(import "$root" "[error-context-debug-message-utf16]" (func (param i32 i32)))
457;;(import "$root" "[error-context-debug-message-latin1+utf16]" (func (param i32 i32)))
458;;(import "$root" "[error-context-drop]" (func (param i32)))
459"#,
460    );
461}