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