1use wit_parser::abi::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, name, sig) = func.task_return_import(resolve, interface, mangling.mangling());
154 wat.push_str(&format!("(import {module:?} {name:?} (func"));
155 push_tys(wat, "param", &sig.params);
156 push_tys(wat, "result", &sig.results);
157 wat.push_str("))\n");
158
159 push_imported_future_and_stream_intrinsics(wat, resolve, "[export]", interface, func);
160}
161
162fn push_imported_future_and_stream_intrinsics(
163 wat: &mut String,
164 resolve: &Resolve,
165 module_prefix: &str,
166 interface: Option<&WorldKey>,
167 func: &Function,
168) {
169 let module = match interface {
170 Some(key) => format!("{module_prefix}{}", resolve.name_world_key(key)),
171 None => format!("{module_prefix}$root"),
172 };
173 let name = &func.name;
174
175 for (i, id) in func
176 .find_futures_and_streams(resolve)
177 .into_iter()
178 .enumerate()
179 {
180 match &resolve.types[id].kind {
181 TypeDefKind::Future(_) => {
182 wat.push_str(&format!(
183 r#"
184(import {module:?} "[future-new-{i}]{name}" (func (result i64)))
185(import {module:?} "[future-read-{i}]{name}" (func (param i32 i32) (result i32)))
186(import {module:?} "[future-write-{i}]{name}" (func (param i32 i32) (result i32)))
187(import {module:?} "[future-cancel-read-{i}]{name}" (func (param i32) (result i32)))
188(import {module:?} "[future-cancel-write-{i}]{name}" (func (param i32) (result i32)))
189(import {module:?} "[future-drop-readable-{i}]{name}" (func (param i32)))
190(import {module:?} "[future-drop-writable-{i}]{name}" (func (param i32)))
191(import {module:?} "[async-lower][future-read-{i}]{name}" (func (param i32 i32) (result i32)))
192(import {module:?} "[async-lower][future-write-{i}]{name}" (func (param i32 i32) (result i32)))
193
194;; deferred behind ๐
195;;(import {module:?} "[async-lower][future-cancel-read-{i}]{name}" (func (param i32) (result i32)))
196;;(import {module:?} "[async-lower][future-cancel-write-{i}]{name}" (func (param i32) (result i32)))
197"#
198 ));
199 }
200 TypeDefKind::Stream(_) => {
201 wat.push_str(&format!(
202 r#"
203(import {module:?} "[stream-new-{i}]{name}" (func (result i64)))
204(import {module:?} "[stream-read-{i}]{name}" (func (param i32 i32 i32) (result i32)))
205(import {module:?} "[stream-write-{i}]{name}" (func (param i32 i32 i32) (result i32)))
206(import {module:?} "[stream-cancel-read-{i}]{name}" (func (param i32) (result i32)))
207(import {module:?} "[stream-cancel-write-{i}]{name}" (func (param i32) (result i32)))
208(import {module:?} "[stream-drop-readable-{i}]{name}" (func (param i32)))
209(import {module:?} "[stream-drop-writable-{i}]{name}" (func (param i32)))
210(import {module:?} "[async-lower][stream-read-{i}]{name}" (func (param i32 i32 i32) (result i32)))
211(import {module:?} "[async-lower][stream-write-{i}]{name}" (func (param i32 i32 i32) (result i32)))
212
213;; deferred behind ๐
214;;(import {module:?} "[async-lower][stream-cancel-read-{i}]{name}" (func (param i32) (result i32)))
215;;(import {module:?} "[async-lower][stream-cancel-write-{i}]{name}" (func (param i32) (result i32)))
216"#
217 ));
218 }
219 _ => unreachable!(),
220 }
221 }
222}
223
224fn push_exported_type_intrinsics(
225 wat: &mut String,
226 resolve: &Resolve,
227 interface: Option<&WorldKey>,
228 resource: TypeId,
229 mangling: ManglingAndAbi,
230) {
231 let ty = &resolve.types[resource];
232 match ty.kind {
233 TypeDefKind::Resource => {
234 let intrinsics = [
235 (ResourceIntrinsic::ExportedDrop, "(func (param i32))"),
236 (
237 ResourceIntrinsic::ExportedNew,
238 "(func (param i32) (result i32))",
239 ),
240 (
241 ResourceIntrinsic::ExportedRep,
242 "(func (param i32) (result i32))",
243 ),
244 ];
245 for (intrinsic, sig) in intrinsics {
246 let (module, name) = resolve.wasm_import_name(
247 mangling.sync(),
248 WasmImport::ResourceIntrinsic {
249 interface,
250 resource,
251 intrinsic,
252 },
253 );
254 wat.push_str(&format!("(import {module:?} {name:?} {sig})\n"));
255 }
256 }
257
258 _ => {}
261 }
262}
263
264fn push_exported_resource_functions(
265 wat: &mut String,
266 resolve: &Resolve,
267 interface: &WorldKey,
268 resource: TypeId,
269 mangling: ManglingAndAbi,
270) {
271 let ty = &resolve.types[resource];
272 match ty.kind {
273 TypeDefKind::Resource => {}
274 _ => return,
275 }
276 let name = resolve.wasm_export_name(
279 mangling,
280 WasmExport::ResourceDtor {
281 interface,
282 resource,
283 },
284 );
285 wat.push_str(&format!("(func (export {name:?}) (param i32))"));
286}
287
288fn push_func_export(
289 wat: &mut String,
290 resolve: &Resolve,
291 interface: Option<&WorldKey>,
292 func: &Function,
293 mangling: ManglingAndAbi,
294) {
295 let sig = resolve.wasm_signature(mangling.export_variant(), func);
296 let name = resolve.wasm_export_name(
297 mangling,
298 WasmExport::Func {
299 interface,
300 func,
301 kind: WasmExportKind::Normal,
302 },
303 );
304 wat.push_str(&format!("(func (export \"{name}\")"));
305 push_tys(wat, "param", &sig.params);
306 push_tys(wat, "result", &sig.results);
307 wat.push_str(" unreachable)\n");
308
309 match mangling {
310 ManglingAndAbi::Standard32 | ManglingAndAbi::Legacy(LiftLowerAbi::Sync) => {
311 let name = resolve.wasm_export_name(
312 mangling,
313 WasmExport::Func {
314 interface,
315 func,
316 kind: WasmExportKind::PostReturn,
317 },
318 );
319 wat.push_str(&format!("(func (export \"{name}\")"));
320 push_tys(wat, "param", &sig.results);
321 wat.push_str(")\n");
322 }
323 ManglingAndAbi::Legacy(LiftLowerAbi::AsyncCallback) => {
324 let name = resolve.wasm_export_name(
325 mangling,
326 WasmExport::Func {
327 interface,
328 func,
329 kind: WasmExportKind::Callback,
330 },
331 );
332 wat.push_str(&format!(
333 "(func (export \"{name}\") (param i32 i32 i32) (result i32) unreachable)\n"
334 ));
335 }
336 ManglingAndAbi::Legacy(LiftLowerAbi::AsyncStackful) => {}
337 }
338}
339
340fn push_tys(dst: &mut String, desc: &str, params: &[WasmType]) {
341 if params.is_empty() {
342 return;
343 }
344 dst.push_str(" (");
345 dst.push_str(desc);
346 for ty in params {
347 dst.push(' ');
348 match ty {
349 WasmType::I32 => dst.push_str("i32"),
350 WasmType::I64 => dst.push_str("i64"),
351 WasmType::F32 => dst.push_str("f32"),
352 WasmType::F64 => dst.push_str("f64"),
353 WasmType::Pointer => dst.push_str("i32"),
354 WasmType::PointerOrI64 => dst.push_str("i64"),
355 WasmType::Length => dst.push_str("i32"),
356 }
357 }
358 dst.push(')');
359}
360
361fn push_root_async_intrinsics(dst: &mut String) {
362 dst.push_str(
363 r#"
364(import "[export]$root" "[task-cancel]" (func))
365(import "$root" "[backpressure-set]" (func (param i32)))
366(import "$root" "[backpressure-inc]" (func))
367(import "$root" "[backpressure-dec]" (func))
368(import "$root" "[waitable-set-new]" (func (result i32)))
369(import "$root" "[waitable-set-wait]" (func (param i32 i32) (result i32)))
370(import "$root" "[waitable-set-poll]" (func (param i32 i32) (result i32)))
371(import "$root" "[waitable-set-drop]" (func (param i32)))
372(import "$root" "[waitable-join]" (func (param i32 i32)))
373(import "$root" "[thread-yield]" (func (result i32)))
374(import "$root" "[subtask-drop]" (func (param i32)))
375(import "$root" "[subtask-cancel]" (func (param i32) (result i32)))
376(import "$root" "[context-get-0]" (func (result i32)))
377(import "$root" "[context-set-0]" (func (param i32)))
378
379;; deferred behind ๐งต upstream
380;;(import "$root" "[cancellable][waitable-set-wait]" (func (param i32 i32) (result i32)))
381;;(import "$root" "[cancellable][waitable-set-poll]" (func (param i32 i32) (result i32)))
382;;(import "$root" "[cancellable][thread-yield]" (func (result i32)))
383;;(import "$root" "[context-get-1]" (func (result i32)))
384;;(import "$root" "[context-set-1]" (func (param i32)))
385
386;; deferred behind ๐ upstream
387;;(import "$root" "[error-context-new-utf8]" (func (param i32 i32) (result i32)))
388;;(import "$root" "[error-context-new-utf16]" (func (param i32 i32) (result i32)))
389;;(import "$root" "[error-context-new-latin1+utf16]" (func (param i32 i32) (result i32)))
390;;(import "$root" "[error-context-debug-message-utf8]" (func (param i32 i32)))
391;;(import "$root" "[error-context-debug-message-utf16]" (func (param i32 i32)))
392;;(import "$root" "[error-context-debug-message-latin1+utf16]" (func (param i32 i32)))
393;;(import "$root" "[error-context-drop]" (func (param i32)))
394"#,
395 );
396}