use wasmparser::{
for_each_visit_operator, FrameKind, FrameStack, FuncValidator, ValidatorResources,
VisitOperator,
};
use super::control::BlockKind;
use super::{wp_err, Translator};
use crate::Result;
pub(super) struct ValidateThenLower<'a, 'v> {
pub validator: &'v mut FuncValidator<ValidatorResources>,
pub translator: &'v mut Translator<'a>,
pub offset: usize,
}
macro_rules! lower_nullary {
($($visit:ident => $helper:ident $variant:ident;)*) => {
$(
pub(in crate::module::compile) fn $visit(&mut self) -> $crate::Result<()> {
if self.reachable {
self.$helper($crate::module::op::Op::$variant);
}
Ok(())
}
)*
};
}
pub(in crate::module::compile) use lower_nullary;
macro_rules! lower_memarg {
($($visit:ident => $helper:ident $variant:ident;)*) => {
$(
pub(in crate::module::compile) fn $visit(
&mut self,
memarg: wasmparser::MemArg,
) -> $crate::Result<()> {
if self.reachable {
let m = self.memarg(memarg);
self.$helper($crate::module::op::Op::$variant(m));
}
Ok(())
}
)*
};
}
pub(in crate::module::compile) use lower_memarg;
macro_rules! validate_then_lower {
($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*) )*) => {
$(
fn $visit(&mut self $($(, $arg: $argty)*)?) -> Result<()> {
self.validator
.visitor(self.offset)
.$visit($($($arg.clone()),*)?)
.map_err(wp_err)?;
self.translator.cur_offset = self.offset as u32;
self.translator.$visit($($($arg),*)?)
}
)*
};
}
impl FrameStack for ValidateThenLower<'_, '_> {
fn current_frame(&self) -> Option<FrameKind> {
Some(match self.translator.open_frame_kind()? {
BlockKind::Block => FrameKind::Block,
BlockKind::Loop => FrameKind::Loop,
BlockKind::If => FrameKind::If,
BlockKind::TryTable => FrameKind::TryTable,
})
}
}
impl<'a> VisitOperator<'a> for ValidateThenLower<'a, '_> {
type Output = Result<()>;
#[cfg(feature = "simd")]
fn simd_visitor(
&mut self,
) -> Option<&mut dyn wasmparser::VisitSimdOperator<'a, Output = Self::Output>> {
Some(self)
}
for_each_visit_operator!(validate_then_lower);
}
macro_rules! unsupported_lowering {
($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*) )*) => {
$( unsupported_lowering!(@one @$proposal $op $({ $($arg: $argty),* })? => $visit); )*
};
(@one @mvp $($rest:tt)*) => {};
(@one @sign_extension $($rest:tt)*) => {};
(@one @saturating_float_to_int $($rest:tt)*) => {};
(@one @bulk_memory $($rest:tt)*) => {};
(@one @reference_types $($rest:tt)*) => {};
(@one @tail_call $($rest:tt)*) => {};
(@one @function_references $($rest:tt)*) => {};
(@one @gc $($rest:tt)*) => {};
(@one @exceptions $($rest:tt)*) => {};
(@one @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident) => {
pub(in crate::module::compile) fn $visit(&mut self $($(, $arg: $argty)*)?) -> $crate::Result<()> {
Err($crate::Error::msg(concat!("unsupported operator: ", stringify!($visit))))
}
};
}
impl Translator<'_> {
for_each_visit_operator!(unsupported_lowering);
}