Middleware builders.

This commit is contained in:
losfair
2020-06-13 00:55:16 +08:00
parent b170c74b77
commit 1337a71753
3 changed files with 154 additions and 30 deletions

View File

@@ -85,8 +85,9 @@ pub use crate::target::{
}; };
#[cfg(feature = "translator")] #[cfg(feature = "translator")]
pub use crate::translator::{ pub use crate::translator::{
to_wasm_error, translate_module, wptype_to_type, FunctionBodyData, MiddlewareBinaryReader, to_wasm_error, translate_module, wptype_to_type, FunctionBodyData, FunctionMiddleware,
ModuleEnvironment, ModuleInfoTranslation, ModuleTranslationState, FunctionMiddlewareBuilder, MiddlewareBinaryReader, MiddlewareBuilderGenerator,
MiddlewareRegistry, ModuleEnvironment, ModuleInfoTranslation, ModuleTranslationState,
}; };
pub use crate::trap::TrapInformation; pub use crate::trap::TrapInformation;
pub use crate::unwind::{CompiledFunctionUnwindInfo, FDERelocEntry, FunctionTableReloc}; pub use crate::unwind::{CompiledFunctionUnwindInfo, FDERelocEntry, FunctionTableReloc};

View File

@@ -1,22 +1,123 @@
//! The middleware parses the function binary bytecodes and transform them //! The middleware parses the function binary bytecodes and transform them
//! with the chosen functions. //! with the chosen functions.
use crate::error::CompileError;
use smallvec::SmallVec; use smallvec::SmallVec;
use wasmparser::{BinaryReader, Operator, Result, Type}; use std::collections::{HashMap, VecDeque};
use std::fmt::Debug;
use wasm_common::LocalFunctionIndex;
use wasmparser::{BinaryReader, Operator, Result as WpResult, Type};
pub trait FunctionMiddleware { /// A registry that holds mappings from names to middleware builder generators.
pub struct MiddlewareRegistry {
/// Middleware builder generators.
generators: HashMap<String, Box<dyn MiddlewareBuilderGenerator>>,
}
/// A middleware builder generator.
pub trait MiddlewareBuilderGenerator: Debug + Send + Sync {
/// Returns the version of the builder.
fn version(&self) -> u32;
/// Generates a builder from a configuration.
fn generate(
&self,
configuration: &[u8],
) -> Result<Box<dyn FunctionMiddlewareBuilder>, CompileError>;
}
/// A shared builder for function middlewares.
pub trait FunctionMiddlewareBuilder: Debug + Send + Sync {
/// Creates a `FunctionMiddleware` for a given function.
fn prepare<'a>(
&self,
local_function_index: LocalFunctionIndex,
) -> Result<Box<dyn FunctionMiddleware>, CompileError>;
}
/// A function middleware specialized for a single function.
pub trait FunctionMiddleware: Debug {
/// Processes the given event, module info and sink. /// Processes the given event, module info and sink.
fn feed<'a, 'b>(&self, operator: &'a Operator<'b>, reader: &'b mut MiddlewareBinaryReader<'b>) { fn feed<'a>(
reader.push_operator(operator.clone()); &mut self,
operator: Operator<'a>,
state: &mut MiddlewareReaderState<'a>,
) -> WpResult<()> {
state.push_operator(operator);
Ok(())
} }
} }
/// A Middleware binary reader of the WebAssembly structures and types. /// A Middleware binary reader of the WebAssembly structures and types.
#[derive(Clone, Debug)] #[derive(Debug)]
pub struct MiddlewareBinaryReader<'a> { pub struct MiddlewareBinaryReader<'a> {
/// Parsing state.
state: MiddlewareReaderState<'a>,
/// The backing middleware chain for this reader.
chain: Vec<Box<dyn FunctionMiddleware>>,
}
/// The state of the binary reader. Exposed to middlewares to push their outputs.
#[derive(Debug)]
pub struct MiddlewareReaderState<'a> {
/// Raw binary reader.
inner: BinaryReader<'a>, inner: BinaryReader<'a>,
// The pending operations added by the middleware
pending_operations: SmallVec<[Operator<'a>; 2]>, /// The pending operations added by the middleware.
pending_operations: VecDeque<Operator<'a>>,
}
impl MiddlewareRegistry {
/// Create a middleware registry.
pub fn new() -> MiddlewareRegistry {
MiddlewareRegistry {
generators: HashMap::new(),
}
}
/// Register a middleware.
pub fn register<K: Into<String>, G: MiddlewareBuilderGenerator + 'static>(
&mut self,
key: K,
generator: G,
) {
self.generators.insert(key.into(), Box::new(generator));
}
/// Try to instantiate a builder.
pub fn instantiate_builder<K: AsRef<str>>(
&self,
key: K,
expected_version: u32,
conf: &[u8],
) -> Result<Box<dyn FunctionMiddlewareBuilder>, CompileError> {
match self.generators.get(key.as_ref()).map(|x| &**x) {
Some(x) => {
if x.version() == expected_version {
x.generate(conf)
} else {
Err(CompileError::Codegen(format!(
"found middleware `{}` but version mismatches: expected `{}`, found `{}`",
key.as_ref(),
expected_version,
x.version()
)))
}
}
None => Err(CompileError::Codegen(format!(
"middleware `{}` not found",
key.as_ref()
))),
}
}
}
impl<'a> MiddlewareReaderState<'a> {
/// Push an operator.
pub fn push_operator(&mut self, operator: Operator<'a>) {
self.pending_operations.push_back(operator);
}
} }
impl<'a> MiddlewareBinaryReader<'a> { impl<'a> MiddlewareBinaryReader<'a> {
@@ -24,52 +125,71 @@ impl<'a> MiddlewareBinaryReader<'a> {
pub fn new_with_offset(data: &'a [u8], original_offset: usize) -> Self { pub fn new_with_offset(data: &'a [u8], original_offset: usize) -> Self {
let inner = BinaryReader::new_with_offset(data, original_offset); let inner = BinaryReader::new_with_offset(data, original_offset);
Self { Self {
inner, state: MiddlewareReaderState {
pending_operations: SmallVec::new(), inner,
pending_operations: VecDeque::new(),
},
chain: vec![],
} }
} }
/// Adds a stage to the back of the middleware chain.
pub fn push_middleware_stage(&mut self, stage: Box<dyn FunctionMiddleware>) {
self.chain.push(stage);
}
/// Read a `count` indicating the number of times to call `read_local_decl`. /// Read a `count` indicating the number of times to call `read_local_decl`.
pub fn read_local_count(&mut self) -> Result<usize> { pub fn read_local_count(&mut self) -> WpResult<usize> {
self.inner.read_local_count() self.state.inner.read_local_count()
} }
/// Read a `(count, value_type)` declaration of local variables of the same type. /// Read a `(count, value_type)` declaration of local variables of the same type.
pub fn read_local_decl(&mut self, locals_total: &mut usize) -> Result<(u32, Type)> { pub fn read_local_decl(&mut self, locals_total: &mut usize) -> WpResult<(u32, Type)> {
self.inner.read_local_decl(locals_total) self.state.inner.read_local_decl(locals_total)
} }
/// Reads the next available `Operator`. /// Reads the next available `Operator`.
pub fn read_operator(&mut self) -> Result<Operator<'a>> { pub fn read_operator(&mut self) -> WpResult<Operator<'a>> {
if self.pending_operations.is_empty() { // Try to fill the `self.pending_operations` buffer, until it is non-empty.
self.inner.read_operator() while self.state.pending_operations.is_empty() {
} else { let raw_op = self.state.inner.read_operator()?;
Ok(self.pending_operations.pop().unwrap())
}
}
/// Push the operator // Fill the initial raw operator into pending buffer.
pub fn push_operator(&mut self, operator: Operator<'a>) { self.state.pending_operations.push_back(raw_op);
self.pending_operations.push(operator);
// Run the operator through each stage.
for stage in &mut self.chain {
// Take the outputs from the previous stage.
let pending: SmallVec<[Operator<'a>; 2]> =
self.state.pending_operations.drain(0..).collect();
// ...and feed them into the current stage.
for pending_op in pending {
stage.feed(pending_op, &mut self.state)?;
}
}
}
Ok(self.state.pending_operations.pop_front().unwrap())
} }
/// Returns the inner `BinaryReader`'s current position. /// Returns the inner `BinaryReader`'s current position.
pub fn current_position(&self) -> usize { pub fn current_position(&self) -> usize {
self.inner.current_position() self.state.inner.current_position()
} }
/// Returns the inner `BinaryReader`'s original position (with the offset) /// Returns the inner `BinaryReader`'s original position (with the offset)
pub fn original_position(&self) -> usize { pub fn original_position(&self) -> usize {
self.inner.original_position() self.state.inner.original_position()
} }
/// Returns the number of bytes remaining in the inner `BinaryReader`. /// Returns the number of bytes remaining in the inner `BinaryReader`.
pub fn bytes_remaining(&self) -> usize { pub fn bytes_remaining(&self) -> usize {
self.inner.bytes_remaining() self.state.inner.bytes_remaining()
} }
/// Returns whether the inner `BinaryReader` has reached the end of the file. /// Returns whether the inner `BinaryReader` has reached the end of the file.
pub fn eof(&self) -> bool { pub fn eof(&self) -> bool {
self.inner.eof() self.state.inner.eof()
} }
} }

View File

@@ -15,7 +15,10 @@ mod sections;
pub use self::environ::{FunctionBodyData, ModuleEnvironment, ModuleInfoTranslation}; pub use self::environ::{FunctionBodyData, ModuleEnvironment, ModuleInfoTranslation};
pub use self::error::to_wasm_error; pub use self::error::to_wasm_error;
pub use self::middleware::MiddlewareBinaryReader; pub use self::middleware::{
FunctionMiddleware, FunctionMiddlewareBuilder, MiddlewareBinaryReader,
MiddlewareBuilderGenerator, MiddlewareRegistry,
};
pub use self::module::translate_module; pub use self::module::translate_module;
pub use self::sections::wptype_to_type; pub use self::sections::wptype_to_type;
pub use self::state::ModuleTranslationState; pub use self::state::ModuleTranslationState;