Skip to content

Commit

Permalink
impl WasmTranslator for ValidatingFuncTranslator
Browse files Browse the repository at this point in the history
  • Loading branch information
Robbepop committed Dec 3, 2023
1 parent 22d6f76 commit 9778667
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 70 deletions.
2 changes: 1 addition & 1 deletion crates/wasmi/src/engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub(crate) use self::{
executor::Stack,
func_args::{FuncFinished, FuncParams, FuncResults},
func_types::DedupFuncType,
translator::FuncTranslatorAllocations,
translator::{FuncTranslatorAllocations, ReusableAllocations, WasmTranslator},
};
use crate::{core::Trap, Func, FuncType, StoreContextMut};
use alloc::{sync::Arc, vec::Vec};
Expand Down
92 changes: 52 additions & 40 deletions crates/wasmi/src/engine/translator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,13 @@ use crate::{
config::FuelCosts,
CompiledFunc,
},
module::{BlockType, FuncIdx, FuncTypeIdx, ModuleResources, ReusableAllocations},
module::{BlockType, FuncIdx, FuncTypeIdx, ModuleResources},
Engine,
FuncType,
};
use alloc::vec::Vec;
use wasmi_core::{TrapCode, UntypedValue, ValueType};
use wasmparser::{BinaryReaderError, MemArg, VisitOperator};
use wasmparser::{BinaryReaderError, FuncValidatorAllocations, MemArg, VisitOperator};

/// Reusable allocations of a [`FuncTranslator`].
#[derive(Debug, Default)]
Expand Down Expand Up @@ -99,8 +99,25 @@ pub struct ValidatingFuncTranslator<'parser> {
translator: FuncTranslator<'parser>,
}

/// Reusable heap allocations for function validation and translation.
pub struct ReusableAllocations {
pub translation: FuncTranslatorAllocations,
pub validation: FuncValidatorAllocations,
}

impl Default for ReusableAllocations {
fn default() -> Self {
let translation = FuncTranslatorAllocations::default();
let validation = FuncValidatorAllocations::default();
Self {
translation,
validation,
}
}
}

/// A WebAssembly (Wasm) function translator.
pub trait WasmTranslator: for<'a> VisitOperator<'a> {
pub trait WasmTranslator<'parser>: VisitOperator<'parser> {
/// The reusable allocations required by the [`WasmTranslator`].
///
/// # Note
Expand Down Expand Up @@ -165,43 +182,53 @@ impl<'parser> ValidatingFuncTranslator<'parser> {
})
}

