1#![doc(test(
2 no_crate_inject,
3 attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_assignments, unused_variables))
4))]
5#![warn(rust_2018_idioms, unreachable_pub)]
6#![no_std]
7#![deny(unsafe_code)]
8
9extern crate alloc;
12use alloc::boxed::Box;
13use core::ops::{Deref, Range};
14
15#[cfg(all(not(feature = "portable-atomic"), not(target_has_atomic = "ptr")))]
16compile_error!(
17 "this target does not support atomic operations, enable the `portable-atomic` feature to use `portable-atomic`"
18);
19
20#[cfg(not(feature = "portable-atomic"))]
22pub use alloc::sync::Arc as Shared;
23#[cfg(not(feature = "portable-atomic"))]
25pub use alloc::sync::Weak as WeakShared;
26#[cfg(feature = "portable-atomic")]
28pub use portable_atomic_util::Arc as Shared;
29#[cfg(feature = "portable-atomic")]
31pub use portable_atomic_util::Weak as WeakShared;
32
33const MEM_PAGE_SIZE: u64 = 65536;
35const fn max_page_count(arch: MemoryArch, page_size: u64) -> u64 {
36 match arch {
37 MemoryArch::I32 => (1u64 << 32) / page_size,
38 MemoryArch::I64 => u64::MAX / page_size,
39 }
40}
41
42mod instructions;
43mod operands;
44mod reference;
45mod types;
46mod value;
47pub use instructions::*;
48pub use operands::*;
49pub use reference::*;
50pub use types::*;
51pub use value::*;
52
53#[cfg(feature = "archive")]
54pub mod archive;
55
56#[cfg(not(feature = "archive"))]
57pub mod archive {
58 #[derive(Debug, PartialEq, Eq)]
59 pub enum TwasmError {}
60 impl core::fmt::Display for TwasmError {
61 fn fmt(&self, _: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
62 Err(core::fmt::Error)
63 }
64 }
65 impl core::error::Error for TwasmError {}
66}
67
68#[derive(Clone, Default, PartialEq)]
75#[cfg_attr(feature = "debug", derive(Debug))]
76#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
77pub struct Module(Shared<ModuleInner>);
78
79impl From<ModuleInner> for Module {
80 fn from(inner: ModuleInner) -> Self {
81 Self(Shared::new(inner))
82 }
83}
84
85impl Deref for Module {
86 type Target = ModuleInner;
87
88 fn deref(&self) -> &ModuleInner {
89 &self.0
90 }
91}
92
93#[doc(hidden)]
94#[derive(Clone, Default, PartialEq)]
95#[cfg_attr(feature = "debug", derive(Debug))]
96#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
97pub struct ModuleInner {
98 pub start_func: Option<FuncAddr>,
102
103 pub funcs: Box<[Shared<WasmFunction>]>,
107
108 pub types: TypeSection,
112
113 pub func_type_idxs: Box<[TypeAddr]>,
115
116 pub exports: Shared<[Export]>,
120
121 pub globals: Box<[Global]>,
125
126 pub tables: Box<[TableDefinition]>,
130
131 pub memory_types: Box<[MemoryType]>,
135
136 pub skip_local_memory_allocation: bool,
138
139 pub tags: Box<[TagType]>,
143
144 pub imports: Box<[Import]>,
148
149 pub data: Box<[Data]>,
153
154 pub elements: Box<[Element]>,
158}
159
160impl Module {
161 pub fn imports(&self) -> impl Iterator<Item = ModuleImport<'_>> {
165 self.0.imports.iter().filter_map(|import| {
166 let ty = match &import.kind {
167 ImportKind::Function(type_idx) => Some(ImportType::Func(self.0.types.get(*type_idx)?.as_func()?)),
168 ImportKind::Table(table_ty) => Some(ImportType::Table(table_ty)),
169 ImportKind::Memory(memory_ty) => Some(ImportType::Memory(memory_ty)),
170 ImportKind::Global(global_ty) => Some(ImportType::Global(global_ty)),
171 ImportKind::Tag(tag_ty) => Some(ImportType::Tag(self.0.types.get(tag_ty.type_idx)?.as_func()?)),
172 }?;
173
174 Some(ModuleImport { module: import.module.as_ref(), name: import.name.as_ref(), ty })
175 })
176 }
177
178 pub fn exports(&self) -> impl Iterator<Item = ModuleExport<'_>> {
182 fn imported_count(module: &ModuleInner, kind: ExternalKind) -> usize {
183 module
184 .imports
185 .iter()
186 .filter(|import| {
187 matches!(
188 (kind, &import.kind),
189 (ExternalKind::Func, ImportKind::Function(_))
190 | (ExternalKind::Table, ImportKind::Table(_))
191 | (ExternalKind::Memory, ImportKind::Memory(_))
192 | (ExternalKind::Global, ImportKind::Global(_))
193 | (ExternalKind::Tag, ImportKind::Tag(_))
194 )
195 })
196 .count()
197 }
198
199 fn imported_type(module: &ModuleInner, kind: ExternalKind, index: usize) -> Option<ExportType<'_>> {
200 let mut imports = module.imports.iter().filter(|import| {
201 matches!(
202 (kind, &import.kind),
203 (ExternalKind::Func, ImportKind::Function(_))
204 | (ExternalKind::Table, ImportKind::Table(_))
205 | (ExternalKind::Memory, ImportKind::Memory(_))
206 | (ExternalKind::Global, ImportKind::Global(_))
207 | (ExternalKind::Tag, ImportKind::Tag(_))
208 )
209 });
210 let import = imports.nth(index)?;
211
212 match &import.kind {
213 ImportKind::Function(type_idx) => Some(ExportType::Func(module.types.get(*type_idx)?.as_func()?)),
214 ImportKind::Table(table_ty) => Some(ExportType::Table(table_ty)),
215 ImportKind::Memory(memory_ty) => Some(ExportType::Memory(memory_ty)),
216 ImportKind::Global(global_ty) => Some(ExportType::Global(global_ty)),
217 ImportKind::Tag(tag_ty) => Some(ExportType::Tag(module.types.get(tag_ty.type_idx)?.as_func()?)),
218 }
219 }
220
221 self.0.exports.iter().filter_map(move |export| {
222 let idx = export.index as usize;
223 let ty = match export.kind {
224 ExternalKind::Func => {
225 let imported_funcs = imported_count(&self.0, ExternalKind::Func);
226 if idx < imported_funcs {
227 imported_type(&self.0, ExternalKind::Func, idx)?
228 } else {
229 let type_idx = *self.0.func_type_idxs.get(idx)?;
230 ExportType::Func(self.0.types.get(type_idx)?.as_func()?)
231 }
232 }
233 ExternalKind::Table => {
234 let imported_tables = imported_count(&self.0, ExternalKind::Table);
235 if idx < imported_tables {
236 imported_type(&self.0, ExternalKind::Table, idx)?
237 } else {
238 ExportType::Table(&self.0.tables.get(idx - imported_tables)?.ty)
239 }
240 }
241 ExternalKind::Memory => {
242 let imported_memories = imported_count(&self.0, ExternalKind::Memory);
243 if idx < imported_memories {
244 imported_type(&self.0, ExternalKind::Memory, idx)?
245 } else {
246 ExportType::Memory(self.0.memory_types.get(idx - imported_memories)?)
247 }
248 }
249 ExternalKind::Global => {
250 let imported_globals = imported_count(&self.0, ExternalKind::Global);
251 if idx < imported_globals {
252 imported_type(&self.0, ExternalKind::Global, idx)?
253 } else {
254 ExportType::Global(&self.0.globals.get(idx - imported_globals)?.ty)
255 }
256 }
257 ExternalKind::Tag => {
258 let imported_tags = imported_count(&self.0, ExternalKind::Tag);
259 if idx < imported_tags {
260 imported_type(&self.0, ExternalKind::Tag, idx)?
261 } else {
262 let tag_ty = self.0.tags.get(idx - imported_tags)?;
263 ExportType::Tag(self.0.types.get(tag_ty.type_idx)?.as_func()?)
264 }
265 }
266 };
267
268 Some(ModuleExport { name: export.name.as_ref(), ty })
269 })
270 }
271}
272
273pub struct ModuleExport<'a> {
275 pub name: &'a str,
277 pub ty: ExportType<'a>,
279}
280
281pub struct ModuleImport<'a> {
283 pub module: &'a str,
285 pub name: &'a str,
287 pub ty: ImportType<'a>,
289}
290
291pub enum ImportType<'a> {
293 Func(&'a FuncType),
295 Table(&'a TableType),
297 Memory(&'a MemoryType),
299 Global(&'a GlobalType),
301 Tag(&'a FuncType),
303}
304
305pub enum ExportType<'a> {
307 Func(&'a FuncType),
309 Table(&'a TableType),
311 Memory(&'a MemoryType),
313 Global(&'a GlobalType),
315 Tag(&'a FuncType),
317}
318
319#[derive(Clone, Copy, PartialEq, Eq)]
323#[cfg_attr(feature = "debug", derive(Debug))]
324#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
325pub enum ExternalKind {
326 Func,
328 Table,
330 Memory,
332 Global,
334 Tag,
336}
337
338pub type Addr = u32;
344
345pub type FuncAddr = Addr;
347pub type TableAddr = Addr;
348pub type MemAddr = Addr;
349pub type GlobalAddr = Addr;
350pub type TagAddr = Addr;
351pub type ElemAddr = Addr;
352pub type DataAddr = Addr;
353pub type ExternAddr = Addr;
354pub type ConstIdx = Addr;
355
356#[derive(Clone, Copy, PartialEq, Eq, Hash)]
361#[cfg_attr(feature = "debug", derive(Debug))]
362#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
363#[cfg_attr(feature = "archive", serde(transparent))]
364pub struct ModuleFuncIdx(u32);
365
366impl ModuleFuncIdx {
367 #[inline]
369 pub const fn new(index: u32) -> Self {
370 Self(index)
371 }
372
373 #[inline]
375 pub const fn index(self) -> u32 {
376 self.0
377 }
378}
379
380pub type TypeAddr = Addr;
384pub type LocalAddr = u16; pub type ModuleInstanceId = Addr;
386
387#[derive(Clone)]
391#[cfg_attr(feature = "debug", derive(Debug))]
392pub enum ExternVal {
393 Func(FuncAddr),
394 Table(TableAddr),
395 Memory(MemAddr),
396 Global(GlobalAddr),
397 Tag(TagAddr),
398}
399
400impl ExternVal {
401 #[inline]
402 pub const fn kind(&self) -> ExternalKind {
403 match self {
404 Self::Func(_) => ExternalKind::Func,
405 Self::Table(_) => ExternalKind::Table,
406 Self::Memory(_) => ExternalKind::Memory,
407 Self::Global(_) => ExternalKind::Global,
408 Self::Tag(_) => ExternalKind::Tag,
409 }
410 }
411
412 #[inline]
413 pub const fn new(kind: ExternalKind, addr: Addr) -> Self {
414 match kind {
415 ExternalKind::Func => Self::Func(addr),
416 ExternalKind::Table => Self::Table(addr),
417 ExternalKind::Memory => Self::Memory(addr),
418 ExternalKind::Global => Self::Global(addr),
419 ExternalKind::Tag => Self::Tag(addr),
420 }
421 }
422}
423
424#[derive(Clone, Copy, PartialEq, Eq)]
426#[cfg_attr(feature = "debug", derive(Debug))]
427pub enum ValueLane {
428 S32,
430 S64,
432 S128,
434}
435
436impl ValueLane {
437 pub fn select<T>(self, s32: T, s64: T, s128: T) -> T {
439 match self {
440 Self::S32 => s32,
441 Self::S64 => s64,
442 Self::S128 => s128,
443 }
444 }
445}
446
447impl From<&WasmType> for ValueLane {
448 fn from(ty: &WasmType) -> Self {
449 match ty {
450 WasmType::I32 | WasmType::F32 | WasmType::Ref(_) => Self::S32,
451 WasmType::I64 | WasmType::F64 => Self::S64,
452 WasmType::V128 => Self::S128,
453 }
454 }
455}
456
457#[derive(Default, Clone, Copy, PartialEq, Eq)]
458#[cfg_attr(feature = "debug", derive(Debug))]
459#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
460pub struct ValueCounts {
461 pub c32: u16,
462 pub c64: u16,
463 pub c128: u16,
464}
465
466impl ValueCounts {
467 #[inline]
468 pub fn is_empty(&self) -> bool {
469 self.c32 == 0 && self.c64 == 0 && self.c128 == 0
470 }
471}
472
473impl<'a> FromIterator<&'a WasmType> for ValueCounts {
474 #[inline]
475 fn from_iter<I: IntoIterator<Item = &'a WasmType>>(iter: I) -> Self {
476 let mut counts = Self::default();
477
478 for ty in iter {
479 match ValueLane::from(ty) {
480 ValueLane::S32 => counts.c32 += 1,
481 ValueLane::S64 => counts.c64 += 1,
482 ValueLane::S128 => counts.c128 += 1,
483 }
484 }
485 counts
486 }
487}
488
489#[derive(Clone, PartialEq, Default)]
490#[cfg_attr(feature = "debug", derive(Debug))]
491#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
492pub struct WasmFunction {
493 pub instructions: Box<[Instruction]>,
494 pub data: WasmFunctionData,
495 pub locals: ValueCounts,
496 pub params: ValueCounts,
497 pub results: ValueCounts,
498}
499
500#[derive(Clone, PartialEq, Eq, Default)]
501#[cfg_attr(feature = "debug", derive(Debug))]
502#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
503pub struct WasmFunctionData {
504 pub operands64: Box<[Operand64]>,
505 pub operands128: Box<[Operand128]>,
506 pub branch_table_targets: Box<[u32]>,
507 pub exception_handlers: Box<[ExceptionHandler]>,
508}
509
510#[derive(Clone, PartialEq, Eq)]
512#[cfg_attr(feature = "debug", derive(Debug))]
513#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
514pub struct Export {
515 pub name: Box<str>,
517 pub kind: ExternalKind,
519 pub index: u32,
521}
522
523#[derive(Clone, PartialEq)]
524#[cfg_attr(feature = "debug", derive(Debug))]
525#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
526pub struct Global {
527 pub ty: GlobalType,
528 pub init: Box<[ConstInstruction]>,
529}
530
531#[derive(Clone, Copy, PartialEq, Eq)]
535#[cfg_attr(feature = "debug", derive(Debug))]
536#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
537pub struct GlobalType {
538 pub mutable: bool,
539 pub ty: WasmType,
540}
541
542impl GlobalType {
543 pub const fn new(ty: WasmType, mutable: bool) -> Self {
545 Self { mutable, ty }
546 }
547
548 pub const fn with_ty(mut self, ty: WasmType) -> Self {
550 self.ty = ty;
551 self
552 }
553
554 pub const fn with_mutable(mut self, mutable: bool) -> Self {
556 self.mutable = mutable;
557 self
558 }
559}
560
561impl Default for GlobalType {
562 fn default() -> Self {
563 Self::new(WasmType::I32, false)
564 }
565}
566
567#[derive(Copy, Clone, PartialEq, Eq)]
571#[cfg_attr(feature = "debug", derive(Debug))]
572#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
573pub struct TableType {
574 arch: MemoryArch,
575 pub element_type: RefType,
576 pub size_initial: u64,
577 pub size_max: Option<u64>,
578}
579
580#[derive(Clone, PartialEq)]
581#[cfg_attr(feature = "debug", derive(Debug))]
582#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
583pub struct TableDefinition {
584 pub ty: TableType,
585 pub init: Option<Box<[ConstInstruction]>>,
586}
587
588impl TableType {
589 pub const fn empty() -> Self {
590 Self::new(RefType::FUNCREF, 0, None)
591 }
592
593 pub const fn new(element_type: RefType, size_initial: u64, size_max: Option<u64>) -> Self {
595 Self { arch: MemoryArch::I32, element_type, size_initial, size_max }
596 }
597
598 pub const fn new64(element_type: RefType, size_initial: u64, size_max: Option<u64>) -> Self {
600 Self { arch: MemoryArch::I64, element_type, size_initial, size_max }
601 }
602
603 #[inline]
604 pub const fn arch(&self) -> MemoryArch {
605 self.arch
606 }
607}
608
609#[derive(Copy, Clone, PartialEq, Eq)]
613#[cfg_attr(feature = "debug", derive(Debug))]
614#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
615pub struct MemoryType {
616 arch: MemoryArch,
617 page_count_initial: u64,
618 page_count_max: Option<u64>,
619 page_size: Option<u64>,
620}
621
622impl MemoryType {
623 pub const fn new(
625 arch: MemoryArch,
626 page_count_initial: u64,
627 page_count_max: Option<u64>,
628 page_size: Option<u64>,
629 ) -> Self {
630 Self { arch, page_count_initial, page_count_max, page_size }
631 }
632
633 #[inline]
634 pub const fn arch(&self) -> MemoryArch {
635 self.arch
636 }
637
638 #[inline]
639 pub const fn page_count_initial(&self) -> u64 {
640 self.page_count_initial
641 }
642
643 #[inline]
644 pub const fn page_count_max(&self) -> u64 {
645 if let Some(page_count_max) = self.page_count_max {
646 page_count_max
647 } else {
648 max_page_count(self.arch, self.page_size())
649 }
650 }
651
652 #[inline]
654 pub const fn page_count_max_declared(&self) -> Option<u64> {
655 self.page_count_max
656 }
657
658 #[inline]
659 pub const fn page_size(&self) -> u64 {
660 if let Some(page_size) = self.page_size { page_size } else { MEM_PAGE_SIZE }
661 }
662
663 pub const fn with_arch(mut self, arch: MemoryArch) -> Self {
665 self.arch = arch;
666 self
667 }
668
669 pub const fn with_page_count_initial(mut self, page_count_initial: u64) -> Self {
671 self.page_count_initial = page_count_initial;
672 self
673 }
674
675 pub const fn with_page_count_max(mut self, page_count_max: Option<u64>) -> Self {
677 self.page_count_max = page_count_max;
678 self
679 }
680
681 pub const fn with_page_size(mut self, page_size: Option<u64>) -> Self {
683 self.page_size = page_size;
684 self
685 }
686}
687
688impl Default for MemoryType {
689 fn default() -> Self {
690 Self::new(MemoryArch::I32, 0, None, None)
691 }
692}
693
694#[derive(Copy, Clone, PartialEq, Eq, Hash)]
695#[cfg_attr(feature = "debug", derive(Debug))]
696#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
697pub enum MemoryArch {
698 I32,
699 I64,
700}
701
702#[derive(Clone, Copy, PartialEq, Eq)]
706#[cfg_attr(feature = "debug", derive(Debug))]
707#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
708pub struct TagType {
709 pub type_idx: TypeAddr,
711}
712
713impl TagType {
714 pub const fn new(type_idx: TypeAddr) -> Self {
716 Self { type_idx }
717 }
718}
719
720#[derive(Clone, PartialEq, Eq)]
721#[cfg_attr(feature = "debug", derive(Debug))]
722#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
723pub struct Import {
724 pub module: Box<str>,
725 pub name: Box<str>,
726 pub kind: ImportKind,
727}
728
729#[derive(Clone, PartialEq, Eq)]
730#[cfg_attr(feature = "debug", derive(Debug))]
731#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
732pub enum ImportKind {
733 Function(TypeAddr),
734 Table(TableType),
735 Memory(MemoryType),
736 Global(GlobalType),
737 Tag(TagType),
738}
739
740impl From<&ImportKind> for ExternalKind {
741 fn from(kind: &ImportKind) -> Self {
742 match kind {
743 ImportKind::Function(_) => Self::Func,
744 ImportKind::Table(_) => Self::Table,
745 ImportKind::Memory(_) => Self::Memory,
746 ImportKind::Global(_) => Self::Global,
747 ImportKind::Tag(_) => Self::Tag,
748 }
749 }
750}
751
752#[derive(Clone, PartialEq)]
753#[cfg_attr(feature = "debug", derive(Debug))]
754#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
755pub struct Data {
756 pub data: Shared<[u8]>,
757 pub range: Range<u64>,
758 pub kind: DataKind,
759}
760
761#[derive(Clone, PartialEq)]
762#[cfg_attr(feature = "debug", derive(Debug))]
763#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
764pub enum DataKind {
765 Active { mem: MemAddr, offset: Box<[ConstInstruction]> },
766 Passive,
767}
768
769#[derive(Clone, PartialEq)]
770#[cfg_attr(feature = "debug", derive(Debug))]
771#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
772pub struct Element {
773 pub kind: ElementKind,
774 pub items: Box<[ElementItem]>,
775 pub range: Range<u64>,
776 pub ty: RefType,
777}
778
779#[derive(Clone, PartialEq)]
780#[cfg_attr(feature = "debug", derive(Debug))]
781#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
782pub enum ElementKind {
783 Passive,
784 Active { table: TableAddr, offset: Box<[ConstInstruction]> },
785 Declared,
786}
787
788#[derive(Clone, PartialEq)]
789#[cfg_attr(feature = "debug", derive(Debug))]
790#[cfg_attr(feature = "archive", derive(serde::Serialize, serde::Deserialize))]
791pub enum ElementItem {
792 Func(FuncAddr),
793 Expr(Box<[ConstInstruction]>),
794}