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 i64)))
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)))
201(import {module:?} "[future-close-writable-{i}]{name}" (func (param 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
205;; deferred behind 🚝
206;;(import {module:?} "[async-lower][future-cancel-read-{i}]{name}" (func (param i32) (result i32)))
207;;(import {module:?} "[async-lower][future-cancel-write-{i}]{name}" (func (param i32) (result i32)))
208"#
209 ));
210 }
211 TypeDefKind::Stream(_) => {
212 wat.push_str(&format!(
213 r#"
214(import {module:?} "[stream-new-{i}]{name}" (func (result i64)))
215(import {module:?} "[stream-read-{i}]{name}" (func (param i32 i32 i32) (result i32)))
216(import {module:?} "[stream-write-{i}]{name}" (func (param i32 i32 i32) (result i32)))
217(import {module:?} "[stream-cancel-read-{i}]{name}" (func (param i32) (result i32)))
218(import {module:?} "[stream-cancel-write-{i}]{name}" (func (param i32) (result i32)))
219(import {module:?} "[stream-close-readable-{i}]{name}" (func (param i32)))
220(import {module:?} "[stream-close-writable-{i}]{name}" (func (param i32)))
221(import {module:?} "[async-lower][stream-read-{i}]{name}" (func (param i32 i32 i32) (result i32)))
222(import {module:?} "[async-lower][stream-write-{i}]{name}" (func (param i32 i32 i32) (result i32)))
223
224;; deferred behind 🚝
225;;(import {module:?} "[async-lower][stream-cancel-read-{i}]{name}" (func (param i32) (result i32)))
226;;(import {module:?} "[async-lower][stream-cancel-write-{i}]{name}" (func (param i32) (result i32)))
227"#
228 ));
229 }
230 _ => unreachable!(),
231 }
232 }
233}
234
235fn push_exported_type_intrinsics(
236 wat: &mut String,
237 resolve: &Resolve,
238 interface: Option<&WorldKey>,
239 resource: TypeId,
240 mangling: ManglingAndAbi,
241) {
242 let ty = &resolve.types[resource];
243 match ty.kind {
244 TypeDefKind::Resource => {
245 let intrinsics = [
246 (ResourceIntrinsic::ExportedDrop, "(func (param i32))"),
247 (
248 ResourceIntrinsic::ExportedNew,
249 "(func (param i32) (result i32))",
250 ),
251 (
252 ResourceIntrinsic::ExportedRep,
253 "(func (param i32) (result i32))",
254 ),
255 ];
256 for (intrinsic, sig) in intrinsics {
257 let (module, name) = resolve.wasm_import_name(
258 mangling.sync(),
259 WasmImport::ResourceIntrinsic {
260 interface,
261 resource,
262 intrinsic,
263 },
264 );
265 wat.push_str(&format!("(import {module:?} {name:?} {sig})\n"));
266 }
267 }
268
269 _ => {}
272 }
273}
274
275fn push_exported_resource_functions(
276 wat: &mut String,
277 resolve: &Resolve,
278 interface: &WorldKey,
279 resource: TypeId,
280 mangling: ManglingAndAbi,
281) {
282 let ty = &resolve.types[resource];
283 match ty.kind {
284 TypeDefKind::Resource => {}
285 _ => return,
286 }
287 let name = resolve.wasm_export_name(
290 mangling,
291 WasmExport::ResourceDtor {
292 interface,
293 resource,
294 },
295 );
296 wat.push_str(&format!("(func (export {name:?}) (param i32))"));
297}
298
299fn push_func_export(
300 wat: &mut String,
301 resolve: &Resolve,
302 interface: Option<&WorldKey>,
303 func: &Function,
304 mangling: ManglingAndAbi,
305) {
306 let sig = resolve.wasm_signature(mangling.export_variant(), func);
307 let name = resolve.wasm_export_name(
308 mangling,
309 WasmExport::Func {
310 interface,
311 func,
312 kind: WasmExportKind::Normal,
313 },
314 );
315 wat.push_str(&format!("(func (export \"{name}\")"));
316 push_tys(wat, "param", &sig.params);
317 push_tys(wat, "result", &sig.results);
318 wat.push_str(" unreachable)\n");
319
320 match mangling {
321 ManglingAndAbi::Standard32 | ManglingAndAbi::Legacy(LiftLowerAbi::Sync) => {
322 let name = resolve.wasm_export_name(
323 mangling,
324 WasmExport::Func {
325 interface,
326 func,
327 kind: WasmExportKind::PostReturn,
328 },
329 );
330 wat.push_str(&format!("(func (export \"{name}\")"));
331 push_tys(wat, "param", &sig.results);
332 wat.push_str(")\n");
333 }
334 ManglingAndAbi::Legacy(LiftLowerAbi::AsyncCallback) => {
335 let name = resolve.wasm_export_name(
336 mangling,
337 WasmExport::Func {
338 interface,
339 func,
340 kind: WasmExportKind::Callback,
341 },
342 );
343 wat.push_str(&format!(
344 "(func (export \"{name}\") (param i32 i32 i32) (result i32) unreachable)\n"
345 ));
346 }
347 ManglingAndAbi::Legacy(LiftLowerAbi::AsyncStackful) => {}
348 }
349}
350
351fn push_tys(dst: &mut String, desc: &str, params: &[WasmType]) {
352 if params.is_empty() {
353 return;
354 }
355 dst.push_str(" (");
356 dst.push_str(desc);
357 for ty in params {
358 dst.push(' ');
359 match ty {
360 WasmType::I32 => dst.push_str("i32"),
361 WasmType::I64 => dst.push_str("i64"),
362 WasmType::F32 => dst.push_str("f32"),
363 WasmType::F64 => dst.push_str("f64"),
364 WasmType::Pointer => dst.push_str("i32"),
365 WasmType::PointerOrI64 => dst.push_str("i64"),
366 WasmType::Length => dst.push_str("i32"),
367 }
368 }
369 dst.push(')');
370}
371
372fn push_root_async_intrinsics(dst: &mut String) {
373 dst.push_str(
374 r#"
375(import "$root" "[backpressure-set]" (func (param i32)))
376(import "$root" "[waitable-set-new]" (func (result i32)))
377(import "$root" "[waitable-set-wait]" (func (param i32 i32) (result i32)))
378(import "$root" "[waitable-set-poll]" (func (param i32 i32) (result i32)))
379(import "$root" "[waitable-set-drop]" (func (param i32)))
380(import "$root" "[waitable-join]" (func (param i32 i32)))
381(import "$root" "[yield]" (func))
382(import "$root" "[subtask-drop]" (func (param i32)))
383(import "$root" "[error-context-new-utf8]" (func (param i32 i32) (result i32)))
384(import "$root" "[error-context-new-utf16]" (func (param i32 i32) (result i32)))
385(import "$root" "[error-context-new-latin1+utf16]" (func (param i32 i32) (result i32)))
386(import "$root" "[error-context-debug-message-utf8]" (func (param i32 i32)))
387(import "$root" "[error-context-debug-message-utf16]" (func (param i32 i32)))
388(import "$root" "[error-context-debug-message-latin1+utf16]" (func (param i32 i32)))
389(import "$root" "[error-context-drop]" (func (param i32)))
390(import "$root" "[context-get-0]" (func (result i32)))
391(import "$root" "[context-get-1]" (func (result i32)))
392(import "$root" "[context-set-0]" (func (param i32)))
393(import "$root" "[context-set-1]" (func (param i32)))
394
395;; deferred behind 🚝 or 🚟 upstream
396;;(import "$root" "[async-lower][waitable-set-wait]" (func (param i32 i32) (result i32)))
397;;(import "$root" "[async-lower][waitable-set-poll]" (func (param i32 i32) (result i32)))
398;;(import "$root" "[async-lower][yield]" (func))
399"#,
400 );
401}