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
8pub 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 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 sig = resolve.wasm_signature(mangling.import_variant(), func);
94
95 let (module, name) = resolve.wasm_import_name(mangling, WasmImport::Func { interface, func });
96 wat.push_str(&format!("(import {module:?} {name:?} (func"));
97 push_tys(wat, "param", &sig.params);
98 push_tys(wat, "result", &sig.results);
99 wat.push_str("))\n");
100
101 if mangling.is_async() {
102 push_imported_future_and_stream_intrinsics(wat, resolve, mangling, false, interface, func);
103 }
104}
105
106fn push_imported_type_intrinsics(
107 wat: &mut String,
108 resolve: &Resolve,
109 interface: Option<&WorldKey>,
110 resource: TypeId,
111 mangling: ManglingAndAbi,
112) {
113 let ty = &resolve.types[resource];
114 match ty.kind {
115 TypeDefKind::Resource => {
116 let (module, name) = resolve.wasm_import_name(
117 mangling.sync(),
120 WasmImport::ResourceIntrinsic {
121 interface,
122 resource,
123 intrinsic: ResourceIntrinsic::ImportedDrop,
124 },
125 );
126 wat.push_str(&format!("(import {module:?} {name:?} (func (param i32)))"));
127
128 if mangling.is_async() {
129 }
134 }
135
136 _ => {}
139 }
140}
141
142fn push_exported_func_intrinsics(
143 wat: &mut String,
144 resolve: &Resolve,
145 interface: Option<&WorldKey>,
146 func: &Function,
147 mangling: ManglingAndAbi,
148) {
149 if !mangling.is_async() {
150 return;
151 }
152
153 let (module, name, sig) = func.task_return_import(resolve, interface, mangling.mangling());
155 wat.push_str(&format!("(import {module:?} {name:?} (func"));
156 push_tys(wat, "param", &sig.params);
157 push_tys(wat, "result", &sig.results);
158 wat.push_str("))\n");
159
160 push_imported_future_and_stream_intrinsics(wat, resolve, mangling, true, interface, func);
161}
162
163fn push_imported_future_and_stream_intrinsics(
164 wat: &mut String,
165 resolve: &Resolve,
166 mangling: ManglingAndAbi,
167 exported: bool,
168 interface: Option<&WorldKey>,
169 func: &Function,
170) {
171 for id in func.find_futures_and_streams(resolve).into_iter() {
172 match &resolve.types[id].kind {
173 TypeDefKind::Future(_) => {
174 let mut module = None;
175 let mut intrinsic_name = |intrinsic, async_| {
176 let (m, name) = resolve.wasm_import_name(
177 mangling,
178 WasmImport::FutureIntrinsic {
179 interface,
180 func,
181 ty: Some(id),
182 intrinsic,
183 exported,
184 async_,
185 },
186 );
187 if let Some(prev) = &module {
188 debug_assert_eq!(prev, &m);
189 } else {
190 module = Some(m);
191 }
192 name
193 };
194
195 let new = intrinsic_name(FutureIntrinsic::New, false);
196 let read = intrinsic_name(FutureIntrinsic::Read, false);
197 let write = intrinsic_name(FutureIntrinsic::Write, false);
198 let cancel_read = intrinsic_name(FutureIntrinsic::CancelRead, false);
199 let cancel_write = intrinsic_name(FutureIntrinsic::CancelWrite, false);
200 let drop_readable = intrinsic_name(FutureIntrinsic::DropReadable, false);
201 let drop_writable = intrinsic_name(FutureIntrinsic::DropWritable, false);
202 let async_read = intrinsic_name(FutureIntrinsic::Read, true);
203 let async_write = intrinsic_name(FutureIntrinsic::Write, true);
204 let async_cancel_read = intrinsic_name(FutureIntrinsic::CancelRead, true);
205 let async_cancel_write = intrinsic_name(FutureIntrinsic::CancelWrite, true);
206 let module = module.unwrap();
207
208 wat.push_str(&format!(
209 r#"
210(import {module:?} {new:?} (func (result i64)))
211(import {module:?} {read:?} (func (param i32 i32) (result i32)))
212(import {module:?} {write:?} (func (param i32 i32) (result i32)))
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:?} {async_read:?} (func (param i32 i32) (result i32)))
218(import {module:?} {async_write:?} (func (param i32 i32) (result i32)))
219
220;; deferred behind ๐
221;;(import {module:?} {async_cancel_read:?} (func (param i32) (result i32)))
222;;(import {module:?} {async_cancel_write:?} (func (param i32) (result i32)))
223"#
224 ));
225 }
226 TypeDefKind::Stream(_) => {
227 let mut module = None;
228 let mut intrinsic_name = |intrinsic, async_| {
229 let (m, name) = resolve.wasm_import_name(
230 mangling,
231 WasmImport::StreamIntrinsic {
232 interface,
233 func,
234 ty: Some(id),
235 intrinsic,
236 exported,
237 async_,
238 },
239 );
240 if let Some(prev) = &module {
241 debug_assert_eq!(prev, &m);
242 } else {
243 module = Some(m);
244 }
245 name
246 };
247
248 let new = intrinsic_name(StreamIntrinsic::New, false);
249 let read = intrinsic_name(StreamIntrinsic::Read, false);
250 let write = intrinsic_name(StreamIntrinsic::Write, false);
251 let cancel_read = intrinsic_name(StreamIntrinsic::CancelRead, false);
252 let cancel_write = intrinsic_name(StreamIntrinsic::CancelWrite, false);
253 let drop_readable = intrinsic_name(StreamIntrinsic::DropReadable, false);
254 let drop_writable = intrinsic_name(StreamIntrinsic::DropWritable, false);
255 let async_read = intrinsic_name(StreamIntrinsic::Read, true);
256 let async_write = intrinsic_name(StreamIntrinsic::Write, true);
257 let async_cancel_read = intrinsic_name(StreamIntrinsic::CancelRead, true);
258 let async_cancel_write = intrinsic_name(StreamIntrinsic::CancelWrite, true);
259 let module = module.unwrap();
260
261 wat.push_str(&format!(
262 r#"
263(import {module:?} {new:?} (func (result i64)))
264(import {module:?} {read:?} (func (param i32 i32 i32) (result i32)))
265(import {module:?} {write:?} (func (param i32 i32 i32) (result i32)))
266(import {module:?} {cancel_read:?} (func (param i32) (result i32)))
267(import {module:?} {cancel_write:?} (func (param i32) (result i32)))
268(import {module:?} {drop_readable:?} (func (param i32)))
269(import {module:?} {drop_writable:?} (func (param i32)))
270(import {module:?} {async_read:?} (func (param i32 i32 i32) (result i32)))
271(import {module:?} {async_write:?} (func (param i32 i32 i32) (result i32)))
272
273;; deferred behind ๐
274;;(import {module:?} {async_cancel_read:?} (func (param i32) (result i32)))
275;;(import {module:?} {async_cancel_write:?} (func (param i32) (result i32)))
276"#
277 ));
278 }
279 _ => unreachable!(),
280 }
281 }
282}
283
284fn push_exported_type_intrinsics(
285 wat: &mut String,
286 resolve: &Resolve,
287 interface: Option<&WorldKey>,
288 resource: TypeId,
289 mangling: ManglingAndAbi,
290) {
291 let ty = &resolve.types[resource];
292 match ty.kind {
293 TypeDefKind::Resource => {
294 let intrinsics = [
295 (ResourceIntrinsic::ExportedDrop, "(func (param i32))"),
296 (
297 ResourceIntrinsic::ExportedNew,
298 "(func (param i32) (result i32))",
299 ),
300 (
301 ResourceIntrinsic::ExportedRep,
302 "(func (param i32) (result i32))",
303 ),
304 ];
305 for (intrinsic, sig) in intrinsics {
306 let (module, name) = resolve.wasm_import_name(
307 mangling.sync(),
308 WasmImport::ResourceIntrinsic {
309 interface,
310 resource,
311 intrinsic,
312 },
313 );
314 wat.push_str(&format!("(import {module:?} {name:?} {sig})\n"));
315 }
316 }
317
318 _ => {}
321 }
322}
323
324fn push_exported_resource_functions(
325 wat: &mut String,
326 resolve: &Resolve,
327 interface: &WorldKey,
328 resource: TypeId,
329 mangling: ManglingAndAbi,
330) {
331 let ty = &resolve.types[resource];
332 match ty.kind {
333 TypeDefKind::Resource => {}
334 _ => return,
335 }
336 let name = resolve.wasm_export_name(
339 mangling,
340 WasmExport::ResourceDtor {
341 interface,
342 resource,
343 },
344 );
345 wat.push_str(&format!("(func (export {name:?}) (param i32))"));
346}
347
348fn push_func_export(
349 wat: &mut String,
350 resolve: &Resolve,
351 interface: Option<&WorldKey>,
352 func: &Function,
353 mangling: ManglingAndAbi,
354) {
355 let sig = resolve.wasm_signature(mangling.export_variant(), func);
356 let name = resolve.wasm_export_name(
357 mangling,
358 WasmExport::Func {
359 interface,
360 func,
361 kind: WasmExportKind::Normal,
362 },
363 );
364 wat.push_str(&format!("(func (export \"{name}\")"));
365 push_tys(wat, "param", &sig.params);
366 push_tys(wat, "result", &sig.results);
367 wat.push_str(" unreachable)\n");
368
369 match mangling {
370 ManglingAndAbi::Standard32 | ManglingAndAbi::Legacy(LiftLowerAbi::Sync) => {
371 let name = resolve.wasm_export_name(
372 mangling,
373 WasmExport::Func {
374 interface,
375 func,
376 kind: WasmExportKind::PostReturn,
377 },
378 );
379 wat.push_str(&format!("(func (export \"{name}\")"));
380 push_tys(wat, "param", &sig.results);
381 wat.push_str(")\n");
382 }
383 ManglingAndAbi::Legacy(LiftLowerAbi::AsyncCallback) => {
384 let name = resolve.wasm_export_name(
385 mangling,
386 WasmExport::Func {
387 interface,
388 func,
389 kind: WasmExportKind::Callback,
390 },
391 );
392 wat.push_str(&format!(
393 "(func (export \"{name}\") (param i32 i32 i32) (result i32) unreachable)\n"
394 ));
395 }
396 ManglingAndAbi::Legacy(LiftLowerAbi::AsyncStackful) => {}
397 }
398}
399
400fn push_tys(dst: &mut String, desc: &str, params: &[WasmType]) {
401 if params.is_empty() {
402 return;
403 }
404 dst.push_str(" (");
405 dst.push_str(desc);
406 for ty in params {
407 dst.push(' ');
408 match ty {
409 WasmType::I32 => dst.push_str("i32"),
410 WasmType::I64 => dst.push_str("i64"),
411 WasmType::F32 => dst.push_str("f32"),
412 WasmType::F64 => dst.push_str("f64"),
413 WasmType::Pointer => dst.push_str("i32"),
414 WasmType::PointerOrI64 => dst.push_str("i64"),
415 WasmType::Length => dst.push_str("i32"),
416 }
417 }
418 dst.push(')');
419}
420
421fn push_root_async_intrinsics(dst: &mut String) {
422 dst.push_str(
423 r#"
424(import "[export]$root" "[task-cancel]" (func))
425(import "$root" "[backpressure-inc]" (func))
426(import "$root" "[backpressure-dec]" (func))
427(import "$root" "[waitable-set-new]" (func (result i32)))
428(import "$root" "[waitable-set-wait]" (func (param i32 i32) (result i32)))
429(import "$root" "[waitable-set-poll]" (func (param i32 i32) (result i32)))
430(import "$root" "[waitable-set-drop]" (func (param i32)))
431(import "$root" "[waitable-join]" (func (param i32 i32)))
432(import "$root" "[thread-yield]" (func (result i32)))
433(import "$root" "[subtask-drop]" (func (param i32)))
434(import "$root" "[subtask-cancel]" (func (param i32) (result i32)))
435(import "$root" "[context-get-0]" (func (result i32)))
436(import "$root" "[context-set-0]" (func (param i32)))
437
438;; deferred behind ๐งต upstream
439;;(import "$root" "[cancellable][waitable-set-wait]" (func (param i32 i32) (result i32)))
440;;(import "$root" "[cancellable][waitable-set-poll]" (func (param i32 i32) (result i32)))
441;;(import "$root" "[cancellable][thread-yield]" (func (result i32)))
442;;(import "$root" "[context-get-1]" (func (result i32)))
443;;(import "$root" "[context-set-1]" (func (param i32)))
444
445;; deferred behind ๐ upstream
446;;(import "$root" "[error-context-new-utf8]" (func (param i32 i32) (result i32)))
447;;(import "$root" "[error-context-new-utf16]" (func (param i32 i32) (result i32)))
448;;(import "$root" "[error-context-new-latin1+utf16]" (func (param i32 i32) (result i32)))
449;;(import "$root" "[error-context-debug-message-utf8]" (func (param i32 i32)))
450;;(import "$root" "[error-context-debug-message-utf16]" (func (param i32 i32)))
451;;(import "$root" "[error-context-debug-message-latin1+utf16]" (func (param i32 i32)))
452;;(import "$root" "[error-context-drop]" (func (param i32)))
453"#,
454 );
455}