wasm/execution/
value.rs

1use alloc::vec;
2use alloc::vec::Vec;
3use core::fmt::{Debug, Display};
4use core::ops::{Add, Div, Mul, Sub};
5use core::{f32, f64};
6
7use crate::core::reader::types::{NumType, ValType};
8use crate::execution::assert_validated::UnwrapValidatedExt;
9use crate::{unreachable_validated, Error, RefType, Result};
10
11#[derive(Clone, Debug, Copy, PartialOrd)]
12pub struct F32(pub f32);
13
14impl Display for F32 {
15    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
16        write!(f, "{}", self.0)
17    }
18}
19
20impl PartialEq for F32 {
21    fn eq(&self, other: &Self) -> bool {
22        self.0.eq(&other.0)
23    }
24}
25
26impl Add for F32 {
27    type Output = Self;
28    fn add(self, rhs: Self) -> Self::Output {
29        Self(self.0 + rhs.0)
30    }
31}
32
33impl Sub for F32 {
34    type Output = Self;
35    fn sub(self, rhs: Self) -> Self::Output {
36        Self(self.0 - rhs.0)
37    }
38}
39
40impl Mul for F32 {
41    type Output = Self;
42    fn mul(self, rhs: Self) -> Self::Output {
43        Self(self.0 * rhs.0)
44    }
45}
46
47impl Div for F32 {
48    type Output = Self;
49    fn div(self, rhs: Self) -> Self::Output {
50        Self(self.0 / rhs.0)
51    }
52}
53
54impl F32 {
55    pub fn abs(&self) -> Self {
56        Self(libm::fabsf(self.0))
57    }
58    pub fn neg(&self) -> Self {
59        Self(-self.0)
60    }
61    pub fn ceil(&self) -> Self {
62        if self.0.is_nan() {
63            return Self(f32::NAN);
64        }
65        Self(libm::ceilf(self.0))
66    }
67    pub fn floor(&self) -> Self {
68        if self.0.is_nan() {
69            return Self(f32::NAN);
70        }
71        Self(libm::floorf(self.0))
72    }
73    pub fn trunc(&self) -> Self {
74        if self.0.is_nan() {
75            return Self(f32::NAN);
76        }
77        Self(libm::truncf(self.0))
78    }
79    pub fn nearest(&self) -> Self {
80        if self.0.is_nan() {
81            return Self(f32::NAN);
82        }
83        Self(libm::rintf(self.0))
84    }
85    pub fn round(&self) -> Self {
86        Self(libm::roundf(self.0))
87    }
88    pub fn sqrt(&self) -> Self {
89        Self(libm::sqrtf(self.0))
90    }
91
92    pub fn min(&self, rhs: Self) -> Self {
93        Self(if self.0.is_nan() || rhs.0.is_nan() {
94            f32::NAN
95        } else if self.0 == 0.0 && rhs.0 == 0.0 {
96            if self.to_bits() >> 31 == 1 {
97                self.0
98            } else {
99                rhs.0
100            }
101        } else {
102            self.0.min(rhs.0)
103        })
104    }
105    pub fn max(&self, rhs: Self) -> Self {
106        Self(if self.0.is_nan() || rhs.0.is_nan() {
107            f32::NAN
108        } else if self.0 == 0.0 && rhs.0 == 0.0 {
109            if self.to_bits() >> 31 == 1 {
110                rhs.0
111            } else {
112                self.0
113            }
114        } else {
115            self.0.max(rhs.0)
116        })
117    }
118    pub fn copysign(&self, rhs: Self) -> Self {
119        Self(libm::copysignf(self.0, rhs.0))
120    }
121    pub fn from_bits(other: u32) -> Self {
122        Self(f32::from_bits(other))
123    }
124    pub fn is_nan(&self) -> bool {
125        self.0.is_nan()
126    }
127    pub fn is_infinity(&self) -> bool {
128        self.0.is_infinite()
129    }
130    pub fn is_negative_infinity(&self) -> bool {
131        self.0.is_infinite() && self.0 < 0.0
132    }
133
134    pub fn as_i32(&self) -> i32 {
135        self.0 as i32
136    }
137    pub fn as_u32(&self) -> u32 {
138        self.0 as u32
139    }
140    pub fn as_i64(&self) -> i64 {
141        self.0 as i64
142    }
143    pub fn as_u64(&self) -> u64 {
144        self.0 as u64
145    }
146    pub fn as_f32(&self) -> F64 {
147        F64(self.0 as f64)
148    }
149    pub fn reinterpret_as_i32(&self) -> i32 {
150        self.0.to_bits() as i32
151    }
152    pub fn to_bits(&self) -> u32 {
153        self.0.to_bits()
154    }
155}
156
157#[derive(Clone, Debug, Copy, PartialOrd)]
158pub struct F64(pub f64);
159
160impl Display for F64 {
161    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
162        write!(f, "{}", self.0)
163    }
164}
165
166impl PartialEq for F64 {
167    fn eq(&self, other: &Self) -> bool {
168        self.0.eq(&other.0)
169    }
170}
171
172impl Add for F64 {
173    type Output = Self;
174    fn add(self, rhs: Self) -> Self::Output {
175        Self(self.0 + rhs.0)
176    }
177}
178
179impl Sub for F64 {
180    type Output = Self;
181    fn sub(self, rhs: Self) -> Self::Output {
182        Self(self.0 - rhs.0)
183    }
184}
185
186impl Mul for F64 {
187    type Output = Self;
188    fn mul(self, rhs: Self) -> Self::Output {
189        Self(self.0 * rhs.0)
190    }
191}
192
193impl Div for F64 {
194    type Output = Self;
195    fn div(self, rhs: Self) -> Self::Output {
196        Self(self.0 / rhs.0)
197    }
198}
199
200impl F64 {
201    pub fn abs(&self) -> Self {
202        Self(libm::fabs(self.0))
203    }
204    pub fn neg(&self) -> Self {
205        Self(-self.0)
206    }
207    pub fn ceil(&self) -> Self {
208        if self.0.is_nan() {
209            return Self(f64::NAN);
210        }
211        Self(libm::ceil(self.0))
212    }
213    pub fn floor(&self) -> Self {
214        if self.0.is_nan() {
215            return Self(f64::NAN);
216        }
217        Self(libm::floor(self.0))
218    }
219    pub fn trunc(&self) -> Self {
220        if self.0.is_nan() {
221            return Self(f64::NAN);
222        }
223        Self(libm::trunc(self.0))
224    }
225    pub fn nearest(&self) -> Self {
226        if self.0.is_nan() {
227            return Self(f64::NAN);
228        }
229        Self(libm::rint(self.0))
230    }
231    pub fn round(&self) -> Self {
232        Self(libm::round(self.0))
233    }
234    pub fn sqrt(&self) -> Self {
235        Self(libm::sqrt(self.0))
236    }
237
238    pub fn min(&self, rhs: Self) -> Self {
239        Self(if self.0.is_nan() || rhs.0.is_nan() {
240            f64::NAN
241        } else if self.0 == 0.0 && rhs.0 == 0.0 {
242            if self.to_bits() >> 63 == 1 {
243                self.0
244            } else {
245                rhs.0
246            }
247        } else {
248            self.0.min(rhs.0)
249        })
250    }
251    pub fn max(&self, rhs: Self) -> Self {
252        Self(if self.0.is_nan() || rhs.0.is_nan() {
253            f64::NAN
254        } else if self.0 == 0.0 && rhs.0 == 0.0 {
255            if self.to_bits() >> 63 == 1 {
256                rhs.0
257            } else {
258                self.0
259            }
260        } else {
261            self.0.max(rhs.0)
262        })
263    }
264    pub fn copysign(&self, rhs: Self) -> Self {
265        Self(libm::copysign(self.0, rhs.0))
266    }
267
268    pub fn from_bits(other: u64) -> Self {
269        Self(f64::from_bits(other))
270    }
271    pub fn is_nan(&self) -> bool {
272        self.0.is_nan()
273    }
274    pub fn is_infinity(&self) -> bool {
275        self.0.is_infinite()
276    }
277    pub fn is_negative_infinity(&self) -> bool {
278        self.0.is_infinite() && self.0 < 0.0
279    }
280
281    pub fn as_i32(&self) -> i32 {
282        self.0 as i32
283    }
284    pub fn as_u32(&self) -> u32 {
285        self.0 as u32
286    }
287    pub fn as_i64(&self) -> i64 {
288        self.0 as i64
289    }
290    pub fn as_u64(&self) -> u64 {
291        self.0 as u64
292    }
293    pub fn as_f32(&self) -> F32 {
294        F32(self.0 as f32)
295    }
296    pub fn reinterpret_as_i64(&self) -> i64 {
297        self.0.to_bits() as i64
298    }
299    pub fn to_bits(&self) -> u64 {
300        self.0.to_bits()
301    }
302}
303
304/// A value at runtime. This is essentially a duplicate of [ValType] just with additional values.
305///
306/// See <https://webassembly.github.io/spec/core/exec/runtime.html#values>
307// TODO implement missing variants
308#[derive(Clone, Copy, Debug, PartialEq)]
309pub enum Value {
310    I32(u32),
311    I64(u64),
312    F32(F32),
313    F64(F64),
314    // F64,
315    // V128,
316    Ref(Ref),
317}
318
319#[derive(Clone, Copy, Debug, PartialEq)]
320pub enum Ref {
321    Func(FuncAddr),
322    Extern(ExternAddr),
323}
324
325impl Ref {
326    pub fn default_from_ref_type(rref: RefType) -> Self {
327        match rref {
328            RefType::ExternRef => Self::Extern(ExternAddr::default()),
329            RefType::FuncRef => Self::Func(FuncAddr::default()),
330        }
331    }
332
333    pub fn is_null(&self) -> bool {
334        match self {
335            Self::Extern(extern_addr) => extern_addr.addr.is_none(),
336            Self::Func(func_addr) => func_addr.addr.is_none(),
337        }
338    }
339
340    pub fn is_specific_func(&self, func_id: u32) -> bool {
341        match self {
342            Self::Func(func_addr) => func_addr.addr == Some(func_id as usize),
343            _ => unreachable!(),
344        }
345    }
346}
347
348impl Display for Ref {
349    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
350        match self {
351            Ref::Func(func_addr) => write!(f, "FuncRef({:?})", func_addr),
352            Ref::Extern(extern_addr) => write!(f, "ExternRef({:?})", extern_addr),
353        }
354    }
355}
356
357/// Represents the address of a function within a WebAssembly module.
358///
359/// Functions in WebAssembly modules can be either:
360/// - **Defined**: Declared and implemented within the module.
361/// - **Imported**: Declared in the module but implemented externally.
362///
363/// [`FuncAddr`] provides a unified representation for both types. Internally,
364/// the address corresponds to an index in a combined function namespace,
365/// typically represented as a vector.
366#[derive(Clone, Copy, PartialEq)]
367pub struct FuncAddr {
368    pub addr: Option<usize>,
369}
370
371impl Debug for FuncAddr {
372    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
373        match self.addr.is_none() {
374            false => write!(f, "FuncAddr {{\n\taddr: {}\n}}", self.addr.unwrap()),
375            true => write!(f, "FuncAddr {{ NULL }}"),
376        }
377    }
378}
379
380impl FuncAddr {
381    pub fn new(addr: Option<usize>) -> Self {
382        match addr {
383            None => Self::null(),
384            Some(u) => Self { addr: Some(u) },
385        }
386    }
387    pub fn null() -> Self {
388        Self { addr: None }
389    }
390    pub fn is_null(&self) -> bool {
391        self.addr.is_none()
392    }
393}
394
395impl Default for FuncAddr {
396    fn default() -> Self {
397        Self::null()
398    }
399}
400
401/// Represents the address of an external reference in the interpreter.
402///
403/// External references are managed at the interpreter level and are not part of
404/// the WebAssembly module itself. They are typically used to refer to host
405/// functions or objects that interact with the module.
406///
407/// Internally, [`ExternAddr`] corresponds to an index in a linear vector,
408/// enabling dynamic storage and retrieval of external values.
409#[derive(Clone, Copy, Debug, PartialEq)]
410pub struct ExternAddr {
411    pub addr: Option<usize>,
412}
413
414impl ExternAddr {
415    pub fn new(addr: Option<usize>) -> Self {
416        match addr {
417            None => Self::null(),
418            Some(u) => Self { addr: Some(u) },
419        }
420    }
421    pub fn null() -> Self {
422        Self { addr: None }
423    }
424}
425
426impl Default for ExternAddr {
427    fn default() -> Self {
428        Self::null()
429    }
430}
431
432#[derive(Clone, Copy, Debug, PartialEq)]
433pub enum RefValueTy {
434    Func,
435    Extern,
436}
437
438impl Value {
439    pub fn default_from_ty(ty: ValType) -> Self {
440        match ty {
441            ValType::NumType(NumType::I32) => Self::I32(0),
442            ValType::NumType(NumType::I64) => Self::I64(0),
443            ValType::NumType(NumType::F32) => Self::F32(F32(0.0)),
444            ValType::NumType(NumType::F64) => Self::F64(F64(0.0_f64)),
445            ValType::RefType(RefType::ExternRef) => Self::Ref(Ref::Extern(ExternAddr::null())),
446            ValType::RefType(RefType::FuncRef) => Self::Ref(Ref::Func(FuncAddr::null())),
447            other => {
448                todo!("cannot determine type for {other:?} because this value is not supported yet")
449            }
450        }
451    }
452
453    pub fn to_ty(&self) -> ValType {
454        match self {
455            Value::I32(_) => ValType::NumType(NumType::I32),
456            Value::I64(_) => ValType::NumType(NumType::I64),
457            Value::F32(_) => ValType::NumType(NumType::F32),
458            Value::F64(_) => ValType::NumType(NumType::F64),
459            Value::Ref(rref) => match rref {
460                Ref::Extern(_) => ValType::RefType(RefType::ExternRef),
461                Ref::Func(_) => ValType::RefType(RefType::FuncRef),
462            },
463        }
464    }
465}
466
467// ------------------------------ INTEROP VALUE -------------------------------------
468
469/// An [InteropValue] is a Rust types that can be converted into a WASM [Value].
470/// This trait is intended to simplify translation between Rust values and WASM values and thus is not used internally.
471pub trait InteropValue: Copy + Debug + PartialEq {
472    // Sadly we cannot use `SIZE` to return fixed-sized arrays because this is still unstable.
473    // See feature(generic_const_exprs)
474    const TY: ValType;
475    #[allow(warnings)]
476    fn into_value(self) -> Value;
477    #[allow(warnings)]
478    fn from_value(value: Value) -> Self;
479}
480
481/// An [InteropValueList] is an iterable list of [InteropValue]s (i.e. Rust types that can be converted into WASM [Value]s).
482pub trait InteropValueList {
483    const TYS: &'static [ValType];
484    #[allow(warnings)]
485    fn into_values(self) -> Vec<Value>;
486    #[allow(warnings)]
487    fn from_values(values: impl Iterator<Item = Value>) -> Self;
488}
489
490impl InteropValue for u32 {
491    const TY: ValType = ValType::NumType(NumType::I32);
492    #[allow(warnings)]
493    fn into_value(self) -> Value {
494        Value::I32(self)
495    }
496
497    #[allow(warnings)]
498    fn from_value(value: Value) -> Self {
499        match value {
500            Value::I32(i) => i,
501            _ => unreachable_validated!(),
502        }
503    }
504}
505
506impl InteropValue for i32 {
507    const TY: ValType = ValType::NumType(NumType::I32);
508
509    #[allow(warnings)]
510    fn into_value(self) -> Value {
511        Value::I32(u32::from_le_bytes(self.to_le_bytes()))
512    }
513
514    #[allow(warnings)]
515    fn from_value(value: Value) -> Self {
516        match value {
517            Value::I32(i) => i32::from_le_bytes(i.to_le_bytes()),
518            _ => unreachable_validated!(),
519        }
520    }
521}
522
523impl InteropValue for u64 {
524    const TY: ValType = ValType::NumType(NumType::I64);
525
526    #[allow(warnings)]
527    fn into_value(self) -> Value {
528        Value::I64(self)
529    }
530
531    #[allow(warnings)]
532    fn from_value(value: Value) -> Self {
533        match value {
534            Value::I64(i) => i,
535            _ => unreachable_validated!(),
536        }
537    }
538}
539
540impl InteropValue for i64 {
541    const TY: ValType = ValType::NumType(NumType::I64);
542
543    #[allow(warnings)]
544    fn into_value(self) -> Value {
545        Value::I64(u64::from_le_bytes(self.to_le_bytes()))
546    }
547
548    #[allow(warnings)]
549    fn from_value(value: Value) -> Self {
550        match value {
551            Value::I64(i) => i64::from_le_bytes(i.to_le_bytes()),
552            _ => unreachable_validated!(),
553        }
554    }
555}
556
557impl InteropValue for F32 {
558    const TY: ValType = ValType::NumType(NumType::F32);
559
560    #[allow(warnings)]
561    fn into_value(self) -> Value {
562        Value::F32(F32(f32::from_le_bytes(self.0.to_le_bytes())))
563    }
564
565    #[allow(warnings)]
566    fn from_value(value: Value) -> Self {
567        match value {
568            Value::F32(f) => F32(f32::from_le_bytes(f.0.to_le_bytes())),
569            _ => unreachable_validated!(),
570        }
571    }
572}
573
574impl InteropValue for f32 {
575    const TY: ValType = ValType::NumType(NumType::F32);
576
577    #[allow(warnings)]
578    fn into_value(self) -> Value {
579        Value::F32(F32(f32::from_le_bytes(self.to_le_bytes())))
580    }
581
582    #[allow(warnings)]
583    fn from_value(value: Value) -> Self {
584        match value {
585            Value::F32(f) => f32::from_le_bytes(f.0.to_le_bytes()),
586            _ => unreachable_validated!(),
587        }
588    }
589}
590
591impl InteropValue for F64 {
592    const TY: ValType = ValType::NumType(NumType::F64);
593
594    #[allow(warnings)]
595    fn into_value(self) -> Value {
596        Value::F64(F64(f64::from_le_bytes(self.0.to_le_bytes())))
597    }
598
599    #[allow(warnings)]
600    fn from_value(value: Value) -> Self {
601        match value {
602            Value::F64(f) => F64(f64::from_le_bytes(f.0.to_le_bytes())),
603            _ => unreachable_validated!(),
604        }
605    }
606}
607
608impl InteropValue for f64 {
609    const TY: ValType = ValType::NumType(NumType::F64);
610
611    #[allow(warnings)]
612    fn into_value(self) -> Value {
613        Value::F64(F64(f64::from_le_bytes(self.to_le_bytes())))
614    }
615
616    #[allow(warnings)]
617    fn from_value(value: Value) -> Self {
618        match value {
619            Value::F64(f) => f64::from_le_bytes(f.0.to_le_bytes()),
620            _ => unreachable_validated!(),
621        }
622    }
623}
624
625#[derive(PartialEq, Debug, Copy, Clone)]
626pub struct FuncRefForInteropValue {
627    rref: Ref,
628}
629
630impl FuncRefForInteropValue {
631    pub fn new(rref: Ref) -> Result<Self> {
632        match rref {
633            Ref::Extern(_) => Err(Error::WrongRefTypeForInteropValue(
634                RefType::ExternRef,
635                RefType::FuncRef,
636            )),
637            Ref::Func(_) => Ok(Self { rref }),
638        }
639    }
640
641    pub fn get_ref(&self) -> Ref {
642        self.rref
643    }
644}
645
646impl InteropValue for FuncRefForInteropValue {
647    const TY: ValType = ValType::RefType(RefType::FuncRef);
648
649    #[allow(warnings)]
650    fn into_value(self) -> Value {
651        Value::Ref(self.rref)
652    }
653
654    #[allow(warnings)]
655    fn from_value(value: Value) -> Self {
656        match value {
657            Value::Ref(rref) => unsafe { FuncRefForInteropValue::new(rref).unwrap_unchecked() },
658            _ => unreachable_validated!(),
659        }
660    }
661}
662
663impl InteropValueList for () {
664    const TYS: &'static [ValType] = &[];
665
666    #[allow(warnings)]
667    fn into_values(self) -> Vec<Value> {
668        Vec::new()
669    }
670
671    #[allow(warnings)]
672    fn from_values(_values: impl Iterator<Item = Value>) -> Self {}
673}
674
675impl<A: InteropValue> InteropValueList for A {
676    const TYS: &'static [ValType] = &[A::TY];
677
678    #[allow(warnings)]
679    fn into_values(self) -> Vec<Value> {
680        vec![self.into_value()]
681    }
682
683    #[allow(warnings)]
684    fn from_values(mut values: impl Iterator<Item = Value>) -> Self {
685        A::from_value(values.next().unwrap_validated())
686    }
687}
688
689impl<A: InteropValue> InteropValueList for (A,) {
690    const TYS: &'static [ValType] = &[A::TY];
691    #[allow(warnings)]
692    fn into_values(self) -> Vec<Value> {
693        vec![self.0.into_value()]
694    }
695
696    #[allow(warnings)]
697    fn from_values(mut values: impl Iterator<Item = Value>) -> Self {
698        (A::from_value(values.next().unwrap_validated()),)
699    }
700}
701
702impl<A: InteropValue, B: InteropValue> InteropValueList for (A, B) {
703    const TYS: &'static [ValType] = &[A::TY, B::TY];
704    #[allow(warnings)]
705    fn into_values(self) -> Vec<Value> {
706        vec![self.0.into_value(), self.1.into_value()]
707    }
708
709    #[allow(warnings)]
710    fn from_values(mut values: impl Iterator<Item = Value>) -> Self {
711        (
712            A::from_value(values.next().unwrap_validated()),
713            B::from_value(values.next().unwrap_validated()),
714        )
715    }
716}
717
718impl<A: InteropValue, B: InteropValue, C: InteropValue> InteropValueList for (A, B, C) {
719    const TYS: &'static [ValType] = &[A::TY, B::TY, C::TY];
720    #[allow(warnings)]
721    fn into_values(self) -> Vec<Value> {
722        vec![
723            self.0.into_value(),
724            self.1.into_value(),
725            self.2.into_value(),
726        ]
727    }
728
729    #[allow(warnings)]
730    fn from_values(mut values: impl Iterator<Item = Value>) -> Self {
731        (
732            A::from_value(values.next().unwrap_validated()),
733            B::from_value(values.next().unwrap_validated()),
734            C::from_value(values.next().unwrap_validated()),
735        )
736    }
737}
738
739// TODO: don't let this like this, use a macro
740impl From<f32> for Value {
741    fn from(x: f32) -> Self {
742        F32(x).into_value()
743    }
744}
745
746impl From<Value> for f32 {
747    fn from(value: Value) -> Self {
748        F32::from(value).0
749    }
750}
751
752// TODO: don't let this like this, use a macro
753impl From<f64> for Value {
754    fn from(x: f64) -> Self {
755        F64(x).into_value()
756    }
757}
758
759impl From<Value> for f64 {
760    fn from(value: Value) -> Self {
761        F64::from(value).0
762    }
763}
764
765/// Stupid From and Into implementations, because Rust's orphan rules won't let me define a generic impl:
766macro_rules! impl_value_conversion {
767    ($ty:ty) => {
768        impl From<$ty> for Value {
769            fn from(x: $ty) -> Self {
770                x.into_value()
771            }
772        }
773        impl From<Value> for $ty {
774            fn from(value: Value) -> Self {
775                <$ty>::from_value(value)
776            }
777        }
778    };
779}
780
781impl_value_conversion!(u32);
782impl_value_conversion!(i32);
783impl_value_conversion!(u64);
784impl_value_conversion!(i64);
785impl_value_conversion!(F32);
786impl_value_conversion!(F64);
787
788impl From<Ref> for Value {
789    fn from(value: Ref) -> Self {
790        Self::Ref(value)
791    }
792}
793
794impl From<Value> for Ref {
795    fn from(value: Value) -> Self {
796        match value {
797            Value::Ref(rref) => rref,
798            _ => unreachable!(),
799        }
800    }
801}