1mod interpreter;
67
68#[cfg(all(
70 any(
71 all(
72 target_arch = "x86_64",
73 any(
74 target_os = "windows",
75 all(target_os = "linux", target_env = "gnu"),
76 target_os = "macos"
77 )
78 ),
79 all(target_arch = "aarch64", target_os = "linux", target_env = "gnu"),
80 all(target_arch = "s390x", target_os = "linux", target_env = "gnu")
81 ),
82 feature = "wasmtime"
83))]
84mod jit;
85
86mod tests;
87
88use alloc::{string::String, vec::Vec};
89use core::{fmt, iter};
90use smallvec::SmallVec;
91
92pub struct Config<'a> {
94 pub module_bytes: &'a [u8],
96
97 pub exec_hint: ExecHint,
99
100 pub symbols: &'a mut dyn FnMut(&str, &str, &Signature) -> Result<usize, ()>,
104}
105
106#[derive(Clone)]
111pub struct VirtualMachinePrototype {
112 inner: VirtualMachinePrototypeInner,
113}
114
115#[derive(Clone)]
116enum VirtualMachinePrototypeInner {
117 #[cfg(all(
118 any(
119 all(
120 target_arch = "x86_64",
121 any(
122 target_os = "windows",
123 all(target_os = "linux", target_env = "gnu"),
124 target_os = "macos"
125 )
126 ),
127 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
128 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
129 ),
130 feature = "wasmtime"
131 ))]
132 Jit(jit::JitPrototype),
133 Interpreter(interpreter::InterpreterPrototype),
134}
135
136impl VirtualMachinePrototype {
137 pub fn new(config: Config) -> Result<Self, NewErr> {
143 Ok(VirtualMachinePrototype {
144 inner: match config.exec_hint {
145 #[cfg(all(
146 any(
147 all(
148 target_arch = "x86_64",
149 any(
150 target_os = "windows",
151 all(target_os = "linux", target_env = "gnu"),
152 target_os = "macos"
153 )
154 ),
155 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
156 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
157 ),
158 feature = "wasmtime"
159 ))]
160 ExecHint::ValidateAndCompile => VirtualMachinePrototypeInner::Jit(
161 jit::JitPrototype::new(config.module_bytes, config.symbols)?,
162 ),
163 #[cfg(not(all(
164 any(
165 all(
166 target_arch = "x86_64",
167 any(
168 target_os = "windows",
169 all(target_os = "linux", target_env = "gnu"),
170 target_os = "macos"
171 )
172 ),
173 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
174 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
175 ),
176 feature = "wasmtime"
177 )))]
178 ExecHint::ValidateAndCompile => VirtualMachinePrototypeInner::Interpreter(
179 interpreter::InterpreterPrototype::new(
180 config.module_bytes,
181 interpreter::CompilationMode::Eager,
182 config.symbols,
183 )?,
184 ),
185 ExecHint::ValidateAndExecuteOnce | ExecHint::Untrusted => {
186 VirtualMachinePrototypeInner::Interpreter(
187 interpreter::InterpreterPrototype::new(
188 config.module_bytes,
189 interpreter::CompilationMode::Eager,
190 config.symbols,
191 )?,
192 )
193 }
194 ExecHint::CompileWithNonDeterministicValidation
195 | ExecHint::ExecuteOnceWithNonDeterministicValidation => {
196 VirtualMachinePrototypeInner::Interpreter(
197 interpreter::InterpreterPrototype::new(
198 config.module_bytes,
199 interpreter::CompilationMode::Lazy,
200 config.symbols,
201 )?,
202 )
203 }
204 ExecHint::ForceWasmi { lazy_validation } => {
205 VirtualMachinePrototypeInner::Interpreter(
206 interpreter::InterpreterPrototype::new(
207 config.module_bytes,
208 if lazy_validation {
209 interpreter::CompilationMode::Lazy
210 } else {
211 interpreter::CompilationMode::Eager
212 },
213 config.symbols,
214 )?,
215 )
216 }
217
218 #[cfg(all(
219 any(
220 all(
221 target_arch = "x86_64",
222 any(
223 target_os = "windows",
224 all(target_os = "linux", target_env = "gnu"),
225 target_os = "macos"
226 )
227 ),
228 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
229 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
230 ),
231 feature = "wasmtime"
232 ))]
233 ExecHint::ForceWasmtime => VirtualMachinePrototypeInner::Jit(
234 jit::JitPrototype::new(config.module_bytes, config.symbols)?,
235 ),
236 },
237 })
238 }
239
240 pub fn global_value(&mut self, name: &str) -> Result<u32, GlobalValueErr> {
245 match &mut self.inner {
246 #[cfg(all(
247 any(
248 all(
249 target_arch = "x86_64",
250 any(
251 target_os = "windows",
252 all(target_os = "linux", target_env = "gnu"),
253 target_os = "macos"
254 )
255 ),
256 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
257 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
258 ),
259 feature = "wasmtime"
260 ))]
261 VirtualMachinePrototypeInner::Jit(inner) => inner.global_value(name),
262 VirtualMachinePrototypeInner::Interpreter(inner) => inner.global_value(name),
263 }
264 }
265
266 pub fn memory_max_pages(&self) -> Option<HeapPages> {
270 match &self.inner {
271 #[cfg(all(
272 any(
273 all(
274 target_arch = "x86_64",
275 any(
276 target_os = "windows",
277 all(target_os = "linux", target_env = "gnu"),
278 target_os = "macos"
279 )
280 ),
281 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
282 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
283 ),
284 feature = "wasmtime"
285 ))]
286 VirtualMachinePrototypeInner::Jit(inner) => inner.memory_max_pages(),
287 VirtualMachinePrototypeInner::Interpreter(inner) => inner.memory_max_pages(),
288 }
289 }
290
291 pub fn prepare(self) -> Prepare {
296 match self.inner {
297 #[cfg(all(
298 any(
299 all(
300 target_arch = "x86_64",
301 any(
302 target_os = "windows",
303 all(target_os = "linux", target_env = "gnu"),
304 target_os = "macos"
305 )
306 ),
307 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
308 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
309 ),
310 feature = "wasmtime"
311 ))]
312 VirtualMachinePrototypeInner::Jit(inner) => Prepare {
313 inner: PrepareInner::Jit(inner.prepare()),
314 },
315 VirtualMachinePrototypeInner::Interpreter(inner) => Prepare {
316 inner: PrepareInner::Interpreter(inner.prepare()),
317 },
318 }
319 }
320}
321
322impl fmt::Debug for VirtualMachinePrototype {
323 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
324 match &self.inner {
325 #[cfg(all(
326 any(
327 all(
328 target_arch = "x86_64",
329 any(
330 target_os = "windows",
331 all(target_os = "linux", target_env = "gnu"),
332 target_os = "macos"
333 )
334 ),
335 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
336 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
337 ),
338 feature = "wasmtime"
339 ))]
340 VirtualMachinePrototypeInner::Jit(inner) => fmt::Debug::fmt(inner, f),
341 VirtualMachinePrototypeInner::Interpreter(inner) => fmt::Debug::fmt(inner, f),
342 }
343 }
344}
345
346pub struct Prepare {
347 inner: PrepareInner,
348}
349
350enum PrepareInner {
351 #[cfg(all(
352 any(
353 all(
354 target_arch = "x86_64",
355 any(
356 target_os = "windows",
357 all(target_os = "linux", target_env = "gnu"),
358 target_os = "macos"
359 )
360 ),
361 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
362 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
363 ),
364 feature = "wasmtime"
365 ))]
366 Jit(jit::Prepare),
367 Interpreter(interpreter::Prepare),
368}
369
370impl Prepare {
371 pub fn into_prototype(self) -> VirtualMachinePrototype {
373 VirtualMachinePrototype {
374 inner: match self.inner {
375 #[cfg(all(
376 any(
377 all(
378 target_arch = "x86_64",
379 any(
380 target_os = "windows",
381 all(target_os = "linux", target_env = "gnu"),
382 target_os = "macos"
383 )
384 ),
385 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
386 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
387 ),
388 feature = "wasmtime"
389 ))]
390 PrepareInner::Jit(inner) => {
391 VirtualMachinePrototypeInner::Jit(inner.into_prototype())
392 }
393 PrepareInner::Interpreter(inner) => {
394 VirtualMachinePrototypeInner::Interpreter(inner.into_prototype())
395 }
396 },
397 }
398 }
399
400 pub fn memory_size(&self) -> HeapPages {
402 match &self.inner {
403 #[cfg(all(
404 any(
405 all(
406 target_arch = "x86_64",
407 any(
408 target_os = "windows",
409 all(target_os = "linux", target_env = "gnu"),
410 target_os = "macos"
411 )
412 ),
413 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
414 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
415 ),
416 feature = "wasmtime"
417 ))]
418 PrepareInner::Jit(inner) => inner.memory_size(),
419 PrepareInner::Interpreter(inner) => inner.memory_size(),
420 }
421 }
422
423 pub fn read_memory(
427 &self,
428 offset: u32,
429 size: u32,
430 ) -> Result<impl AsRef<[u8]>, OutOfBoundsError> {
431 Ok(match &self.inner {
432 #[cfg(all(
433 any(
434 all(
435 target_arch = "x86_64",
436 any(
437 target_os = "windows",
438 all(target_os = "linux", target_env = "gnu"),
439 target_os = "macos"
440 )
441 ),
442 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
443 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
444 ),
445 feature = "wasmtime"
446 ))]
447 PrepareInner::Jit(inner) => either::Left(inner.read_memory(offset, size)?),
448 #[cfg(all(
449 any(
450 all(
451 target_arch = "x86_64",
452 any(
453 target_os = "windows",
454 all(target_os = "linux", target_env = "gnu"),
455 target_os = "macos"
456 )
457 ),
458 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
459 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
460 ),
461 feature = "wasmtime"
462 ))]
463 PrepareInner::Interpreter(inner) => either::Right(inner.read_memory(offset, size)?),
464 #[cfg(not(all(
465 any(
466 all(
467 target_arch = "x86_64",
468 any(
469 target_os = "windows",
470 all(target_os = "linux", target_env = "gnu"),
471 target_os = "macos"
472 )
473 ),
474 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
475 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
476 ),
477 feature = "wasmtime"
478 )))]
479 PrepareInner::Interpreter(inner) => inner.read_memory(offset, size)?,
480 })
481 }
482
483 pub fn write_memory(&mut self, offset: u32, value: &[u8]) -> Result<(), OutOfBoundsError> {
487 match &mut self.inner {
488 #[cfg(all(
489 any(
490 all(
491 target_arch = "x86_64",
492 any(
493 target_os = "windows",
494 all(target_os = "linux", target_env = "gnu"),
495 target_os = "macos"
496 )
497 ),
498 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
499 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
500 ),
501 feature = "wasmtime"
502 ))]
503 PrepareInner::Jit(inner) => inner.write_memory(offset, value),
504 PrepareInner::Interpreter(inner) => inner.write_memory(offset, value),
505 }
506 }
507
508 pub fn grow_memory(&mut self, additional: HeapPages) -> Result<(), OutOfBoundsError> {
513 match &mut self.inner {
514 #[cfg(all(
515 any(
516 all(
517 target_arch = "x86_64",
518 any(
519 target_os = "windows",
520 all(target_os = "linux", target_env = "gnu"),
521 target_os = "macos"
522 )
523 ),
524 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
525 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
526 ),
527 feature = "wasmtime"
528 ))]
529 PrepareInner::Jit(inner) => inner.grow_memory(additional),
530 PrepareInner::Interpreter(inner) => inner.grow_memory(additional),
531 }
532 }
533
534 pub fn start(
537 self,
538 function_name: &str,
539 params: &[WasmValue],
540 ) -> Result<VirtualMachine, (StartErr, VirtualMachinePrototype)> {
541 Ok(VirtualMachine {
542 inner: match self.inner {
543 #[cfg(all(
544 any(
545 all(
546 target_arch = "x86_64",
547 any(
548 target_os = "windows",
549 all(target_os = "linux", target_env = "gnu"),
550 target_os = "macos"
551 )
552 ),
553 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
554 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
555 ),
556 feature = "wasmtime"
557 ))]
558 PrepareInner::Jit(inner) => match inner.start(function_name, params) {
559 Ok(vm) => VirtualMachineInner::Jit(vm),
560 Err((err, proto)) => {
561 return Err((
562 err,
563 VirtualMachinePrototype {
564 inner: VirtualMachinePrototypeInner::Jit(proto),
565 },
566 ));
567 }
568 },
569 PrepareInner::Interpreter(inner) => match inner.start(function_name, params) {
570 Ok(vm) => VirtualMachineInner::Interpreter(vm),
571 Err((err, proto)) => {
572 return Err((
573 err,
574 VirtualMachinePrototype {
575 inner: VirtualMachinePrototypeInner::Interpreter(proto),
576 },
577 ));
578 }
579 },
580 },
581 })
582 }
583}
584
585impl fmt::Debug for Prepare {
586 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
587 match &self.inner {
588 #[cfg(all(
589 any(
590 all(
591 target_arch = "x86_64",
592 any(
593 target_os = "windows",
594 all(target_os = "linux", target_env = "gnu"),
595 target_os = "macos"
596 )
597 ),
598 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
599 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
600 ),
601 feature = "wasmtime"
602 ))]
603 PrepareInner::Jit(inner) => fmt::Debug::fmt(inner, f),
604 PrepareInner::Interpreter(inner) => fmt::Debug::fmt(inner, f),
605 }
606 }
607}
608
609pub struct VirtualMachine {
610 inner: VirtualMachineInner,
611}
612
613enum VirtualMachineInner {
614 #[cfg(all(
615 any(
616 all(
617 target_arch = "x86_64",
618 any(
619 target_os = "windows",
620 all(target_os = "linux", target_env = "gnu"),
621 target_os = "macos"
622 )
623 ),
624 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
625 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
626 ),
627 feature = "wasmtime"
628 ))]
629 Jit(jit::Jit),
630 Interpreter(interpreter::Interpreter),
631}
632
633impl VirtualMachine {
634 pub fn run(&mut self, value: Option<WasmValue>) -> Result<ExecOutcome, RunErr> {
642 match &mut self.inner {
643 #[cfg(all(
644 any(
645 all(
646 target_arch = "x86_64",
647 any(
648 target_os = "windows",
649 all(target_os = "linux", target_env = "gnu"),
650 target_os = "macos"
651 )
652 ),
653 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
654 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
655 ),
656 feature = "wasmtime"
657 ))]
658 VirtualMachineInner::Jit(inner) => inner.run(value),
659 VirtualMachineInner::Interpreter(inner) => inner.run(value),
660 }
661 }
662
663 pub fn memory_size(&self) -> HeapPages {
667 match &self.inner {
668 #[cfg(all(
669 any(
670 all(
671 target_arch = "x86_64",
672 any(
673 target_os = "windows",
674 all(target_os = "linux", target_env = "gnu"),
675 target_os = "macos"
676 )
677 ),
678 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
679 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
680 ),
681 feature = "wasmtime"
682 ))]
683 VirtualMachineInner::Jit(inner) => inner.memory_size(),
684 VirtualMachineInner::Interpreter(inner) => inner.memory_size(),
685 }
686 }
687
688 pub fn read_memory(
692 &self,
693 offset: u32,
694 size: u32,
695 ) -> Result<impl AsRef<[u8]>, OutOfBoundsError> {
696 Ok(match &self.inner {
697 #[cfg(all(
698 any(
699 all(
700 target_arch = "x86_64",
701 any(
702 target_os = "windows",
703 all(target_os = "linux", target_env = "gnu"),
704 target_os = "macos"
705 )
706 ),
707 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
708 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
709 ),
710 feature = "wasmtime"
711 ))]
712 VirtualMachineInner::Jit(inner) => either::Left(inner.read_memory(offset, size)?),
713 #[cfg(all(
714 any(
715 all(
716 target_arch = "x86_64",
717 any(
718 target_os = "windows",
719 all(target_os = "linux", target_env = "gnu"),
720 target_os = "macos"
721 )
722 ),
723 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
724 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
725 ),
726 feature = "wasmtime"
727 ))]
728 VirtualMachineInner::Interpreter(inner) => {
729 either::Right(inner.read_memory(offset, size)?)
730 }
731 #[cfg(not(all(
732 any(
733 all(
734 target_arch = "x86_64",
735 any(
736 target_os = "windows",
737 all(target_os = "linux", target_env = "gnu"),
738 target_os = "macos"
739 )
740 ),
741 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
742 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
743 ),
744 feature = "wasmtime"
745 )))]
746 VirtualMachineInner::Interpreter(inner) => inner.read_memory(offset, size)?,
747 })
748 }
749
750 pub fn write_memory(&mut self, offset: u32, value: &[u8]) -> Result<(), OutOfBoundsError> {
754 match &mut self.inner {
755 #[cfg(all(
756 any(
757 all(
758 target_arch = "x86_64",
759 any(
760 target_os = "windows",
761 all(target_os = "linux", target_env = "gnu"),
762 target_os = "macos"
763 )
764 ),
765 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
766 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
767 ),
768 feature = "wasmtime"
769 ))]
770 VirtualMachineInner::Jit(inner) => inner.write_memory(offset, value),
771 VirtualMachineInner::Interpreter(inner) => inner.write_memory(offset, value),
772 }
773 }
774
775 pub fn grow_memory(&mut self, additional: HeapPages) -> Result<(), OutOfBoundsError> {
780 match &mut self.inner {
781 #[cfg(all(
782 any(
783 all(
784 target_arch = "x86_64",
785 any(
786 target_os = "windows",
787 all(target_os = "linux", target_env = "gnu"),
788 target_os = "macos"
789 )
790 ),
791 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
792 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
793 ),
794 feature = "wasmtime"
795 ))]
796 VirtualMachineInner::Jit(inner) => inner.grow_memory(additional),
797 VirtualMachineInner::Interpreter(inner) => inner.grow_memory(additional),
798 }
799 }
800
801 pub fn into_prototype(self) -> VirtualMachinePrototype {
803 VirtualMachinePrototype {
804 inner: match self.inner {
805 #[cfg(all(
806 any(
807 all(
808 target_arch = "x86_64",
809 any(
810 target_os = "windows",
811 all(target_os = "linux", target_env = "gnu"),
812 target_os = "macos"
813 )
814 ),
815 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
816 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
817 ),
818 feature = "wasmtime"
819 ))]
820 VirtualMachineInner::Jit(inner) => {
821 VirtualMachinePrototypeInner::Jit(inner.into_prototype())
822 }
823 VirtualMachineInner::Interpreter(inner) => {
824 VirtualMachinePrototypeInner::Interpreter(inner.into_prototype())
825 }
826 },
827 }
828 }
829}
830
831impl fmt::Debug for VirtualMachine {
832 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
833 match &self.inner {
834 #[cfg(all(
835 any(
836 all(
837 target_arch = "x86_64",
838 any(
839 target_os = "windows",
840 all(target_os = "linux", target_env = "gnu"),
841 target_os = "macos"
842 )
843 ),
844 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
845 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
846 ),
847 feature = "wasmtime"
848 ))]
849 VirtualMachineInner::Jit(inner) => fmt::Debug::fmt(inner, f),
850 VirtualMachineInner::Interpreter(inner) => fmt::Debug::fmt(inner, f),
851 }
852 }
853}
854
855#[derive(Debug, Copy, Clone, PartialEq, Eq)]
857pub enum ExecHint {
858 ValidateAndCompile,
861
862 CompileWithNonDeterministicValidation,
867
868 ValidateAndExecuteOnce,
872
873 ExecuteOnceWithNonDeterministicValidation,
878
879 Untrusted,
881
882 ForceWasmi {
886 lazy_validation: bool,
890 },
891 #[cfg(all(
895 any(
896 all(
897 target_arch = "x86_64",
898 any(
899 target_os = "windows",
900 all(target_os = "linux", target_env = "gnu"),
901 target_os = "macos"
902 )
903 ),
904 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
905 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
906 ),
907 feature = "wasmtime"
908 ))]
909 ForceWasmtime,
910}
911
912impl ExecHint {
913 pub fn available_engines() -> impl Iterator<Item = ExecHint> {
917 iter::once(ExecHint::ForceWasmi {
918 lazy_validation: false,
919 })
920 .chain(Self::force_wasmtime_if_available())
921 }
922
923 pub fn force_wasmtime_if_available() -> Option<ExecHint> {
925 #[cfg(all(
926 any(
927 all(
928 target_arch = "x86_64",
929 any(
930 target_os = "windows",
931 all(target_os = "linux", target_env = "gnu"),
932 target_os = "macos"
933 )
934 ),
935 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
936 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
937 ),
938 feature = "wasmtime"
939 ))]
940 fn value() -> Option<ExecHint> {
941 Some(ExecHint::ForceWasmtime)
942 }
943 #[cfg(not(all(
944 any(
945 all(
946 target_arch = "x86_64",
947 any(
948 target_os = "windows",
949 all(target_os = "linux", target_env = "gnu"),
950 target_os = "macos"
951 )
952 ),
953 all(target_arch = "aarch64", all(target_os = "linux", target_env = "gnu")),
954 all(target_arch = "s390x", all(target_os = "linux", target_env = "gnu"))
955 ),
956 feature = "wasmtime"
957 )))]
958 fn value() -> Option<ExecHint> {
959 None
960 }
961 value()
962 }
963}
964
965#[derive(
969 Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, derive_more::Add, derive_more::Sub,
970)]
971pub struct HeapPages(u32);
972
973impl HeapPages {
974 pub const fn new(v: u32) -> Self {
975 HeapPages(v)
976 }
977}
978
979impl From<u32> for HeapPages {
980 fn from(v: u32) -> Self {
981 HeapPages(v)
982 }
983}
984
985impl From<HeapPages> for u32 {
986 fn from(v: HeapPages) -> Self {
987 v.0
988 }
989}
990
991#[derive(Debug, Clone, PartialEq, Eq, Hash)]
993pub struct Signature {
994 params: SmallVec<[ValueType; 8]>,
995 ret_ty: Option<ValueType>,
996}
997
998#[macro_export]
1000macro_rules! signature {
1001 (($($param:expr),* $(,)?) => ()) => {
1002 $crate::executor::vm::Signature::from_components(smallvec::smallvec!($($param),*), None)
1003 };
1004 (($($param:expr),* $(,)?) => $ret:expr) => {
1005 $crate::executor::vm::Signature::from_components(smallvec::smallvec!($($param),*), Some($ret))
1006 };
1007}
1008
1009impl Signature {
1010 pub fn new(
1012 params: impl Iterator<Item = ValueType>,
1013 ret_ty: impl Into<Option<ValueType>>,
1014 ) -> Signature {
1015 Signature {
1016 params: params.collect(),
1017 ret_ty: ret_ty.into(),
1018 }
1019 }
1020
1021 #[doc(hidden)]
1023 pub(crate) fn from_components(
1024 params: SmallVec<[ValueType; 8]>,
1025 ret_ty: Option<ValueType>,
1026 ) -> Self {
1027 Signature { params, ret_ty }
1028 }
1029
1030 pub fn parameters(&self) -> impl ExactSizeIterator<Item = &ValueType> {
1032 self.params.iter()
1033 }
1034
1035 pub fn return_type(&self) -> Option<&ValueType> {
1037 self.ret_ty.as_ref()
1038 }
1039}
1040
1041impl<'a> From<&'a Signature> for wasmi::FuncType {
1042 fn from(sig: &'a Signature) -> Self {
1043 wasmi::FuncType::new(
1044 sig.params
1045 .iter()
1046 .copied()
1047 .map(wasmi::core::ValType::from)
1048 .collect::<Vec<_>>(),
1049 sig.ret_ty.map(wasmi::core::ValType::from),
1050 )
1051 }
1052}
1053
1054impl From<Signature> for wasmi::FuncType {
1055 fn from(sig: Signature) -> wasmi::FuncType {
1056 wasmi::FuncType::from(&sig)
1057 }
1058}
1059
1060impl<'a> TryFrom<&'a wasmi::FuncType> for Signature {
1061 type Error = UnsupportedTypeError;
1062
1063 fn try_from(sig: &'a wasmi::FuncType) -> Result<Self, Self::Error> {
1064 if sig.results().len() > 1 {
1065 return Err(UnsupportedTypeError);
1066 }
1067
1068 Ok(Signature {
1069 params: sig
1070 .params()
1071 .iter()
1072 .copied()
1073 .map(ValueType::try_from)
1074 .collect::<Result<_, _>>()?,
1075 ret_ty: sig
1076 .results()
1077 .first()
1078 .copied()
1079 .map(ValueType::try_from)
1080 .transpose()?,
1081 })
1082 }
1083}
1084
1085#[cfg(all(
1086 any(
1087 all(
1088 target_arch = "x86_64",
1089 any(
1090 target_os = "windows",
1091 all(target_os = "linux", target_env = "gnu"),
1092 target_os = "macos"
1093 )
1094 ),
1095 all(target_arch = "aarch64", target_os = "linux", target_env = "gnu"),
1096 all(target_arch = "s390x", target_os = "linux", target_env = "gnu")
1097 ),
1098 feature = "wasmtime"
1099))]
1100impl<'a> TryFrom<&'a wasmtime::FuncType> for Signature {
1101 type Error = UnsupportedTypeError;
1102
1103 fn try_from(sig: &'a wasmtime::FuncType) -> Result<Self, Self::Error> {
1104 if sig.results().len() > 1 {
1105 return Err(UnsupportedTypeError);
1106 }
1107
1108 Ok(Signature {
1109 params: sig
1110 .params()
1111 .map(ValueType::try_from)
1112 .collect::<Result<_, _>>()?,
1113 ret_ty: sig.results().next().map(ValueType::try_from).transpose()?,
1114 })
1115 }
1116}
1117
1118impl TryFrom<wasmi::FuncType> for Signature {
1119 type Error = UnsupportedTypeError;
1120
1121 fn try_from(sig: wasmi::FuncType) -> Result<Self, Self::Error> {
1122 Signature::try_from(&sig)
1123 }
1124}
1125
1126#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1128pub enum WasmValue {
1129 I32(i32),
1132 I64(i64),
1135}
1136
1137#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1139pub enum ValueType {
1140 I32,
1142 I64,
1144}
1145
1146impl WasmValue {
1147 pub fn ty(&self) -> ValueType {
1149 match self {
1150 WasmValue::I32(_) => ValueType::I32,
1151 WasmValue::I64(_) => ValueType::I64,
1152 }
1153 }
1154
1155 pub fn into_i32(self) -> Option<i32> {
1157 if let WasmValue::I32(v) = self {
1158 Some(v)
1159 } else {
1160 None
1161 }
1162 }
1163
1164 pub fn into_i64(self) -> Option<i64> {
1166 if let WasmValue::I64(v) = self {
1167 Some(v)
1168 } else {
1169 None
1170 }
1171 }
1172}
1173
1174impl TryFrom<wasmi::Val> for WasmValue {
1175 type Error = UnsupportedTypeError;
1176
1177 fn try_from(val: wasmi::Val) -> Result<Self, Self::Error> {
1178 match val {
1179 wasmi::Val::I32(v) => Ok(WasmValue::I32(v)),
1180 wasmi::Val::I64(v) => Ok(WasmValue::I64(v)),
1181 _ => Err(UnsupportedTypeError),
1182 }
1183 }
1184}
1185
1186impl<'a> TryFrom<&'a wasmi::Val> for WasmValue {
1187 type Error = UnsupportedTypeError;
1188
1189 fn try_from(val: &'a wasmi::Val) -> Result<Self, Self::Error> {
1190 match val {
1191 wasmi::Val::I32(v) => Ok(WasmValue::I32(*v)),
1192 wasmi::Val::I64(v) => Ok(WasmValue::I64(*v)),
1193 _ => Err(UnsupportedTypeError),
1194 }
1195 }
1196}
1197
1198impl From<WasmValue> for wasmi::Val {
1199 fn from(val: WasmValue) -> Self {
1200 match val {
1201 WasmValue::I32(v) => wasmi::Val::I32(v),
1202 WasmValue::I64(v) => wasmi::Val::I64(v),
1203 }
1204 }
1205}
1206
1207#[cfg(all(
1208 any(
1209 all(
1210 target_arch = "x86_64",
1211 any(
1212 target_os = "windows",
1213 all(target_os = "linux", target_env = "gnu"),
1214 target_os = "macos"
1215 )
1216 ),
1217 all(target_arch = "aarch64", target_os = "linux", target_env = "gnu"),
1218 all(target_arch = "s390x", target_os = "linux", target_env = "gnu")
1219 ),
1220 feature = "wasmtime"
1221))]
1222impl From<WasmValue> for wasmtime::Val {
1223 fn from(val: WasmValue) -> Self {
1224 match val {
1225 WasmValue::I32(v) => wasmtime::Val::I32(v),
1226 WasmValue::I64(v) => wasmtime::Val::I64(v),
1227 }
1228 }
1229}
1230
1231#[cfg(all(
1232 any(
1233 all(
1234 target_arch = "x86_64",
1235 any(
1236 target_os = "windows",
1237 all(target_os = "linux", target_env = "gnu"),
1238 target_os = "macos"
1239 )
1240 ),
1241 all(target_arch = "aarch64", target_os = "linux", target_env = "gnu"),
1242 all(target_arch = "s390x", target_os = "linux", target_env = "gnu")
1243 ),
1244 feature = "wasmtime"
1245))]
1246impl<'a> TryFrom<&'a wasmtime::Val> for WasmValue {
1247 type Error = UnsupportedTypeError;
1248
1249 fn try_from(val: &'a wasmtime::Val) -> Result<Self, Self::Error> {
1250 match val {
1251 wasmtime::Val::I32(v) => Ok(WasmValue::I32(*v)),
1252 wasmtime::Val::I64(v) => Ok(WasmValue::I64(*v)),
1253 _ => Err(UnsupportedTypeError),
1254 }
1255 }
1256}
1257
1258impl From<ValueType> for wasmi::core::ValType {
1259 fn from(ty: ValueType) -> wasmi::core::ValType {
1260 match ty {
1261 ValueType::I32 => wasmi::core::ValType::I32,
1262 ValueType::I64 => wasmi::core::ValType::I64,
1263 }
1264 }
1265}
1266
1267impl TryFrom<wasmi::core::ValType> for ValueType {
1268 type Error = UnsupportedTypeError;
1269
1270 fn try_from(val: wasmi::core::ValType) -> Result<Self, Self::Error> {
1271 match val {
1272 wasmi::core::ValType::I32 => Ok(ValueType::I32),
1273 wasmi::core::ValType::I64 => Ok(ValueType::I64),
1274 _ => Err(UnsupportedTypeError),
1275 }
1276 }
1277}
1278
1279#[cfg(all(
1280 any(
1281 all(
1282 target_arch = "x86_64",
1283 any(
1284 target_os = "windows",
1285 all(target_os = "linux", target_env = "gnu"),
1286 target_os = "macos"
1287 )
1288 ),
1289 all(target_arch = "aarch64", target_os = "linux", target_env = "gnu"),
1290 all(target_arch = "s390x", target_os = "linux", target_env = "gnu")
1291 ),
1292 feature = "wasmtime"
1293))]
1294impl TryFrom<wasmtime::ValType> for ValueType {
1295 type Error = UnsupportedTypeError;
1296
1297 fn try_from(val: wasmtime::ValType) -> Result<Self, Self::Error> {
1298 match val {
1299 wasmtime::ValType::I32 => Ok(ValueType::I32),
1300 wasmtime::ValType::I64 => Ok(ValueType::I64),
1301 _ => Err(UnsupportedTypeError),
1302 }
1303 }
1304}
1305
1306#[derive(Debug, derive_more::Display, derive_more::Error)]
1308pub struct UnsupportedTypeError;
1309
1310#[derive(Debug)]
1312pub enum ExecOutcome {
1313 Finished {
1318 return_value: Result<Option<WasmValue>, Trap>,
1320 },
1321
1322 Interrupted {
1332 id: usize,
1335
1336 params: Vec<WasmValue>,
1338 },
1339}
1340
1341#[derive(Debug, derive_more::Display, derive_more::Error, Clone)]
1343#[display("{_0}")]
1344pub struct Trap(#[error(not(source))] String);
1345
1346#[derive(Debug, derive_more::Display, derive_more::Error, Clone)]
1348pub enum NewErr {
1349 #[display("{_0}")]
1353 InvalidWasm(#[error(not(source))] String),
1354 #[display("{_0}")]
1358 Instantiation(#[error(not(source))] String),
1359 #[display("Unresolved function `{module_name}`:`{function}`")]
1361 UnresolvedFunctionImport {
1362 function: String,
1364 module_name: String,
1366 },
1367 #[display("Start function not supported")]
1370 StartFunctionNotSupported,
1372 #[display("If a \"memory\" symbol is provided, it must be a memory.")]
1374 MemoryIsntMemory,
1375 MemoryNotNamedMemory,
1377 NoMemory,
1379 TwoMemories,
1381 CouldntAllocateMemory,
1383 ImportTypeNotSupported,
1385}
1386
1387#[derive(Debug, Clone, derive_more::Display, derive_more::Error)]
1389pub enum StartErr {
1390 #[display("Function to start was not found.")]
1392 FunctionNotFound,
1393 #[display("Symbol to start is not a function.")]
1395 NotAFunction,
1396 #[display("Function to start uses unsupported signature.")]
1398 SignatureNotSupported,
1399 #[display("The types of the provided parameters don't match the signature.")]
1401 InvalidParameters,
1402}
1403
1404#[derive(Debug, derive_more::Display, derive_more::Error)]
1406#[display("Out of bounds when accessing virtual machine memory")]
1407pub struct OutOfBoundsError;
1408
1409#[derive(Debug, derive_more::Display, derive_more::Error)]
1411pub enum RunErr {
1412 #[display("State machine is poisoned")]
1414 Poisoned,
1415 #[display("Expected value of type {expected:?} but got {obtained:?} instead")]
1417 BadValueTy {
1418 expected: Option<ValueType>,
1420 obtained: Option<ValueType>,
1422 },
1423}
1424
1425#[derive(Debug, derive_more::Display, derive_more::Error)]
1427pub enum GlobalValueErr {
1428 NotFound,
1430 Invalid,
1432}