/// Translates the given local variables for the translated function.
pub fn translate_locals(
/// Returns the current position within the Wasm binary while parsing operators.
fn current_pos(&self) -> usize {
self.pos
}

/// Translates into `wasmi` bytecode if the current code path is reachable.
fn validate_then_translate<V, T>(
&mut self,
validate: V,
translate: T,
) -> Result<(), TranslationError>
where
V: FnOnce(&mut FuncValidator) -> Result<(), BinaryReaderError>,
T: FnOnce(&mut FuncTranslator<'parser>) -> Result<(), TranslationError>,
{
validate(&mut self.validator)?;
translate(&mut self.translator)?;
Ok(())
}
}

impl<'parser> WasmTranslator<'parser> for ValidatingFuncTranslator<'parser> {
type Allocations = ReusableAllocations;

fn translate_locals(
&mut self,
offset: usize,
amount: u32,
value_type: wasmparser::ValType,
) -> Result<(), TranslationError> {
self.validator.define_locals(offset, amount, value_type)?;
self.validator
.define_locals(self.current_pos(), amount, value_type)?;
self.translator.register_locals(amount)?;
Ok(())
}

/// This informs the [`ValidatingFuncTranslator`] that the function header translation is finished.
///
/// # Note
///
/// This was introduced to properly calculate the fuel costs for all local variables
/// and function parameters. After this function call no more locals and parameters may
/// be added to this function translation.
pub fn finish_translate_locals(&mut self) -> Result<(), TranslationError> {
fn finish_translate_locals(&mut self) -> Result<(), TranslationError> {
self.translator.finish_translate_locals()?;
Ok(())
}

/// Updates the current position within the Wasm binary while parsing operators.
pub fn update_pos(&mut self, pos: usize) {
fn update_pos(&mut self, pos: usize) {
self.pos = pos;
}

/// Returns the current position within the Wasm binary while parsing operators.
fn current_pos(&self) -> usize {
self.pos
}

/// Finishes constructing the function by initializing its [`CompiledFunc`].
pub fn finish(mut self, offset: usize) -> Result<ReusableAllocations, TranslationError> {
self.validator.finish(offset)?;
fn finish(mut self) -> Result<ReusableAllocations, TranslationError> {
let pos = self.current_pos();
self.validator.finish(pos)?;
self.translator.finish()?;
let translation = self.translator.into_allocations();
let validation = self.validator.into_allocations();
Expand All @@ -211,21 +238,6 @@ impl<'parser> ValidatingFuncTranslator<'parser> {
};
Ok(allocations)
}

/// Translates into `wasmi` bytecode if the current code path is reachable.
fn validate_then_translate<V, T>(
&mut self,
validate: V,
translate: T,
) -> Result<(), TranslationError>
where
V: FnOnce(&mut FuncValidator) -> Result<(), BinaryReaderError>,
T: FnOnce(&mut FuncTranslator<'parser>) -> Result<(), TranslationError>,
{
validate(&mut self.validator)?;
translate(&mut self.translator)?;
Ok(())
}
}

macro_rules! impl_visit_operator {
Expand Down
19 changes: 13 additions & 6 deletions crates/wasmi/src/module/compile/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
pub use self::block_type::BlockType;
use super::{parser::ReusableAllocations, FuncIdx, ModuleResources};
use super::{FuncIdx, ModuleResources};
use crate::{
engine::{CompiledFunc, FuncTranslatorAllocations, ValidatingFuncTranslator},
engine::{
CompiledFunc,
FuncTranslatorAllocations,
ReusableAllocations,
ValidatingFuncTranslator,
WasmTranslator,
},
errors::ModuleError,
};
use wasmparser::{FuncValidator, FunctionBody, ValidatorResources};
Expand Down Expand Up @@ -68,8 +74,9 @@ impl<'parser> FunctionTranslator<'parser> {
}

/// Finishes construction of the function and returns its [`CompiledFunc`].
fn finish(self, offset: usize) -> Result<ReusableAllocations, ModuleError> {
self.func_builder.finish(offset).map_err(Into::into)
fn finish(mut self, offset: usize) -> Result<ReusableAllocations, ModuleError> {
self.func_builder.update_pos(offset);
self.func_builder.finish().map_err(Into::into)
}

/// Translates local variables of the Wasm function.
Expand All @@ -79,8 +86,8 @@ impl<'parser> FunctionTranslator<'parser> {
for _ in 0..len_locals {
let offset = reader.original_position();
let (amount, value_type) = reader.read()?;
self.func_builder
.translate_locals(offset, amount, value_type)?;
self.func_builder.update_pos(offset);
self.func_builder.translate_locals(amount, value_type)?;
}
self.func_builder.finish_translate_locals()?;
Ok(())
Expand Down
1 change: 0 additions & 1 deletion crates/wasmi/src/module/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ pub use self::{
global::GlobalIdx,
import::{FuncTypeIdx, ImportName},
instantiate::{InstancePre, InstantiationError},
parser::ReusableAllocations,
read::Read,
};
pub(crate) use self::{
Expand Down
25 changes: 3 additions & 22 deletions crates/wasmi/src/module/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use super::{
Read,
};
use crate::{
engine::{CompiledFunc, FuncTranslatorAllocations},
engine::{CompiledFunc, ReusableAllocations},
Engine,
FuncType,
MemoryType,
Expand All @@ -27,7 +27,6 @@ use wasmparser::{
ElementSectionReader,
Encoding,
ExportSectionReader,
FuncValidatorAllocations,
FunctionBody,
FunctionSectionReader,
GlobalSectionReader,
Expand Down Expand Up @@ -67,24 +66,6 @@ pub struct ModuleParser<'engine> {
allocations: ReusableAllocations,
}

/// Reusable heap allocations for function validation and translation.
pub struct ReusableAllocations {
pub translation: FuncTranslatorAllocations,
pub validation: FuncValidatorAllocations,
}

impl ReusableAllocations {
/// Creates new [`ReusableAllocations`] for the given [`Engine`].
pub fn new() -> Self {
let translation = FuncTranslatorAllocations::default();
let validation = FuncValidatorAllocations::default();
Self {
translation,
validation,
}
}
}

impl<'engine> ModuleParser<'engine> {
/// Creates a new [`ModuleParser`] for the given [`Engine`].
fn new(engine: &'engine Engine) -> Self {
Expand All @@ -96,7 +77,7 @@ impl<'engine> ModuleParser<'engine> {
validator,
parser,
compiled_funcs: 0,
allocations: ReusableAllocations::new(),
allocations: ReusableAllocations::default(),
}
}

Expand Down Expand Up @@ -512,7 +493,7 @@ impl<'engine> ModuleParser<'engine> {
let (func, compiled_func_2) = self.next_func();
let validator = self.validator.code_section_entry(&func_body)?;
let module_resources = ModuleResources::new(&self.builder);
let dummy_allocations = ReusableAllocations::new();
let dummy_allocations = ReusableAllocations::default();
let allocations = replace(&mut self.allocations, dummy_allocations);
let allocations = translate(
func,
Expand Down

0 comments on commit 9778667

Please sign in to comment.