1use std::borrow::Cow;
2use std::collections::{HashMap, HashSet};
3use std::mem;
4use wasm_encoder::{
5 CodeSection, ConstExpr, CustomSection, DataSection, ElementSection, Elements, Encode,
6 EntityType, ExportKind, ExportSection, Function, FunctionSection, GlobalType, ImportSection,
7 MemoryType, Module, NameMap, NameSection, RefType, TableType, TypeSection, ValType,
8};
9use wit_parser::abi::{WasmSignature, WasmType};
10use wit_parser::{
11 Handle, LiftLowerAbi, LiveTypes, ManglingAndAbi, Resolve, ResourceIntrinsic, SizeAlign, Type,
12 TypeDefKind, TypeId, TypeOwner, WasmExport, WasmExportKind, WasmImport, WorldId, WorldItem,
13 WorldKey,
14};
15
16mod async_;
17mod bindgen;
18pub mod metadata;
19pub use crate::async_::AsyncFilterSet;
20pub use crate::metadata::Metadata;
21
22pub const C_HEADER: &'static str = include_str!("../wit_dylib.h");
23
24#[derive(Default, Clone, Debug)]
25#[cfg_attr(feature = "clap", derive(clap::Parser))]
26pub struct DylibOpts {
27 #[cfg_attr(feature = "clap", clap(long, value_name = "name"))]
30 pub interpreter: Option<String>,
31
32 #[cfg_attr(feature = "clap", clap(flatten))]
33 pub async_: AsyncFilterSet,
34
35 #[cfg_attr(
40 feature = "clap",
41 clap(long, value_name = "loc", default_value = "global")
42 )]
43 pub stack_pointer: StackPointer,
44}
45
46#[derive(Default, Clone, Debug)]
47#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
48pub enum StackPointer {
49 #[default]
50 Global,
51 TaskContext,
52}
53
54pub fn create(
55 resolve: &Resolve,
56 world_id: WorldId,
57 opts: Option<&mut DylibOpts>,
58) -> anyhow::Result<Vec<u8>> {
59 Ok(create_with_metadata(resolve, world_id, opts)?.0)
60}
61
62pub fn create_with_metadata(
63 resolve: &Resolve,
64 world_id: WorldId,
65 mut opts: Option<&mut DylibOpts>,
66) -> anyhow::Result<(Vec<u8>, Metadata)> {
67 let mut adapter = Adapter::default();
68 if let Some(opts) = &mut opts {
69 adapter.opts = opts.clone();
70 }
71 let result = adapter.encode(resolve, world_id)?;
72 if let Some(opts) = &mut opts {
73 **opts = adapter.opts;
74 }
75 Ok((result, adapter.metadata))
76}
77
78#[derive(Default)]
79struct Adapter {
80 types: TypeSection,
81 wasm_type_map: HashMap<(Vec<ValType>, Vec<ValType>), u32>,
82 imports: ImportSection,
83 imports_done: bool,
84 global_index: u32,
85 table_base: Option<u32>,
86 memory_base: Option<u32>,
87 stack_pointer: Option<ImportedStackPointer>,
88 func_index: u32,
89 functions: FunctionSection,
90 exports: ExportSection,
91 code: CodeSection,
92 global_names: NameMap,
93 function_names: NameMap,
94 metadata: Metadata,
95 type_map: HashMap<TypeId, metadata::Type>,
96 resource_map: HashMap<TypeId, usize>,
97 export_resource_map: HashMap<TypeId, usize>,
98 intrinsics: Option<bindgen::WitInterpreterIntrinsics>,
99 sizes: SizeAlign,
100 opts: DylibOpts,
101
102 elem_segment: Vec<u32>,
108}
109
110#[derive(Copy, Clone)]
111enum ImportedStackPointer {
112 Global(u32),
113 TaskContext { get: u32, set: u32 },
114}
115
116#[derive(Default)]
117struct Imports<'a> {
118 wit_imports: Vec<WitImport<'a>>,
119 wit_exports: Vec<WitExport<'a>>,
120}
121
122struct WitImport<'a> {
123 interface: Option<&'a WorldKey>,
124 func: &'a wit_parser::Function,
125 import_index: u32,
126}
127
128struct WitExport<'a> {
129 interface: Option<&'a WorldKey>,
130 func: &'a wit_parser::Function,
131 async_task_return_index: Option<u32>,
132}
133
134struct PayloadData {
137 new_elem_index: u32,
139 read_elem_index: u32,
141 write_elem_index: u32,
143 cancel_read_elem_index: u32,
145 cancel_write_elem_index: u32,
147 drop_readable_elem_index: u32,
149 drop_writable_elem_index: u32,
151 ordinal: usize,
155 function: String,
158}
159
160impl Adapter {
161 pub fn encode(&mut self, resolve: &Resolve, world_id: WorldId) -> anyhow::Result<Vec<u8>> {
162 self.sizes.fill(resolve)?;
163
164 let imports = self.add_imports(resolve, world_id);
169
170 let mut payload_data = HashMap::new();
171 self.collect_payload_data(resolve, world_id, &mut payload_data);
172
173 self.imports_done = true;
174
175 let cabi_realloc = self.intrinsics().cabi_realloc;
179 self.exports
180 .export("cabi_realloc", ExportKind::Func, cabi_realloc);
181
182 self.bindgen_world(resolve, world_id, &imports, &payload_data);
185
186 let (metadata_offset, metadata) = self.encode_metadata();
192 let mut ctor = Function::new([]);
193 ctor.instructions().i32_const(metadata_offset as i32);
194 ctor.instructions().global_get(self.memory_base());
195 ctor.instructions().i32_add();
196 ctor.instructions().call(self.intrinsics().initialize);
197 ctor.instructions().end();
198 let ty = self.define_ty([], []);
199 self.define_func("__wasm_call_ctors", ty, ctor, true);
200
201 Ok(self.finish(&metadata))
202 }
203
204 fn mangling(
205 &mut self,
206 resolve: &Resolve,
207 interface: Option<&WorldKey>,
208 func: &wit_parser::Function,
209 is_import: bool,
210 ) -> ManglingAndAbi {
211 let abi = if self
212 .opts
213 .async_
214 .is_async(resolve, interface, func, is_import)
215 {
216 LiftLowerAbi::AsyncCallback
217 } else {
218 LiftLowerAbi::Sync
219 };
220 ManglingAndAbi::Legacy(abi)
221 }
222
223 fn resource_intrinsic_mangling(&mut self) -> ManglingAndAbi {
224 ManglingAndAbi::Legacy(LiftLowerAbi::Sync)
225 }
226
227 fn collect_payload_data_for_func(
231 &mut self,
232 resolve: &Resolve,
233 interface: Option<&WorldKey>,
234 func: &wit_parser::Function,
235 prefix: &str,
236 data: &mut HashMap<TypeId, PayloadData>,
237 ) {
238 let mut make = |arg_count, kind, ordinal| {
239 let module = format!(
240 "{prefix}{}",
241 interface
242 .map(|name| resolve.name_world_key(name))
243 .unwrap_or_else(|| "$root".into())
244 );
245 let function = func.name.clone();
246
247 let import = |me: &mut Self, prefix, name, params, results| {
248 let ty = me.define_ty(params, results);
249 let import = me.import_func(
250 &module,
251 &format!("{prefix}[{kind}-{name}-{ordinal}]{function}"),
252 ty,
253 );
254 me.push_elem(import)
255 };
256
257 let new_elem_index = import(self, "", "new", vec![], vec![ValType::I64]);
258 let read_elem_index = import(
259 self,
260 "[async-lower]",
261 "read",
262 vec![ValType::I32; arg_count],
263 vec![ValType::I32],
264 );
265 let write_elem_index = import(
266 self,
267 "[async-lower]",
268 "write",
269 vec![ValType::I32; arg_count],
270 vec![ValType::I32],
271 );
272 let cancel_read_elem_index = import(
273 self,
274 "",
275 "cancel-read",
276 vec![ValType::I32],
277 vec![ValType::I32],
278 );
279 let cancel_write_elem_index = import(
280 self,
281 "",
282 "cancel-write",
283 vec![ValType::I32],
284 vec![ValType::I32],
285 );
286 let drop_readable_elem_index =
287 import(self, "", "drop-readable", vec![ValType::I32], vec![]);
288 let drop_writable_elem_index =
289 import(self, "", "drop-writable", vec![ValType::I32], vec![]);
290
291 PayloadData {
292 new_elem_index,
293 read_elem_index,
294 write_elem_index,
295 cancel_read_elem_index,
296 cancel_write_elem_index,
297 drop_readable_elem_index,
298 drop_writable_elem_index,
299 ordinal,
300 function,
301 }
302 };
303
304 for (ordinal, ty) in func
305 .find_futures_and_streams(resolve)
306 .into_iter()
307 .enumerate()
308 {
309 match &resolve.types[ty].kind {
310 TypeDefKind::Future(_) => {
311 data.entry(ty).or_insert_with(|| make(2, "future", ordinal))
312 }
313 TypeDefKind::Stream(_) => {
314 data.entry(ty).or_insert_with(|| make(3, "stream", ordinal))
315 }
316 _ => unreachable!(),
317 };
318 }
319 }
320
321 fn collect_payload_data(
322 &mut self,
323 resolve: &Resolve,
324 world_id: WorldId,
325 data: &mut HashMap<TypeId, PayloadData>,
326 ) {
327 let world = &resolve.worlds[world_id];
328
329 for (key, import) in world.imports.iter() {
330 match import {
331 WorldItem::Interface { id, .. } => {
332 for (_, func) in resolve.interfaces[*id].functions.iter() {
333 self.collect_payload_data_for_func(resolve, Some(key), func, "", data);
334 }
335 }
336 WorldItem::Type { .. } => {}
337 WorldItem::Function(func) => {
338 self.collect_payload_data_for_func(resolve, None, func, "", data);
339 }
340 }
341 }
342
343 for (key, export) in world.exports.iter() {
344 match export {
345 WorldItem::Interface { id, .. } => {
346 for (_, func) in resolve.interfaces[*id].functions.iter() {
347 self.collect_payload_data_for_func(
348 resolve,
349 Some(key),
350 func,
351 "[export]",
352 data,
353 );
354 }
355 }
356 WorldItem::Type { .. } => unreachable!(),
357 WorldItem::Function(func) => {
358 self.collect_payload_data_for_func(resolve, None, func, "[export]", data);
359 }
360 }
361 }
362 }
363
364 fn add_imports<'a>(&mut self, resolve: &'a Resolve, world_id: WorldId) -> Imports<'a> {
365 let mut ret = Imports::default();
366 let world = &resolve.worlds[world_id];
367
368 self.intrinsics = Some(bindgen::WitInterpreterIntrinsics::new(self));
371
372 for (interface, import) in world.imports.iter() {
377 match import {
378 WorldItem::Interface { id, .. } => {
379 for (_, func) in resolve.interfaces[*id].functions.iter() {
380 self.add_imported_func(resolve, Some(interface), func, &mut ret);
381 }
382 for (_, ty) in resolve.interfaces[*id].types.iter() {
383 self.add_imported_type_intrinsics(resolve, Some(interface), *ty);
384 }
385 }
386 WorldItem::Type { id, .. } => {
387 self.add_imported_type_intrinsics(resolve, None, *id);
388 }
389 WorldItem::Function(func) => {
390 self.add_imported_func(resolve, None, func, &mut ret);
391 }
392 }
393 }
394
395 for (name, export) in world.exports.iter() {
398 match export {
399 WorldItem::Function(func) => {
400 self.add_imported_func_intrinsics_for_export(resolve, None, func, &mut ret);
401 }
402 WorldItem::Interface { id: export, .. } => {
403 for (_, ty) in resolve.interfaces[*export].types.iter() {
404 self.add_imported_type_intrinsics_for_export(resolve, Some(name), *ty);
405 }
406 for (_, func) in resolve.interfaces[*export].functions.iter() {
407 self.add_imported_func_intrinsics_for_export(
408 resolve,
409 Some(name),
410 func,
411 &mut ret,
412 );
413 }
414 }
415 WorldItem::Type { .. } => unreachable!(),
416 }
417 }
418
419 let const_i32_global = GlobalType {
420 val_type: ValType::I32,
421 mutable: false,
422 shared: false,
423 };
424 let mut_i32_global = GlobalType {
425 val_type: ValType::I32,
426 mutable: true,
427 shared: false,
428 };
429
430 self.table_base = Some(self.import_global("env", "__table_base", const_i32_global));
431 self.memory_base = Some(self.import_global("env", "__memory_base", const_i32_global));
432 self.stack_pointer = Some(match self.opts.stack_pointer {
433 StackPointer::Global => ImportedStackPointer::Global(self.import_global(
434 "env",
435 "__stack_pointer",
436 mut_i32_global,
437 )),
438 StackPointer::TaskContext => {
439 let get_ty = self.define_ty([], [ValType::I32]);
440 let set_ty = self.define_ty([ValType::I32], []);
441 ImportedStackPointer::TaskContext {
442 get: self.import_func("$root", "[context-get-0]", get_ty),
443 set: self.import_func("$root", "[context-set-0]", set_ty),
444 }
445 }
446 });
447
448 self.imports.import(
449 "env",
450 "memory",
451 EntityType::Memory(MemoryType {
452 minimum: 0,
453 maximum: None,
454 memory64: false,
455 shared: false,
456 page_size_log2: None,
457 }),
458 );
459
460 self.imports.import(
461 "env",
462 "__indirect_function_table",
463 EntityType::Table(TableType {
464 element_type: RefType::FUNCREF,
465 minimum: 0,
466 maximum: None,
467 table64: false,
468 shared: false,
469 }),
470 );
471 ret
472 }
473
474 fn add_imported_func<'a>(
475 &mut self,
476 resolve: &'a Resolve,
477 interface: Option<&'a WorldKey>,
478 func: &'a wit_parser::Function,
479 imports: &mut Imports<'a>,
480 ) {
481 let mangling = self.mangling(resolve, interface, func, true);
482 let (module, name) =
483 resolve.wasm_import_name(mangling, WasmImport::Func { interface, func });
484 let sig = resolve.wasm_signature(mangling.import_variant(), func);
485 let ty = self.define_wasm_sig(sig);
486 let import_index = self.import_func(&module, &name, ty);
487 imports.wit_imports.push(WitImport {
488 func,
489 interface,
490 import_index,
491 });
492 }
493
494 fn add_imported_type_intrinsics<'a>(
495 &mut self,
496 resolve: &Resolve,
497 interface: Option<&'a WorldKey>,
498 id: TypeId,
499 ) {
500 let mangling = self.resource_intrinsic_mangling();
501 let ty = &resolve.types[id];
502 match ty.kind {
503 TypeDefKind::Resource => {
504 let (module, name) = resolve.wasm_import_name(
505 mangling,
506 WasmImport::ResourceIntrinsic {
507 interface,
508 resource: id,
509 intrinsic: ResourceIntrinsic::ImportedDrop,
510 },
511 );
512 let core_ty = self.define_ty([ValType::I32], []);
513 let drop = self.import_func(&module, &name, core_ty);
514 let drop_elem_index = self.push_elem(drop);
515 let resource_index = self.metadata.resources.len();
516 self.metadata.resources.push(metadata::Resource {
517 id,
518 interface: interface.map(|i| resolve.name_world_key(i)),
519 name: ty.name.clone().unwrap(),
520 drop_elem_index,
521 new_elem_index: None,
522 rep_elem_index: None,
523 });
524 let prev = self.resource_map.insert(id, resource_index);
525 assert!(prev.is_none());
526 }
527
528 _ => {}
531 }
532 }
533
534 fn add_imported_type_intrinsics_for_export<'a>(
535 &mut self,
536 resolve: &Resolve,
537 interface: Option<&'a WorldKey>,
538 id: TypeId,
539 ) {
540 let ty = &resolve.types[id];
541 let mangling = self.resource_intrinsic_mangling();
542 match ty.kind {
543 TypeDefKind::Resource => {
544 let drop_ty = self.define_ty([ValType::I32], []);
545 let new_rep_ty = self.define_ty([ValType::I32], [ValType::I32]);
546
547 let mut import = |ty, intrinsic| {
548 let (module, name) = resolve.wasm_import_name(
549 mangling,
550 WasmImport::ResourceIntrinsic {
551 interface,
552 resource: id,
553 intrinsic,
554 },
555 );
556 self.import_func(&module, &name, ty)
557 };
558
559 let drop = import(drop_ty, ResourceIntrinsic::ExportedDrop);
560 let new = import(new_rep_ty, ResourceIntrinsic::ExportedNew);
561 let rep = import(new_rep_ty, ResourceIntrinsic::ExportedRep);
562
563 let drop_elem_index = self.push_elem(drop);
564 let new_elem_index = Some(self.push_elem(new));
565 let rep_elem_index = Some(self.push_elem(rep));
566
567 let resource_index = self.metadata.resources.len();
568 self.metadata.resources.push(metadata::Resource {
569 id,
570 interface: interface.map(|i| resolve.name_world_key(i)),
571 name: ty.name.clone().unwrap(),
572 drop_elem_index,
573 new_elem_index,
574 rep_elem_index,
575 });
576
577 let prev = self.export_resource_map.insert(id, resource_index);
583 assert!(prev.is_none());
584 }
585
586 _ => {}
589 }
590 }
591
592 fn add_imported_func_intrinsics_for_export<'a>(
595 &mut self,
596 resolve: &Resolve,
597 interface: Option<&'a WorldKey>,
598 func: &'a wit_parser::Function,
599 ret: &mut Imports<'a>,
600 ) {
601 let mangling = self.mangling(resolve, interface, func, false);
602 let async_task_return_index = if mangling.is_async() {
603 let (module, name, sig) =
604 func.task_return_import(resolve, interface, mangling.mangling());
605 let ty = self.define_wasm_sig(sig);
606 Some(self.import_func(&module, &name, ty))
607 } else {
608 None
609 };
610 ret.wit_exports.push(WitExport {
611 interface,
612 func,
613 async_task_return_index,
614 });
615 }
616
617 fn bindgen_world(
618 &mut self,
619 resolve: &Resolve,
620 world_id: WorldId,
621 imports: &Imports<'_>,
622 payload_data: &HashMap<TypeId, PayloadData>,
623 ) {
624 let world = &resolve.worlds[world_id];
625
626 let mut import_types = LiveTypes::default();
630 let mut interface_names = HashMap::new();
631 for (interface, import) in world.imports.iter() {
632 import_types.add_world_item(resolve, import);
633 if let WorldItem::Interface { id, .. } = import {
634 interface_names.insert(*id, interface);
635 }
636 }
637 for (_, export) in world.exports.iter() {
638 match export {
639 WorldItem::Function(func) => import_types.add_func(resolve, func),
640 WorldItem::Interface { .. } => {}
641 WorldItem::Type { .. } => unreachable!(),
642 }
643 }
644 for ty in import_types.iter() {
645 let key = match resolve.types[ty].owner {
646 TypeOwner::Interface(id) => Some(interface_names[&id]),
647 _ => None,
648 };
649 self.register_type(resolve, key, ty, payload_data);
650 }
651
652 for import in imports.wit_imports.iter() {
656 self.bindgen_world_func_import(resolve, import);
657 }
658 for export in imports.wit_exports.iter().filter(|i| i.interface.is_none()) {
659 self.bindgen_world_func_export(resolve, export);
660 }
661
662 let to_keep = imported_types_used_by_exported_interfaces(resolve, world_id);
669 self.type_map.retain(|id, _| to_keep.contains(*id));
670 let mut exported_types = LiveTypes::default();
671 let mut export_names = HashMap::new();
672 for (interface, import) in world.exports.iter() {
673 if let WorldItem::Interface { id, .. } = import {
674 exported_types.add_world_item(resolve, import);
675 export_names.insert(*id, interface);
676 }
677 }
678 for (ty, index) in mem::take(&mut self.export_resource_map) {
679 self.resource_map.insert(ty, index);
680 }
681 for ty in exported_types.iter() {
682 if self.type_map.contains_key(&ty) {
683 continue;
684 }
685 let key = match resolve.types[ty].owner {
686 TypeOwner::Interface(id) => Some(export_names[&id]),
687 _ => None,
688 };
689 self.register_type(resolve, key, ty, payload_data);
690
691 if let Some(index) = self.resource_map.get(&ty) {
692 self.bindgen_world_export_resource_dtor(resolve, key.unwrap(), ty, *index);
693 }
694 }
695
696 for export in imports.wit_exports.iter().filter(|i| i.interface.is_some()) {
699 self.bindgen_world_func_export(resolve, export);
700 }
701 }
702
703 fn register_type(
709 &mut self,
710 resolve: &Resolve,
711 key: Option<&WorldKey>,
712 id: TypeId,
713 payload_data: &HashMap<TypeId, PayloadData>,
714 ) {
715 let ty = &resolve.types[id];
716 let interface = key.map(|key| resolve.name_world_key(key));
717 let name = ty.name.clone();
718 let result = match &ty.kind {
719 TypeDefKind::Record(r) => {
720 let index = self.metadata.records.len();
721 let fields = r
722 .fields
723 .iter()
724 .map(|field| (field.name.clone(), self.lookup_ty(&field.ty)))
725 .collect();
726 self.metadata.records.push(metadata::Record {
727 id,
728 interface,
729 name: name.unwrap(),
730 fields,
731 });
732 metadata::Type::Record(index)
733 }
734 TypeDefKind::Flags(t) => {
735 let index = self.metadata.flags.len();
736 let names = t.flags.iter().map(|f| f.name.clone()).collect();
737 self.metadata.flags.push(metadata::Flags {
738 id,
739 interface,
740 name: name.unwrap(),
741 names,
742 });
743 metadata::Type::Flags(index)
744 }
745 TypeDefKind::Tuple(t) => {
746 let index = self.metadata.tuples.len();
747 let types = t.types.iter().map(|t| self.lookup_ty(t)).collect();
748 self.metadata.tuples.push(metadata::Tuple {
749 id,
750 interface,
751 name,
752 types,
753 });
754 metadata::Type::Tuple(index)
755 }
756 TypeDefKind::Variant(t) => {
757 let index = self.metadata.variants.len();
758 let cases = t
759 .cases
760 .iter()
761 .map(|c| (c.name.clone(), c.ty.map(|t| self.lookup_ty(&t))))
762 .collect();
763 self.metadata.variants.push(metadata::Variant {
764 id,
765 interface,
766 name: name.unwrap(),
767 cases,
768 });
769 metadata::Type::Variant(index)
770 }
771 TypeDefKind::Enum(t) => {
772 let index = self.metadata.enums.len();
773 let names = t.cases.iter().map(|f| f.name.clone()).collect();
774 self.metadata.enums.push(metadata::Enum {
775 id,
776 interface,
777 name: name.unwrap(),
778 names,
779 });
780 metadata::Type::Enum(index)
781 }
782 TypeDefKind::Option(t) => {
783 let index = self.metadata.options.len();
784 self.metadata.options.push(metadata::WitOption {
785 id,
786 interface,
787 name,
788 ty: self.lookup_ty(t),
789 });
790 metadata::Type::Option(index)
791 }
792 TypeDefKind::Result(t) => {
793 let index = self.metadata.results.len();
794 self.metadata.results.push(metadata::WitResult {
795 id,
796 interface,
797 name,
798 ok: t.ok.map(|t| self.lookup_ty(&t)),
799 err: t.err.map(|t| self.lookup_ty(&t)),
800 });
801 metadata::Type::Result(index)
802 }
803 TypeDefKind::List(t) => {
804 let index = self.metadata.lists.len();
805 self.metadata.lists.push(metadata::List {
806 id,
807 interface,
808 name,
809 ty: self.lookup_ty(t),
810 });
811 metadata::Type::List(index)
812 }
813 TypeDefKind::FixedLengthList(t, len) => {
814 let index = self.metadata.fixed_length_lists.len();
815 self.metadata
816 .fixed_length_lists
817 .push(metadata::FixedLengthList {
818 id,
819 interface,
820 name,
821 len: *len,
822 ty: self.lookup_ty(t),
823 });
824 metadata::Type::FixedLengthList(index)
825 }
826 TypeDefKind::Future(t) => {
827 let index = self.metadata.futures.len();
828
829 let Some(&PayloadData {
830 new_elem_index,
831 read_elem_index,
832 write_elem_index,
833 cancel_read_elem_index,
834 cancel_write_elem_index,
835 drop_readable_elem_index,
836 drop_writable_elem_index,
837 ordinal,
838 ref function,
839 }) = payload_data.get(&id)
840 else {
841 panic!("encountered future type not used in any function")
843 };
844
845 let lift_elem_index = t.map(|t| {
849 let ty = self.define_ty([ValType::I32; 2], []);
850 let func = bindgen::lift_payload(self, resolve, t);
851 let func = self.define_func(
852 &format!("[future-lift-{ordinal}]{function}"),
853 ty,
854 func,
855 false,
856 );
857 self.push_elem(func)
858 });
859
860 let lower_elem_index = t.map(|t| {
861 let ty = self.define_ty([ValType::I32; 2], []);
862 let func = bindgen::lower_payload(self, resolve, t);
863 let func = self.define_func(
864 &format!("[future-lower-{ordinal}]{function}"),
865 ty,
866 func,
867 false,
868 );
869 self.push_elem(func)
870 });
871
872 self.metadata.futures.push(metadata::Future {
873 id,
874 interface,
875 name,
876 ty: t.map(|t| self.lookup_ty(&t)),
877 new_elem_index,
878 read_elem_index,
879 write_elem_index,
880 cancel_read_elem_index,
881 cancel_write_elem_index,
882 drop_readable_elem_index,
883 drop_writable_elem_index,
884 lift_elem_index,
885 lower_elem_index,
886 abi_payload_size: t.map(|t| self.sizes.size(&t).size_wasm32()).unwrap_or(0),
887 abi_payload_align: t.map(|t| self.sizes.align(&t).align_wasm32()).unwrap_or(1),
888 });
889 metadata::Type::Future(index)
890 }
891 TypeDefKind::Stream(t) => {
892 let index = self.metadata.streams.len();
893
894 let Some(&PayloadData {
895 new_elem_index,
896 read_elem_index,
897 write_elem_index,
898 cancel_read_elem_index,
899 cancel_write_elem_index,
900 drop_readable_elem_index,
901 drop_writable_elem_index,
902 ordinal,
903 ref function,
904 }) = payload_data.get(&id)
905 else {
906 panic!("encountered stream type not used in any function")
908 };
909
910 let lift_elem_index = t.map(|t| {
921 let ty = self.define_ty([ValType::I32; 2], []);
922 let func = bindgen::lift_payload(self, resolve, t);
923 let func = self.define_func(
924 &format!("[stream-lift-{ordinal}]{function}"),
925 ty,
926 func,
927 false,
928 );
929 self.push_elem(func)
930 });
931
932 let lower_elem_index = t.map(|t| {
933 let ty = self.define_ty([ValType::I32; 2], []);
934 let func = bindgen::lower_payload(self, resolve, t);
935 let func = self.define_func(
936 &format!("[stream-lower-{ordinal}]{function}"),
937 ty,
938 func,
939 false,
940 );
941 self.push_elem(func)
942 });
943
944 self.metadata.streams.push(metadata::Stream {
945 id,
946 interface,
947 name,
948 ty: t.map(|t| self.lookup_ty(&t)),
949 new_elem_index,
950 read_elem_index,
951 write_elem_index,
952 cancel_read_elem_index,
953 cancel_write_elem_index,
954 drop_readable_elem_index,
955 drop_writable_elem_index,
956 lift_elem_index,
957 lower_elem_index,
958 abi_payload_size: t.map(|t| self.sizes.size(&t).size_wasm32()).unwrap_or(0),
959 abi_payload_align: t.map(|t| self.sizes.align(&t).align_wasm32()).unwrap_or(1),
960 });
961 metadata::Type::Stream(index)
962 }
963 TypeDefKind::Type(t) => {
964 let index = self.metadata.aliases.len();
965 self.metadata.aliases.push(metadata::Alias {
966 id,
967 interface,
968 name: name.unwrap(),
969 ty: self.lookup_ty(t),
970 });
971 metadata::Type::Alias(index)
972 }
973 TypeDefKind::Resource => metadata::Type::Own(self.resource_map[&id]),
974
975 TypeDefKind::Handle(Handle::Own(t)) => {
978 metadata::Type::Own(self.resource_map[&dealias(resolve, *t)])
979 }
980 TypeDefKind::Handle(Handle::Borrow(t)) => {
981 metadata::Type::Borrow(self.resource_map[&dealias(resolve, *t)])
982 }
983 TypeDefKind::Map(k, v) => {
984 let index = self.metadata.maps.len();
985 self.metadata.maps.push(metadata::Map {
986 id,
987 interface,
988 name,
989 key_type: self.lookup_ty(k),
990 value_type: self.lookup_ty(v),
991 });
992 metadata::Type::Map(index)
993 }
994 TypeDefKind::Unknown => unreachable!(),
995 };
996 self.type_map.insert(id, result);
997 }
998
999 fn lookup_ty(&self, ty: &Type) -> metadata::Type {
1000 match ty {
1001 Type::U8 => metadata::Type::U8,
1002 Type::U16 => metadata::Type::U16,
1003 Type::U32 => metadata::Type::U32,
1004 Type::U64 => metadata::Type::U64,
1005 Type::S8 => metadata::Type::S8,
1006 Type::S16 => metadata::Type::S16,
1007 Type::S32 => metadata::Type::S32,
1008 Type::S64 => metadata::Type::S64,
1009 Type::F32 => metadata::Type::F32,
1010 Type::F64 => metadata::Type::F64,
1011 Type::Bool => metadata::Type::Bool,
1012 Type::Char => metadata::Type::Char,
1013 Type::String => metadata::Type::String,
1014 Type::ErrorContext => metadata::Type::ErrorContext,
1015 Type::Id(id) => self.type_map[id],
1019 }
1020 }
1021
1022 fn bindgen_world_func_import(&mut self, resolve: &Resolve, import: &WitImport<'_>) {
1023 let func = import.func;
1024 let mangling = self.mangling(resolve, import.interface, func, true);
1025 let body = bindgen::import(
1026 self,
1027 resolve,
1028 func,
1029 mangling.import_variant(),
1030 import.import_index,
1031 );
1032
1033 let ty = if mangling.is_async() {
1034 self.define_ty([ValType::I32; 2], [ValType::I32])
1036 } else {
1037 self.define_ty([ValType::I32], [])
1039 };
1040
1041 let idx = self.define_func(&format!("adapter {}", func.name), ty, body, false);
1042 let elem_index = self.push_elem(idx);
1043
1044 let sync_import_elem_index;
1045 let async_import_elem_index;
1046 let async_import_lift_results_elem_index;
1047
1048 if mangling.is_async() {
1049 sync_import_elem_index = None;
1050 async_import_elem_index = Some(elem_index);
1051 let body =
1052 bindgen::lift_async_import_results(self, resolve, func, mangling.import_variant());
1053 let ty = self.define_ty([ValType::I32; 2], []);
1054 let idx = self.define_func(&format!("lift results {}", func.name), ty, body, false);
1055 async_import_lift_results_elem_index = Some(self.push_elem(idx));
1056 } else {
1057 sync_import_elem_index = Some(elem_index);
1058 async_import_elem_index = None;
1059 async_import_lift_results_elem_index = None;
1060 }
1061
1062 self.metadata.import_funcs.push(metadata::ImportFunc {
1063 interface: import.interface.map(|k| resolve.name_world_key(k)),
1064 name: func.name.clone(),
1065 sync_import_elem_index,
1066 async_import_elem_index,
1067 async_import_lift_results_elem_index,
1068 args: func.params.iter().map(|p| self.lookup_ty(&p.ty)).collect(),
1069 result: func.result.map(|t| self.lookup_ty(&t)),
1070 async_abi_area: self.async_import_abi_area(resolve, mangling, func),
1071 })
1072 }
1073
1074 fn async_import_abi_area(
1077 &self,
1078 resolve: &Resolve,
1079 mangling: ManglingAndAbi,
1080 func: &wit_parser::Function,
1081 ) -> Option<(usize, usize)> {
1082 if !mangling.is_async() {
1083 return None;
1084 }
1085
1086 let info = self
1087 .sizes
1088 .record(bindgen::async_import_abi_area_types(resolve, func));
1089 Some((info.size.size_wasm32(), info.align.align_wasm32()))
1090 }
1091
1092 fn bindgen_world_func_export(&mut self, resolve: &Resolve, export: &WitExport<'_>) {
1093 let func = export.func;
1094 let mangling = self.mangling(resolve, export.interface, func, false);
1095 let sig = resolve.wasm_signature(mangling.export_variant(), func);
1096 let ty = self.define_wasm_sig(sig);
1097 let name = resolve.wasm_export_name(
1098 mangling,
1099 WasmExport::Func {
1100 interface: export.interface,
1101 func,
1102 kind: WasmExportKind::Normal,
1103 },
1104 );
1105
1106 let metadata_func_index = self.metadata.export_funcs.len();
1107 let body = bindgen::export(
1108 self,
1109 resolve,
1110 func,
1111 mangling.export_variant(),
1112 metadata_func_index,
1113 );
1114 self.define_func(&name, ty, body, true);
1115
1116 let mut async_export_task_return_elem_index = None;
1117 match mangling {
1118 ManglingAndAbi::Standard32 | ManglingAndAbi::Legacy(LiftLowerAbi::Sync) => {
1122 let post_return_name = resolve.wasm_export_name(
1123 mangling,
1124 WasmExport::Func {
1125 interface: export.interface,
1126 func,
1127 kind: WasmExportKind::PostReturn,
1128 },
1129 );
1130 let post_return = bindgen::post_return(
1131 self,
1132 resolve,
1133 func,
1134 mangling.export_variant(),
1135 metadata_func_index,
1136 );
1137 let mut sig = resolve.wasm_signature(mangling.export_variant(), func);
1138 sig.params = mem::take(&mut sig.results);
1139 let post_return_ty = self.define_wasm_sig(sig);
1140 self.define_func(&post_return_name, post_return_ty, post_return, true);
1141 }
1142
1143 ManglingAndAbi::Legacy(LiftLowerAbi::AsyncCallback) => {
1150 let callback_name = resolve.wasm_export_name(
1151 mangling,
1152 WasmExport::Func {
1153 interface: export.interface,
1154 func,
1155 kind: WasmExportKind::Callback,
1156 },
1157 );
1158 let mut callback = Function::new([]);
1163 let mut ins = callback.instructions();
1164 ins.local_get(0);
1165 ins.local_get(1);
1166 ins.local_get(2);
1167 ins.i32_const(metadata_func_index.try_into().unwrap());
1168 let export_async_callback = self.intrinsics().export_async_callback;
1169 ins.call(export_async_callback);
1170 ins.end();
1171 let callback_ty = self.define_ty([ValType::I32; 3], [ValType::I32]);
1172 self.define_func(&callback_name, callback_ty, callback, true);
1173
1174 let task_return = bindgen::task_return(
1175 self,
1176 resolve,
1177 func,
1178 mangling.export_variant(),
1179 export.async_task_return_index.unwrap(),
1180 );
1181 let task_return_ty = self.define_ty([ValType::I32], []);
1182 let task_return = self.define_func(
1183 &format!("task.return {}", func.name),
1184 task_return_ty,
1185 task_return,
1186 false,
1187 );
1188 async_export_task_return_elem_index = Some(self.push_elem(task_return));
1189 }
1190
1191 ManglingAndAbi::Legacy(LiftLowerAbi::AsyncStackful) => unimplemented!(),
1192 }
1193
1194 self.metadata.export_funcs.push(metadata::ExportFunc {
1195 interface: export.interface.map(|k| resolve.name_world_key(k)),
1196 name: func.name.clone(),
1197 async_export_task_return_elem_index,
1198 args: func.params.iter().map(|p| self.lookup_ty(&p.ty)).collect(),
1199 result: func.result.map(|t| self.lookup_ty(&t)),
1200 })
1201 }
1202
1203 fn bindgen_world_export_resource_dtor(
1204 &mut self,
1205 resolve: &Resolve,
1206 interface: &WorldKey,
1207 resource: TypeId,
1208 index: usize,
1209 ) {
1210 let mangling = self.resource_intrinsic_mangling();
1211 let name = resolve.wasm_export_name(
1212 mangling,
1213 WasmExport::ResourceDtor {
1214 interface,
1215 resource,
1216 },
1217 );
1218 let dtor = self.intrinsics().resource_dtor;
1219 let mut func = Function::new([]);
1220 let mut ins = func.instructions();
1221 ins.i32_const(index.try_into().unwrap());
1222 ins.local_get(0);
1223 ins.call(dtor);
1224 ins.end();
1225 let ty = self.define_ty([ValType::I32], []);
1226 self.define_func(&name, ty, func, true);
1227 }
1228
1229 fn encode_metadata(&mut self) -> (u32, Vec<u8>) {
1230 let (metadata_offset, metadata, apply_relocs) =
1231 self.metadata.encode(self.table_base(), self.memory_base());
1232 if let Some(apply_relocs) = apply_relocs {
1233 let ty = self.define_ty([], []);
1234 self.define_func("__wasm_apply_data_relocs", ty, apply_relocs, true);
1235 }
1236 (metadata_offset, metadata)
1237 }
1238
1239 fn table_base(&self) -> u32 {
1240 self.table_base.unwrap()
1241 }
1242
1243 fn intrinsics(&self) -> &bindgen::WitInterpreterIntrinsics {
1244 self.intrinsics.as_ref().unwrap()
1245 }
1246
1247 fn memory_base(&self) -> u32 {
1248 self.memory_base.unwrap()
1249 }
1250
1251 fn push_elem(&mut self, elem: u32) -> u32 {
1252 let ret = self.elem_segment.len();
1253 self.elem_segment.push(elem);
1254 u32::try_from(ret).unwrap()
1255 }
1256
1257 fn finish(&mut self, metadata: &[u8]) -> Vec<u8> {
1258 let mut elements = ElementSection::new();
1260 if !self.elem_segment.is_empty() {
1261 elements.active(
1262 Some(0),
1263 &ConstExpr::global_get(self.table_base()),
1264 Elements::Functions(Cow::Borrowed(&self.elem_segment)),
1265 );
1266 }
1267
1268 let mut data = DataSection::new();
1270 data.active(
1271 0,
1272 &ConstExpr::global_get(self.memory_base()),
1273 metadata.iter().copied(),
1274 );
1275
1276 let mut names = NameSection::new();
1277 names.functions(&self.function_names);
1278 names.globals(&self.global_names);
1279
1280 let dylink0 = {
1281 struct MemInfo {
1282 memory_size: u32,
1283 memory_alignment: u32,
1284 table_size: u32,
1285 table_alignment: u32,
1286 }
1287
1288 let mem_info = MemInfo {
1289 memory_size: metadata.len().try_into().unwrap(),
1290 memory_alignment: 2,
1291 table_size: self.elem_segment.len().try_into().unwrap(),
1292 table_alignment: 0,
1293 };
1294
1295 let mut mem_info_subsection = Vec::new();
1296 mem_info.memory_size.encode(&mut mem_info_subsection);
1297 mem_info.memory_alignment.encode(&mut mem_info_subsection);
1298 mem_info.table_size.encode(&mut mem_info_subsection);
1299 mem_info.table_alignment.encode(&mut mem_info_subsection);
1300
1301 let mut needed_subsection = Vec::new();
1302 if let Some(name) = &self.opts.interpreter {
1303 [name.as_str()].encode(&mut needed_subsection);
1304 }
1305
1306 const WASM_DYLINK_MEM_INFO: u8 = 1;
1307 const WASM_DYLINK_NEEDED: u8 = 2;
1308
1309 let mut dylink0 = Vec::new();
1310 dylink0.push(WASM_DYLINK_MEM_INFO);
1311 mem_info_subsection.encode(&mut dylink0);
1312 if self.opts.interpreter.is_some() {
1313 dylink0.push(WASM_DYLINK_NEEDED);
1314 needed_subsection.encode(&mut dylink0);
1315 }
1316 dylink0
1317 };
1318
1319 let mut result = Module::new();
1320 result.section(&CustomSection {
1321 name: Cow::Borrowed("dylink.0"),
1322 data: Cow::Borrowed(&dylink0),
1323 });
1324 result.section(&self.types);
1325 result.section(&self.imports);
1326 result.section(&self.functions);
1327 result.section(&self.exports);
1328 if !elements.is_empty() {
1329 result.section(&elements);
1330 }
1331 result.section(&self.code);
1332 result.section(&data);
1333 result.section(&names);
1334
1335 result.finish()
1336 }
1337
1338 fn define_wasm_sig(&mut self, sig: WasmSignature) -> u32 {
1339 let ret = self.define_ty(
1340 sig.params
1341 .iter()
1342 .map(|t| self.map_wasm_type(*t))
1343 .collect::<Vec<_>>(),
1344 sig.results
1345 .iter()
1346 .map(|t| self.map_wasm_type(*t))
1347 .collect::<Vec<_>>(),
1348 );
1349 return ret;
1350 }
1351
1352 fn map_wasm_type(&self, a: WasmType) -> ValType {
1353 match a {
1354 WasmType::I32 => ValType::I32,
1355 WasmType::I64 => ValType::I64,
1356 WasmType::F32 => ValType::F32,
1357 WasmType::F64 => ValType::F64,
1358 WasmType::PointerOrI64 => ValType::I64,
1359 WasmType::Length | WasmType::Pointer => ValType::I32,
1360 }
1361 }
1362
1363 fn import_global(&mut self, module: &str, name: &str, ty: GlobalType) -> u32 {
1364 assert!(!self.imports_done);
1365 self.imports.import(module, name, ty);
1366 let ret = self.global_index;
1367 self.global_index += 1;
1368 self.global_names.append(ret, name);
1369 ret
1370 }
1371
1372 fn import_func(&mut self, module: &str, name: &str, ty: u32) -> u32 {
1373 assert!(!self.imports_done);
1374 self.imports.import(module, name, EntityType::Function(ty));
1375 let ret = self.func_index;
1376 self.func_index += 1;
1377 self.function_names.append(ret, name);
1378 ret
1379 }
1380
1381 fn define_func(&mut self, name: &str, ty: u32, body: Function, export: bool) -> u32 {
1382 assert!(self.imports_done);
1383 let ret = self.func_index;
1384 self.func_index += 1;
1385 self.functions.function(ty);
1386 self.code.function(&body);
1387 self.function_names.append(ret, name);
1388 if export {
1389 self.exports.export(name, ExportKind::Func, ret);
1390 }
1391 ret
1392 }
1393
1394 fn define_ty<P, R>(&mut self, params: P, results: R) -> u32
1395 where
1396 P: IntoIterator<Item = ValType> + Clone,
1397 P::IntoIter: ExactSizeIterator,
1398 R: IntoIterator<Item = ValType> + Clone,
1399 R::IntoIter: ExactSizeIterator,
1400 {
1401 let param_vec = params.clone().into_iter().collect::<Vec<_>>();
1402 let result_vec = results.clone().into_iter().collect::<Vec<_>>();
1403 *self
1404 .wasm_type_map
1405 .entry((param_vec, result_vec))
1406 .or_insert_with(|| {
1407 let ret = self.types.len();
1408 self.types.ty().function(params, results);
1409 ret
1410 })
1411 }
1412}
1413
1414fn imported_types_used_by_exported_interfaces(resolve: &Resolve, world: WorldId) -> LiveTypes {
1415 let mut live_export_types = LiveTypes::default();
1418 let mut exported_interfaces = HashSet::new();
1419 for (_, export) in resolve.worlds[world].exports.iter() {
1420 match export {
1421 WorldItem::Function(_) => {}
1422 WorldItem::Interface { id, .. } => {
1423 exported_interfaces.insert(*id);
1424 live_export_types.add_interface(resolve, *id)
1425 }
1426 WorldItem::Type { .. } => unreachable!(),
1427 }
1428 }
1429
1430 let mut live_import_types = LiveTypes::default();
1434 for ty in live_export_types.iter() {
1435 if let TypeOwner::Interface(id) = resolve.types[ty].owner {
1436 if !exported_interfaces.contains(&id) {
1437 live_import_types.add_interface(resolve, id);
1438 }
1439 }
1440 }
1441
1442 live_import_types
1443}
1444
1445fn dealias(resolve: &Resolve, mut id: TypeId) -> TypeId {
1446 loop {
1447 match resolve.types[id].kind {
1448 TypeDefKind::Type(Type::Id(other)) => id = other,
1449 _ => break id,
1450 }
1451 }
1452}
1453
1454#[cfg(test)]
1455mod tests {
1456 use wasmparser::{Operator, Parser, Payload};
1457 use wit_parser::Resolve;
1458
1459 #[derive(Copy, Clone)]
1460 enum Which {
1461 S8,
1462 S16,
1463 }
1464
1465 #[test]
1466 fn s8_uses_signed_load() {
1467 assert!(find_signed_load(Which::S8));
1468 }
1469
1470 #[test]
1471 fn s16_uses_signed_load() {
1472 assert!(find_signed_load(Which::S16));
1473 }
1474
1475 fn find_signed_load(which: Which) -> bool {
1476 let mut resolve = Resolve::default();
1477 let ty = match which {
1478 Which::S8 => "s8",
1479 Which::S16 => "s16",
1480 };
1481 let package = resolve
1482 .push_str(
1483 "wit",
1484 &format!(
1485 "package test:test;
1486world w {{
1487 export foo: func(v: list<{ty}>);
1488}}
1489"
1490 ),
1491 )
1492 .unwrap();
1493 let world = resolve.select_world(&[package], None).unwrap();
1494 let adapter = super::create(&resolve, world, None).unwrap();
1495 for payload in Parser::new(0).parse_all(&adapter) {
1496 match payload.unwrap() {
1497 Payload::CodeSectionEntry(body) => {
1498 for operator in body.get_operators_reader().unwrap() {
1499 match (operator.unwrap(), which) {
1500 (Operator::I32Load16S { .. }, Which::S16)
1501 | (Operator::I32Load8S { .. }, Which::S8) => return true,
1502 _ => {}
1503 }
1504 }
1505 }
1506 _ => {}
1507 }
1508 }
1509 false
1510 }
1511}