1use crate::{
2 core::Trap,
3 func::{FuncEntity, HostFuncEntity, HostFuncTrampolineEntity},
4 module::{ImportName, ImportType},
5 AsContext,
6 AsContextMut,
7 Caller,
8 Engine,
9 Error,
10 Extern,
11 ExternType,
12 Func,
13 FuncType,
14 GlobalType,
15 InstancePre,
16 IntoFunc,
17 MemoryType,
18 Module,
19 TableType,
20 Value,
21};
22use alloc::{
23 collections::{btree_map::Entry, BTreeMap},
24 sync::Arc,
25 vec::Vec,
26};
27use core::{
28 fmt,
29 fmt::{Debug, Display},
30 num::NonZeroUsize,
31 ops::Deref,
32};
33
34#[derive(Debug)]
36pub enum LinkerError {
37 DuplicateDefinition {
39 import_name: ImportName,
41 },
42 MissingDefinition {
44 name: ImportName,
46 ty: ExternType,
48 },
49 InvalidTypeDefinition {
51 name: ImportName,
53 expected: ExternType,
55 found: ExternType,
57 },
58 FuncTypeMismatch {
60 name: ImportName,
62 expected: FuncType,
64 found: FuncType,
66 },
67 InvalidTableSubtype {
69 name: ImportName,
71 ty: TableType,
73 other: TableType,
75 },
76 InvalidMemorySubtype {
78 name: ImportName,
80 ty: MemoryType,
82 other: MemoryType,
84 },
85 GlobalTypeMismatch {
87 name: ImportName,
89 expected: GlobalType,
91 found: GlobalType,
93 },
94}
95
96impl LinkerError {
97 fn missing_definition(import: &ImportType) -> Self {
99 Self::MissingDefinition {
100 name: import.import_name().clone(),
101 ty: import.ty().clone(),
102 }
103 }
104
105 fn invalid_type_definition(import: &ImportType, found: &ExternType) -> Self {
107 Self::InvalidTypeDefinition {
108 name: import.import_name().clone(),
109 expected: import.ty().clone(),
110 found: found.clone(),
111 }
112 }
113
114 fn func_type_mismatch(name: &ImportName, expected: &FuncType, found: &FuncType) -> Self {
116 Self::FuncTypeMismatch {
117 name: name.clone(),
118 expected: expected.clone(),
119 found: found.clone(),
120 }
121 }
122
123 fn table_type_mismatch(name: &ImportName, ty: &TableType, other: &TableType) -> Self {
125 Self::InvalidTableSubtype {
126 name: name.clone(),
127 ty: *ty,
128 other: *other,
129 }
130 }
131
132 fn invalid_memory_subtype(name: &ImportName, ty: &MemoryType, other: &MemoryType) -> Self {
134 Self::InvalidMemorySubtype {
135 name: name.clone(),
136 ty: *ty,
137 other: *other,
138 }
139 }
140
141 fn global_type_mismatch(name: &ImportName, expected: &GlobalType, found: &GlobalType) -> Self {
143 Self::GlobalTypeMismatch {
144 name: name.clone(),
145 expected: *expected,
146 found: *found,
147 }
148 }
149}
150
151#[cfg(feature = "std")]
152impl std::error::Error for LinkerError {}
153
154impl Display for LinkerError {
155 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
156 match self {
157 Self::DuplicateDefinition { import_name } => {
158 write!(
159 f,
160 "encountered duplicate definition with name `{import_name}`",
161 )
162 }
163 Self::MissingDefinition { name, ty } => {
164 write!(
165 f,
166 "cannot find definition for import {name} with type {ty:?}",
167 )
168 }
169 Self::InvalidTypeDefinition {
170 name,
171 expected,
172 found,
173 } => {
174 write!(f, "found definition for import {name} with type {expected:?} but found type {found:?}")
175 }
176 Self::FuncTypeMismatch {
177 name,
178 expected,
179 found,
180 } => {
181 write!(
182 f,
183 "function type mismatch for import {name}: \
184 expected {expected:?} but found {found:?}",
185 )
186 }
187 Self::InvalidTableSubtype { name, ty, other } => {
188 write!(
189 f,
190 "import {name}: table type {ty:?} is not a subtype of {other:?}"
191 )
192 }
193 Self::InvalidMemorySubtype { name, ty, other } => {
194 write!(
195 f,
196 "import {name}: memory type {ty:?} is not a subtype of {other:?}"
197 )
198 }
199 Self::GlobalTypeMismatch {
200 name,
201 expected,
202 found,
203 } => {
204 write!(
205 f,
206 "global variable type mismatch for import {name}: \
207 expected {expected:?} but found {found:?}",
208 )
209 }
210 }
211 }
212}
213
214#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
228#[repr(transparent)]
229pub struct Symbol(NonZeroUsize);
230
231impl Symbol {
232 pub fn from_usize(value: usize) -> Self {
238 NonZeroUsize::new(value.wrapping_add(1))
239 .map(Symbol)
240 .expect("encountered invalid symbol value")
241 }
242
243 pub fn into_usize(self) -> usize {
245 self.0.get().wrapping_sub(1)
246 }
247}
248
249#[derive(Debug, Default, Clone)]
253pub struct StringInterner {
254 string2idx: BTreeMap<Arc<str>, Symbol>,
255 strings: Vec<Arc<str>>,
256}
257
258impl StringInterner {
259 fn next_symbol(&self) -> Symbol {
261 Symbol::from_usize(self.strings.len())
262 }
263
264 pub fn get_or_intern(&mut self, string: &str) -> Symbol {
266 match self.string2idx.get(string) {
267 Some(symbol) => *symbol,
268 None => {
269 let symbol = self.next_symbol();
270 let rc_string: Arc<str> = Arc::from(string);
271 self.string2idx.insert(rc_string.clone(), symbol);
272 self.strings.push(rc_string);
273 symbol
274 }
275 }
276 }
277
278 pub fn get(&self, string: &str) -> Option<Symbol> {
280 self.string2idx.get(string).copied()
281 }
282
283 pub fn resolve(&self, symbol: Symbol) -> Option<&str> {
285 self.strings.get(symbol.into_usize()).map(Deref::deref)
286 }
287}
288
289#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
291struct ImportKey {
292 module: Symbol,
294 name: Symbol,
296}
297
298enum Definition<T> {
300 Extern(Extern),
302 HostFunc(HostFuncTrampolineEntity<T>),
304}
305
306impl<T> Clone for Definition<T> {
307 fn clone(&self) -> Self {
308 match self {
309 Self::Extern(definition) => Self::Extern(*definition),
310 Self::HostFunc(host_func) => Self::HostFunc(host_func.clone()),
311 }
312 }
313}
314
315impl<T> Definition<T> {
316 fn as_extern(&self) -> Option<&Extern> {
320 match self {
321 Definition::Extern(item) => Some(item),
322 Definition::HostFunc(_) => None,
323 }
324 }
325
326 pub fn ty(&self, ctx: impl AsContext) -> ExternType {
328 match self {
329 Definition::Extern(item) => item.ty(ctx),
330 Definition::HostFunc(host_func) => {
331 let func_type = ctx
332 .as_context()
333 .store
334 .engine()
335 .resolve_func_type(host_func.ty_dedup(), FuncType::clone);
336 ExternType::Func(func_type)
337 }
338 }
339 }
340
341 pub fn as_func(&self, mut ctx: impl AsContextMut<UserState = T>) -> Option<Func> {
352 match self {
353 Definition::Extern(Extern::Func(func)) => Some(*func),
354 Definition::HostFunc(host_func) => {
355 let trampoline = ctx
356 .as_context_mut()
357 .store
358 .alloc_trampoline(host_func.trampoline().clone());
359 let ty_dedup = host_func.ty_dedup();
360 let entity = HostFuncEntity::new(*ty_dedup, trampoline);
361 let func = ctx
362 .as_context_mut()
363 .store
364 .inner
365 .alloc_func(FuncEntity::Host(entity));
366 Some(func)
367 }
368 _ => None,
369 }
370 }
371}
372
373pub struct DebugDefinitions<'a, T> {
375 engine: &'a Engine,
377 definitions: &'a BTreeMap<ImportKey, Definition<T>>,
379}
380
381impl<'a, T> DebugDefinitions<'a, T> {
382 fn new(linker: &'a Linker<T>) -> Self {
384 Self {
385 engine: linker.engine(),
386 definitions: &linker.definitions,
387 }
388 }
389}
390
391impl<'a, T> Debug for DebugDefinitions<'a, T> {
392 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
393 let mut map = f.debug_map();
394 for (name, definition) in self.definitions {
395 match definition {
396 Definition::Extern(definition) => {
397 map.entry(name, definition);
398 }
399 Definition::HostFunc(definition) => {
400 map.entry(name, &DebugHostFuncEntity::new(self.engine, definition));
401 }
402 }
403 }
404 map.finish()
405 }
406}
407
408pub struct DebugHostFuncEntity<'a, T> {
410 engine: &'a Engine,
412 host_func: &'a HostFuncTrampolineEntity<T>,
414}
415
416impl<'a, T> DebugHostFuncEntity<'a, T> {
417 fn new(engine: &'a Engine, host_func: &'a HostFuncTrampolineEntity<T>) -> Self {
419 Self { engine, host_func }
420 }
421}
422
423impl<'a, T> Debug for DebugHostFuncEntity<'a, T> {
424 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
425 self.engine
426 .resolve_func_type(self.host_func.ty_dedup(), |func_type| {
427 f.debug_struct("HostFunc").field("ty", func_type).finish()
428 })
429 }
430}
431
432pub struct Linker<T> {
434 engine: Engine,
441 strings: StringInterner,
443 definitions: BTreeMap<ImportKey, Definition<T>>,
445}
446
447impl<T> Debug for Linker<T> {
448 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
449 f.debug_struct("Linker")
450 .field("strings", &self.strings)
451 .field("definitions", &DebugDefinitions::new(self))
452 .finish()
453 }
454}
455
456impl<T> Clone for Linker<T> {
457 fn clone(&self) -> Linker<T> {
458 Self {
459 engine: self.engine.clone(),
460 strings: self.strings.clone(),
461 definitions: self.definitions.clone(),
462 }
463 }
464}
465
466impl<T> Default for Linker<T> {
467 fn default() -> Self {
468 Self::new(&Engine::default())
469 }
470}
471
472impl<T> Linker<T> {
473 pub fn new(engine: &Engine) -> Self {
475 Self {
476 engine: engine.clone(),
477 strings: StringInterner::default(),
478 definitions: BTreeMap::default(),
479 }
480 }
481
482 pub fn engine(&self) -> &Engine {
484 &self.engine
485 }
486
487 pub fn define(
493 &mut self,
494 module: &str,
495 name: &str,
496 item: impl Into<Extern>,
497 ) -> Result<&mut Self, LinkerError> {
498 let key = self.import_key(module, name);
499 self.insert(key, Definition::Extern(item.into()))?;
500 Ok(self)
501 }
502
503 pub fn func_new(
511 &mut self,
512 module: &str,
513 name: &str,
514 ty: FuncType,
515 func: impl Fn(Caller<'_, T>, &[Value], &mut [Value]) -> Result<(), Trap> + Send + Sync + 'static,
516 ) -> Result<&mut Self, LinkerError> {
517 let func = HostFuncTrampolineEntity::new(&self.engine, ty, func);
518 let key = self.import_key(module, name);
519 self.insert(key, Definition::HostFunc(func))?;
520 Ok(self)
521 }
522
523 pub fn func_wrap<Params, Args>(
545 &mut self,
546 module: &str,
547 name: &str,
548 func: impl IntoFunc<T, Params, Args>,
549 ) -> Result<&mut Self, LinkerError> {
550 let func = HostFuncTrampolineEntity::wrap(&self.engine, func);
551 let key = self.import_key(module, name);
552 self.insert(key, Definition::HostFunc(func))?;
553 Ok(self)
554 }
555
556 fn import_key(&mut self, module: &str, name: &str) -> ImportKey {
558 ImportKey {
559 module: self.strings.get_or_intern(module),
560 name: self.strings.get_or_intern(name),
561 }
562 }
563
564 fn resolve_import_key(&self, key: ImportKey) -> Option<(&str, &str)> {
566 let module_name = self.strings.resolve(key.module)?;
567 let item_name = self.strings.resolve(key.name)?;
568 Some((module_name, item_name))
569 }
570
571 fn insert(&mut self, key: ImportKey, item: Definition<T>) -> Result<(), LinkerError> {
577 match self.definitions.entry(key) {
578 Entry::Occupied(_) => {
579 let (module_name, field_name) = self
580 .resolve_import_key(key)
581 .unwrap_or_else(|| panic!("encountered missing import names for key {key:?}"));
582 let import_name = ImportName::new(module_name, field_name);
583 return Err(LinkerError::DuplicateDefinition { import_name });
584 }
585 Entry::Vacant(v) => {
586 v.insert(item);
587 }
588 }
589 Ok(())
590 }
591
592 pub fn get(
601 &self,
602 context: impl AsContext<UserState = T>,
603 module: &str,
604 name: &str,
605 ) -> Option<Extern> {
606 match self.get_definition(context, module, name) {
607 Some(Definition::Extern(item)) => Some(*item),
608 _ => None,
609 }
610 }
611
612 fn get_definition(
620 &self,
621 context: impl AsContext<UserState = T>,
622 module: &str,
623 name: &str,
624 ) -> Option<&Definition<T>> {
625 assert!(Engine::same(
626 context.as_context().store.engine(),
627 self.engine()
628 ));
629 let key = ImportKey {
630 module: self.strings.get(module)?,
631 name: self.strings.get(name)?,
632 };
633 self.definitions.get(&key)
634 }
635
636 pub fn instantiate(
647 &self,
648 mut context: impl AsContextMut<UserState = T>,
649 module: &Module,
650 ) -> Result<InstancePre, Error> {
651 assert!(Engine::same(self.engine(), context.as_context().engine()));
652 let externals = module
653 .imports()
654 .map(|import| self.process_import(&mut context, import))
655 .collect::<Result<Vec<Extern>, Error>>()?;
656 module.instantiate(context, externals)
657 }
658
659 fn process_import(
669 &self,
670 mut context: impl AsContextMut<UserState = T>,
671 import: ImportType,
672 ) -> Result<Extern, Error> {
673 assert!(Engine::same(self.engine(), context.as_context().engine()));
674 let import_name = import.import_name();
675 let module_name = import.module();
676 let field_name = import.name();
677 let resolved = self
678 .get_definition(context.as_context(), module_name, field_name)
679 .ok_or_else(|| LinkerError::missing_definition(&import))?;
680 let invalid_type = || LinkerError::invalid_type_definition(&import, &resolved.ty(&context));
681 match import.ty() {
682 ExternType::Func(expected_type) => {
683 let found_type = resolved
684 .ty(&context)
685 .func()
686 .cloned()
687 .ok_or_else(invalid_type)?;
688 if &found_type != expected_type {
689 return Err(LinkerError::func_type_mismatch(
690 import_name,
691 expected_type,
692 &found_type,
693 ))
694 .map_err(Into::into);
695 }
696 let func = resolved
697 .as_func(&mut context)
698 .expect("already asserted that `resolved` is a function");
699 Ok(Extern::Func(func))
700 }
701 ExternType::Table(expected_type) => {
702 let table = resolved
703 .as_extern()
704 .copied()
705 .and_then(Extern::into_table)
706 .ok_or_else(invalid_type)?;
707 let found_type = table.dynamic_ty(context);
708 found_type.is_subtype_or_err(expected_type).map_err(|_| {
709 LinkerError::table_type_mismatch(import_name, expected_type, &found_type)
710 })?;
711 Ok(Extern::Table(table))
712 }
713 ExternType::Memory(expected_type) => {
714 let memory = resolved
715 .as_extern()
716 .copied()
717 .and_then(Extern::into_memory)
718 .ok_or_else(invalid_type)?;
719 let found_type = memory.dynamic_ty(context);
720 found_type.is_subtype_or_err(expected_type).map_err(|_| {
721 LinkerError::invalid_memory_subtype(import_name, expected_type, &found_type)
722 })?;
723 Ok(Extern::Memory(memory))
724 }
725 ExternType::Global(expected_type) => {
726 let global = resolved
727 .as_extern()
728 .copied()
729 .and_then(Extern::into_global)
730 .ok_or_else(invalid_type)?;
731 let found_type = global.ty(context);
732 if &found_type != expected_type {
733 return Err(LinkerError::global_type_mismatch(
734 import_name,
735 expected_type,
736 &found_type,
737 ))
738 .map_err(Into::into);
739 }
740 Ok(Extern::Global(global))
741 }
742 }
743 }
744}
745
746#[cfg(test)]
747mod tests {
748 use wasmi_core::ValueType;
749
750 use super::*;
751 use crate::Store;
752
753 struct HostState {
754 a: i32,
755 b: i64,
756 }
757
758 #[test]
759 fn linker_funcs_work() {
760 let engine = Engine::default();
761 let mut linker = <Linker<HostState>>::new(&engine);
762 linker
763 .func_new(
764 "host",
765 "get_a",
766 FuncType::new([], [ValueType::I32]),
767 |ctx: Caller<HostState>, _params: &[Value], results: &mut [Value]| {
768 results[0] = Value::from(ctx.data().a);
769 Ok(())
770 },
771 )
772 .unwrap();
773 linker
774 .func_new(
775 "host",
776 "set_a",
777 FuncType::new([ValueType::I32], []),
778 |mut ctx: Caller<HostState>, params: &[Value], _results: &mut [Value]| {
779 ctx.data_mut().a = params[0].i32().unwrap();
780 Ok(())
781 },
782 )
783 .unwrap();
784 linker
785 .func_wrap("host", "get_b", |ctx: Caller<HostState>| ctx.data().b)
786 .unwrap();
787 linker
788 .func_wrap("host", "set_b", |mut ctx: Caller<HostState>, value: i64| {
789 ctx.data_mut().b = value
790 })
791 .unwrap();
792 let a_init = 42;
793 let b_init = 77;
794 let mut store = <Store<HostState>>::new(
795 &engine,
796 HostState {
797 a: a_init,
798 b: b_init,
799 },
800 );
801 let wat = r#"
802 (module
803 (import "host" "get_a" (func $host_get_a (result i32)))
804 (import "host" "set_a" (func $host_set_a (param i32)))
805 (import "host" "get_b" (func $host_get_b (result i64)))
806 (import "host" "set_b" (func $host_set_b (param i64)))
807
808 (func (export "wasm_get_a") (result i32)
809 (call $host_get_a)
810 )
811 (func (export "wasm_set_a") (param $param i32)
812 (call $host_set_a (local.get $param))
813 )
814
815 (func (export "wasm_get_b") (result i64)
816 (call $host_get_b)
817 )
818 (func (export "wasm_set_b") (param $param i64)
819 (call $host_set_b (local.get $param))
820 )
821 )
822 "#;
823 let wasm = wat::parse_str(wat).unwrap();
824 let module = Module::new(&engine, &mut &wasm[..]).unwrap();
825 let instance = linker
826 .instantiate(&mut store, &module)
827 .unwrap()
828 .start(&mut store)
829 .unwrap();
830
831 let wasm_get_a = instance
832 .get_typed_func::<(), i32>(&store, "wasm_get_a")
833 .unwrap();
834 let wasm_set_a = instance
835 .get_typed_func::<i32, ()>(&store, "wasm_set_a")
836 .unwrap();
837 let wasm_get_b = instance
838 .get_typed_func::<(), i64>(&store, "wasm_get_b")
839 .unwrap();
840 let wasm_set_b = instance
841 .get_typed_func::<i64, ()>(&store, "wasm_set_b")
842 .unwrap();
843
844 assert_eq!(wasm_get_a.call(&mut store, ()).unwrap(), a_init);
845 wasm_set_a.call(&mut store, 100).unwrap();
846 assert_eq!(wasm_get_a.call(&mut store, ()).unwrap(), 100);
847
848 assert_eq!(wasm_get_b.call(&mut store, ()).unwrap(), b_init);
849 wasm_set_b.call(&mut store, 200).unwrap();
850 assert_eq!(wasm_get_b.call(&mut store, ()).unwrap(), 200);
851 }
852}