1use wit_parser::abi::{AbiVariant, WasmType};
2use wit_parser::{
3 Function, LiftLowerAbi, ManglingAndAbi, Resolve, ResourceIntrinsic, TypeDefKind, TypeId,
4 WasmExport, WasmExportKind, WasmImport, WorldId, WorldItem, WorldKey,
5};
6
7pub fn dummy_module(resolve: &Resolve, world: WorldId, mangling: ManglingAndAbi) -> Vec<u8> {
9 let world = &resolve.worlds[world];
10 let mut wat = String::new();
11 wat.push_str("(module\n");
12 for (name, import) in world.imports.iter() {
13 match import {
14 WorldItem::Function(func) => {
15 push_imported_func(&mut wat, resolve, None, func, mangling);
16 }
17 WorldItem::Interface { id: import, .. } => {
18 for (_, func) in resolve.interfaces[*import].functions.iter() {
19 push_imported_func(&mut wat, resolve, Some(name), func, mangling);
20 }
21 for (_, ty) in resolve.interfaces[*import].types.iter() {
22 push_imported_type_intrinsics(&mut wat, resolve, Some(name), *ty, mangling);
23 }
24 }
25 WorldItem::Type(id) => {
26 push_imported_type_intrinsics(&mut wat, resolve, None, *id, mangling);
27 }
28 }
29 }
30
31 if mangling.is_async() {
32 push_root_async_intrinsics(&mut wat);
33 }
34
35 for (name, export) in world.exports.iter() {
38 match export {
39 WorldItem::Function(func) => {
40 push_exported_func_intrinsics(&mut wat, resolve, None, func, mangling);
41 }
42 WorldItem::Interface { id: export, .. } => {
43 for (_, func) in resolve.interfaces[*export].functions.iter() {
44 push_exported_func_intrinsics(&mut wat, resolve, Some(name), func, mangling);
45 }
46 for (_, ty) in resolve.interfaces[*export].types.iter() {
47 push_exported_type_intrinsics(&mut wat, resolve, Some(name), *ty, mangling);
48 }
49 }
50 WorldItem::Type(_) => {}
51 }
52 }
53
54 for (name, export) in world.exports.iter() {
55 match export {
56 WorldItem::Function(func) => {
57 push_func_export(&mut wat, resolve, None, func, mangling);
58 }
59 WorldItem::Interface { id: export, .. } => {
60 for (_, func) in resolve.interfaces[*export].functions.iter() {
61 push_func_export(&mut wat, resolve, Some(name), func, mangling);
62 }
63 for (_, ty) in resolve.interfaces[*export].types.iter() {
64 push_exported_resource_functions(&mut wat, resolve, name, *ty, mangling);
65 }
66 }
67 WorldItem::Type(_) => {}
68 }
69 }
70
71 let memory = resolve.wasm_export_name(mangling, WasmExport::Memory);
72 wat.push_str(&format!("(memory (export {memory:?}) 0)\n"));
73 let realloc = resolve.wasm_export_name(mangling, WasmExport::Realloc);
74 wat.push_str(&format!(
75 "(func (export {realloc:?}) (param i32 i32 i32 i32) (result i32) unreachable)\n"
76 ));
77
78 let initialize = resolve.wasm_export_name(mangling, WasmExport::Initialize);
79 wat.push_str(&format!("(func (export {initialize:?}))"));
80 wat.push_str(")\n");
81
82 return wat::parse_str(&wat).unwrap();
83}
84
85fn push_imported_func(
86 wat: &mut String,
87 resolve: &Resolve,
88 interface: Option<&WorldKey>,
89 func: &Function,
90 mangling: ManglingAndAbi,
91) {
92 let sig = resolve.wasm_signature(mangling.import_variant(), func);
93
94 let (module, name) = resolve.wasm_import_name(mangling, WasmImport::Func { interface, func });
95 wat.push_str(&format!("(import {module:?} {name:?} (func"));
96 push_tys(wat, "param", &sig.params);
97 push_tys(wat, "result", &sig.results);
98 wat.push_str("))\n");
99
100 if mangling.is_async() {
101 push_imported_future_and_stream_intrinsics(wat, resolve, "", interface, func);
102 }
103}
104
105fn push_imported_type_intrinsics(
106 wat: &mut String,
107 resolve: &Resolve,
108 interface: Option<&WorldKey>,
109 resource: TypeId,
110 mangling: ManglingAndAbi,
111) {
112 let ty = &resolve.types[resource];
113 match ty.kind {
114 TypeDefKind::Resource => {
115 let (module, name) = resolve.wasm_import_name(
116 mangling.sync(),
119 WasmImport::ResourceIntrinsic {
120 interface,
121 resource,
122 intrinsic: ResourceIntrinsic::ImportedDrop,
123 },
124 );
125 wat.push_str(&format!("(import {module:?} {name:?} (func (param i32)))"));
126
127 if mangling.is_async() {
128 }
133 }
134
135 _ => {}
138 }
139}
140
141fn push_exported_func_intrinsics(
142 wat: &mut String,
143 resolve: &Resolve,
144 interface: Option<&WorldKey>,
145 func: &Function,
146 mangling: ManglingAndAbi,
147) {
148 if !mangling.is_async() {
149 return;
150 }
151
152 let module = match interface {
154 Some(key) => format!("[export]{}", resolve.name_world_key(key)),
155 None => "[export]$root".to_string(),
156 };
157 let name = format!("[task-return]{}", func.name);
158 let mut func_tmp = func.clone();
159 func_tmp.params = Vec::new();
160 func_tmp.result = None;
161 if let Some(ty) = func.result {
162 func_tmp.params.push(("x".to_string(), ty));
163 }
164 let sig = resolve.wasm_signature(AbiVariant::GuestImport, &func_tmp);
165 wat.push_str(&format!("(import {module:?} {name:?} (func"));
166 push_tys(wat, "param", &sig.params);
167 push_tys(wat, "result", &sig.results);
168 wat.push_str("))\n");
169
170 push_imported_future_and_stream_intrinsics(wat, resolve, "[export]", interface, func);
171}
172
173fn push_imported_future_and_stream_intrinsics(
174 wat: &mut String,
175 resolve: &Resolve,
176 module_prefix: &str,
177 interface: Option<&WorldKey>,
178 func: &Function,
179) {
180 let module = match interface {
181 Some(key) => format!("{module_prefix}{}", resolve.name_world_key(key)),
182 None => format!("{module_prefix}$root"),
183 };
184 let name = &func.name;
185
186 for (i, id) in func
187 .find_futures_and_streams(resolve)
188 .into_iter()
189 .enumerate()
190 {
191 match &resolve.types[id].kind {
192 TypeDefKind::Future(_) => {
193 wat.push_str(&format!(
194 r#"
195(import {module:?} "[future-new-{i}]{name}" (func (result i32)))
196(import {module:?} "[future-read-{i}]{name}" (func (param i32 i32) (result i32)))
197(import {module:?} "[future-write-{i}]{name}" (func (param i32 i32) (result i32)))
198(import {module:?} "[future-cancel-read-{i}]{name}" (func (param i32) (result i32)))
199(import {module:?} "[future-cancel-write-{i}]{name}" (func (param i32) (result i32)))
200(import {module:?} "[future-close-readable-{i}]{name}" (func (param i32 i32)))
201(import {module:?} "[future-close-writable-{i}]{name}" (func (param i32 i32)))
202(import {module:?} "[async-lower][future-read-{i}]{name}" (func (param i32 i32) (result i32)))
203(import {module:?} "[async-lower][future-write-{i}]{name}" (func (param i32 i32) (result i32)))
204(import {module:?} "[async-lower][future-cancel-read-{i}]{name}" (func (param i32) (result i32)))
205(import {module:?} "[async-lower][future-cancel-write-{i}]{name}" (func (param i32) (result i32)))
206"#
207 ));
208 }
209 TypeDefKind::Stream(_) => {
210 wat.push_str(&format!(
211 r#"
212(import {module:?} "[stream-new-{i}]{name}" (func (result i32)))
213(import {module:?} "[stream-read-{i}]{name}" (func (param i32 i32 i32) (result i32)))
214(import {module:?} "[stream-write-{i}]{name}" (func (param i32 i32 i32) (result i32)))
215(import {module:?} "[stream-cancel-read-{i}]{name}" (func (param i32) (result i32)))
216(import {module:?} "[stream-cancel-write-{i}]{name}" (func (param i32) (result i32)))
217(import {module:?} "[stream-close-readable-{i}]{name}" (func (param i32 i32)))
218(import {module:?} "[stream-close-writable-{i}]{name}" (func (param i32 i32)))
219(import {module:?} "[async-lower][stream-read-{i}]{name}" (func (param i32 i32 i32) (result i32)))
220(import {module:?} "[async-lower][stream-write-{i}]{name}" (func (param i32 i32 i32) (result i32)))
221(import {module:?} "[async-lower][stream-cancel-read-{i}]{name}" (func (param i32) (result i32)))
222(import {module:?} "[async-lower][stream-cancel-write-{i}]{name}" (func (param i32) (result i32)))
223"#
224 ));
225 }
226 _ => unreachable!(),
227 }
228 }
229}
230
231fn push_exported_type_intrinsics(
232 wat: &mut String,
233 resolve: &Resolve,
234 interface: Option<&WorldKey>,
235 resource: TypeId,
236 mangling: ManglingAndAbi,
237) {
238 let ty = &resolve.types[resource];
239 match ty.kind {
240 TypeDefKind::Resource => {
241 let intrinsics = [
242 (ResourceIntrinsic::ExportedDrop, "(func (param i32))"),
243 (
244 ResourceIntrinsic::ExportedNew,
245 "(func (param i32) (result i32))",
246 ),
247 (
248 ResourceIntrinsic::ExportedRep,
249 "(func (param i32) (result i32))",
250 ),
251 ];
252 for (intrinsic, sig) in intrinsics {
253 let (module, name) = resolve.wasm_import_name(
254 mangling.sync(),
255 WasmImport::ResourceIntrinsic {
256 interface,
257 resource,
258 intrinsic,
259 },
260 );
261 wat.push_str(&format!("(import {module:?} {name:?} {sig})\n"));
262 }
263 }
264
265 _ => {}
268 }
269}
270
271fn push_exported_resource_functions(
272 wat: &mut String,
273 resolve: &Resolve,
274 interface: &WorldKey,
275 resource: TypeId,
276 mangling: ManglingAndAbi,
277) {
278 let ty = &resolve.types[resource];
279 match ty.kind {
280 TypeDefKind::Resource => {}
281 _ => return,
282 }
283 let name = resolve.wasm_export_name(
286 mangling,
287 WasmExport::ResourceDtor {
288 interface,
289 resource,
290 },
291 );
292 wat.push_str(&format!("(func (export {name:?}) (param i32))"));
293}
294
295fn push_func_export(
296 wat: &mut String,
297 resolve: &Resolve,
298 interface: Option<&WorldKey>,
299 func: &Function,
300 mangling: ManglingAndAbi,
301) {
302 let sig = resolve.wasm_signature(mangling.export_variant(), func);
303 let name = resolve.wasm_export_name(
304 mangling,
305 WasmExport::Func {
306 interface,
307 func,
308 kind: WasmExportKind::Normal,
309 },
310 );
311 wat.push_str(&format!("(func (export \"{name}\")"));
312 push_tys(wat, "param", &sig.params);
313 push_tys(wat, "result", &sig.results);
314 wat.push_str(" unreachable)\n");
315
316 match mangling {
317 ManglingAndAbi::Standard32 | ManglingAndAbi::Legacy(LiftLowerAbi::Sync) => {
318 let name = resolve.wasm_export_name(
319 mangling,
320 WasmExport::Func {
321 interface,
322 func,
323 kind: WasmExportKind::PostReturn,
324 },
325 );
326 wat.push_str(&format!("(func (export \"{name}\")"));
327 push_tys(wat, "param", &sig.results);
328 wat.push_str(")\n");
329 }
330 ManglingAndAbi::Legacy(LiftLowerAbi::AsyncCallback) => {
331 let name = resolve.wasm_export_name(
332 mangling,
333 WasmExport::Func {
334 interface,
335 func,
336 kind: WasmExportKind::Callback,
337 },
338 );
339 wat.push_str(&format!(
340 "(func (export \"{name}\") (param i32 i32 i32 i32) (result i32) unreachable)\n"
341 ));
342 }
343 ManglingAndAbi::Legacy(LiftLowerAbi::AsyncStackful) => {}
344 }
345}
346
347fn push_tys(dst: &mut String, desc: &str, params: &[WasmType]) {
348 if params.is_empty() {
349 return;
350 }
351 dst.push_str(" (");
352 dst.push_str(desc);
353 for ty in params {
354 dst.push(' ');
355 match ty {
356 WasmType::I32 => dst.push_str("i32"),
357 WasmType::I64 => dst.push_str("i64"),
358 WasmType::F32 => dst.push_str("f32"),
359 WasmType::F64 => dst.push_str("f64"),
360 WasmType::Pointer => dst.push_str("i32"),
361 WasmType::PointerOrI64 => dst.push_str("i64"),
362 WasmType::Length => dst.push_str("i32"),
363 }
364 }
365 dst.push(')');
366}
367
368fn push_root_async_intrinsics(dst: &mut String) {
369 dst.push_str(
370 r#"
371(import "$root" "[backpressure-set]" (func (param i32)))
372(import "$root" "[waitable-set-new]" (func (result i32)))
373(import "$root" "[waitable-set-wait]" (func (param i32 i32) (result i32)))
374(import "$root" "[async-lower][waitable-set-wait]" (func (param i32 i32) (result i32)))
375(import "$root" "[waitable-set-poll]" (func (param i32 i32) (result i32)))
376(import "$root" "[async-lower][waitable-set-poll]" (func (param i32 i32) (result i32)))
377(import "$root" "[waitable-set-drop]" (func (param i32)))
378(import "$root" "[waitable-join]" (func (param i32 i32)))
379(import "$root" "[yield]" (func))
380(import "$root" "[async-lower][yield]" (func))
381(import "$root" "[subtask-drop]" (func (param i32)))
382(import "$root" "[error-context-new-utf8]" (func (param i32 i32) (result i32)))
383(import "$root" "[error-context-new-utf16]" (func (param i32 i32) (result i32)))
384(import "$root" "[error-context-new-latin1+utf16]" (func (param i32 i32) (result i32)))
385(import "$root" "[error-context-debug-message-utf8]" (func (param i32 i32)))
386(import "$root" "[error-context-debug-message-utf16]" (func (param i32 i32)))
387(import "$root" "[error-context-debug-message-latin1+utf16]" (func (param i32 i32)))
388(import "$root" "[error-context-drop]" (func (param i32)))
389"#,
390 );
391}