wasmi 2.0.0-beta.10

WebAssembly interpreter
Documentation
use crate::{
    Error,
    engine::{CompiledFuncEntry, WasmOperator, WasmTranslator, translator::FuncTranslator},
};
use wasmparser::{VisitOperator, WasmFeatures};

macro_rules! impl_visit_operator_for_fuel_metering {
    ( @mvp $($rest:tt)* ) => {
        impl_visit_operator_for_fuel_metering!(@@supported $($rest)*);
    };
    ( @sign_extension $($rest:tt)* ) => {
        impl_visit_operator_for_fuel_metering!(@@supported $($rest)*);
    };
    ( @saturating_float_to_int $($rest:tt)* ) => {
        impl_visit_operator_for_fuel_metering!(@@supported $($rest)*);
    };
    ( @bulk_memory $($rest:tt)* ) => {
        impl_visit_operator_for_fuel_metering!(@@supported $($rest)*);
    };
    ( @reference_types $($rest:tt)* ) => {
        impl_visit_operator_for_fuel_metering!(@@supported $($rest)*);
    };
    ( @tail_call $($rest:tt)* ) => {
        impl_visit_operator_for_fuel_metering!(@@supported $($rest)*);
    };
    ( @wide_arithmetic $($rest:tt)* ) => {
        impl_visit_operator_for_fuel_metering!(@@supported $($rest)*);
    };
    ( @simd $($rest:tt)* ) => {
        impl_visit_operator_for_fuel_metering!(@@supported $($rest)*);
    };
    ( @relaxed_simd $($rest:tt)* ) => {
        impl_visit_operator_for_fuel_metering!(@@supported $($rest)*);
    };
    ( @@supported $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident $_ann:tt $($rest:tt)* ) => {
        // Implementation for supported Wasm operators.
        #[inline]
        fn $visit(&mut self $($(, $arg: $argty)*)?) -> Self::Output {
            // Apply fuel metering and forward to the underlying func translator's visit implementation.
            self.0.bump_fuel_for_operator(WasmOperator::$op)?;
            self.0.$visit( $( $($arg),* )? )
        }
        impl_visit_operator_for_fuel_metering!($($rest)*);
    };
    ( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident $_ann:tt $($rest:tt)* ) => {
        // Fallback implementation for unsupported Wasm operators.
        #[inline]
        fn $visit(&mut self $($(, $arg: $argty)*)?) -> Self::Output {
            // Simply forward to the underlying func translator's visit implementation.
            self.0.$visit( $( $($arg),* )? )
        }
        impl_visit_operator_for_fuel_metering!($($rest)*);
    };
    () => {};
}

/// Wrapper around [`FuncTranslator`] to handle fuel metering.
#[derive(Debug)]
pub struct FuelMeteringFuncTranslator(FuncTranslator);

impl From<FuncTranslator> for FuelMeteringFuncTranslator {
    fn from(translator: FuncTranslator) -> Self {
        Self(translator)
    }
}

impl<'a> VisitOperator<'a> for FuelMeteringFuncTranslator {
    type Output = Result<(), Error>;

    #[cfg(feature = "simd")]
    fn simd_visitor(
        &mut self,
    ) -> Option<&mut dyn wasmparser::VisitSimdOperator<'a, Output = Self::Output>> {
        Some(self)
    }

    wasmparser::for_each_visit_operator!(impl_visit_operator_for_fuel_metering);
}

#[cfg(feature = "simd")]
impl<'a> wasmparser::VisitSimdOperator<'a> for FuelMeteringFuncTranslator {
    wasmparser::for_each_visit_simd_operator!(impl_visit_operator_for_fuel_metering);
}

impl<'a> WasmTranslator<'a> for FuelMeteringFuncTranslator {
    type Allocations = <FuncTranslator as WasmTranslator<'a>>::Allocations;

    #[inline]
    fn setup(&mut self, bytes: &[u8]) -> Result<bool, Error> {
        self.0.setup(bytes)
    }

    #[inline]
    fn features(&self) -> WasmFeatures {
        self.0.features()
    }

    #[inline]
    fn translate_locals(
        &mut self,
        amount: u32,
        value_type: wasmparser::ValType,
    ) -> Result<(), Error> {
        self.0.translate_locals(amount, value_type)
    }

    #[inline]
    fn finish_translate_locals(&mut self) -> Result<(), Error> {
        self.0.finish_translate_locals()
    }

    #[inline]
    fn update_pos(&mut self, pos: usize) {
        self.0.update_pos(pos)
    }

    #[inline]
    fn finish(self, finalize: impl FnOnce(CompiledFuncEntry)) -> Result<Self::Allocations, Error> {
        self.0.finish(finalize)
    }
}