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 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 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 }
135 }
136
137 _ => {}
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 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 _ => {}
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 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}