use super::operators::{Frame, OperatorValidator};
use crate::{BinaryReader, Result, ValType};
use crate::{FunctionBody, Operator, WasmFeatures, WasmModuleResources};
pub struct FuncValidator<T> {
validator: OperatorValidator,
resources: T,
index: u32,
}
impl<T: WasmModuleResources> FuncValidator<T> {
pub fn new(
index: u32,
ty: u32,
offset: usize,
resources: T,
features: &WasmFeatures,
) -> Result<FuncValidator<T>> {
Ok(FuncValidator {
validator: OperatorValidator::new_func(ty, offset, features, &resources)?,
resources,
index,
})
}
pub fn validate(&mut self, body: &FunctionBody<'_>) -> Result<()> {
let mut reader = body.get_binary_reader();
self.read_locals(&mut reader)?;
reader.allow_memarg64(self.validator.features.memory64);
while !reader.eof() {
reader.visit_operator(self)??;
}
self.finish(reader.original_position())
}
pub fn read_locals(&mut self, reader: &mut BinaryReader<'_>) -> Result<()> {
for _ in 0..reader.read_var_u32()? {
let offset = reader.original_position();
let cnt = reader.read_var_u32()?;
let ty = reader.read_val_type()?;
self.define_locals(offset, cnt, ty)?;
}
Ok(())
}
pub fn define_locals(&mut self, offset: usize, count: u32, ty: ValType) -> Result<()> {
self.validator.define_locals(offset, count, ty)
}
pub fn op(&mut self, offset: usize, operator: &Operator<'_>) -> Result<()> {
self.validator
.with_resources(&self.resources)
.visit_operator(offset, operator)
}
pub fn finish(&mut self, offset: usize) -> Result<()> {
self.validator.finish(offset)
}
pub fn resources(&self) -> &T {
&self.resources
}
pub fn index(&self) -> u32 {
self.index
}
pub fn len_locals(&self) -> u32 {
self.validator.locals.len_locals()
}
pub fn get_local_type(&self, index: u32) -> Option<ValType> {
self.validator.locals.get(index)
}
pub fn operand_stack_height(&self) -> u32 {
self.validator.operand_stack_height() as u32
}
pub fn get_operand_type(&self, index: usize) -> Option<Option<ValType>> {
self.validator.peek_operand_at(index)
}
pub fn control_stack_height(&self) -> u32 {
self.validator.control_stack_height() as u32
}
pub fn get_control_frame(&self, depth: usize) -> Option<&Frame> {
self.validator.get_frame(depth)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::WasmFuncType;
struct EmptyResources;
impl WasmModuleResources for EmptyResources {
type FuncType = EmptyFuncType;
fn table_at(&self, _at: u32) -> Option<crate::TableType> {
todo!()
}
fn memory_at(&self, _at: u32) -> Option<crate::MemoryType> {
todo!()
}
fn tag_at(&self, _at: u32) -> Option<&Self::FuncType> {
todo!()
}
fn global_at(&self, _at: u32) -> Option<crate::GlobalType> {
todo!()
}
fn func_type_at(&self, _type_idx: u32) -> Option<&Self::FuncType> {
Some(&EmptyFuncType)
}
fn type_of_function(&self, _func_idx: u32) -> Option<&Self::FuncType> {
todo!()
}
fn element_type_at(&self, _at: u32) -> Option<ValType> {
todo!()
}
fn element_count(&self) -> u32 {
todo!()
}
fn data_count(&self) -> Option<u32> {
todo!()
}
fn is_function_referenced(&self, _idx: u32) -> bool {
todo!()
}
}
struct EmptyFuncType;
impl WasmFuncType for EmptyFuncType {
fn len_inputs(&self) -> usize {
0
}
fn len_outputs(&self) -> usize {
0
}
fn input_at(&self, _at: u32) -> Option<ValType> {
todo!()
}
fn output_at(&self, _at: u32) -> Option<ValType> {
todo!()
}
}
#[test]
fn operand_stack_height() {
let mut v = FuncValidator::new(0, 0, 0, &EmptyResources, &Default::default()).unwrap();
assert_eq!(v.operand_stack_height(), 0);
assert!(v.op(0, &Operator::I32Const { value: 0 }).is_ok());
assert_eq!(v.operand_stack_height(), 1);
assert!(v
.op(
1,
&Operator::Block {
ty: crate::BlockType::Empty
}
)
.is_ok());
assert_eq!(v.operand_stack_height(), 1);
assert!(v.op(2, &Operator::I32Const { value: 99 }).is_ok());
assert_eq!(v.operand_stack_height(), 2);
}
}
use crate::{BlockType, BrTable, Ieee32, Ieee64, MemArg, VisitOperator, V128};
macro_rules! define_visit_operator {
($($op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => {
$(
fn $visit(&mut self, offset: usize $($(,$arg: $argty)*)?) -> Result<()> {
self.validator.with_resources(&self.resources)
.$visit(offset $($(,$arg)*)?)
}
)*
}
}
#[allow(unused_variables)]
impl<'a, T> VisitOperator<'a> for FuncValidator<T>
where
T: WasmModuleResources,
{
type Output = Result<()>;
for_each_operator!(define_visit_operator);
}