diff --git a/Cargo.lock b/Cargo.lock index e5bcf7a78d6..d9691bfe8b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2726,6 +2726,15 @@ dependencies = [ "tempfile", ] +[[package]] +name = "wasmer-middlewares" +version = "1.0.0-alpha5" +dependencies = [ + "wasmer", + "wasmer-types", + "wasmer-vm", +] + [[package]] name = "wasmer-object" version = "1.0.0-alpha5" @@ -2832,6 +2841,7 @@ dependencies = [ "wasmer-engine-jit", "wasmer-engine-native", "wasmer-engine-object-file", + "wasmer-middlewares", "wasmer-types", "wasmer-wasi", "wasmer-wast", diff --git a/Cargo.toml b/Cargo.toml index 2ec3c49370b..d763dac116c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ wasmer-wasi = { version = "1.0.0-alpha5", path = "lib/wasi", optional = true } wasmer-wast = { version = "1.0.0-alpha5", path = "tests/lib/wast", optional = true } wasmer-cache = { version = "1.0.0-alpha5", path = "lib/cache", optional = true } wasmer-types = { version = "1.0.0-alpha5", path = "lib/wasmer-types" } +wasmer-middlewares = { version = "1.0.0-alpha5", path = "lib/middlewares", optional = true } cfg-if = "1.0" [workspace] @@ -81,6 +82,7 @@ default = [ "cache", "wasi", "emscripten", + "middlewares", ] engine = [] jit = [ @@ -119,6 +121,7 @@ llvm = [ "wasmer-compiler-llvm", "compiler", ] +middlewares = ["wasmer-middlewares"] # Testing features test-singlepass = [ diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 52c20ea7fea..5f2831b99ae 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -75,8 +75,7 @@ pub use crate::utils::is_wasm; pub use target_lexicon::{Architecture, CallingConvention, OperatingSystem, Triple, HOST}; #[cfg(feature = "compiler")] pub use wasmer_compiler::{ - wasmparser, CompilerConfig, FunctionMiddleware, FunctionMiddlewareGenerator, - MiddlewareReaderState, + wasmparser, CompilerConfig, FunctionMiddleware, MiddlewareReaderState, ModuleMiddleware, }; pub use wasmer_compiler::{CpuFeature, Features, Target}; pub use wasmer_engine::{ diff --git a/lib/compiler-cranelift/src/compiler.rs b/lib/compiler-cranelift/src/compiler.rs index 84e1ae42e1a..50445d467e9 100644 --- a/lib/compiler-cranelift/src/compiler.rs +++ b/lib/compiler-cranelift/src/compiler.rs @@ -19,11 +19,13 @@ use cranelift_codegen::{binemit, Context}; #[cfg(feature = "unwind")] use gimli::write::{Address, EhFrame, FrameTable}; use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; +use std::sync::Arc; use wasmer_compiler::CompileError; use wasmer_compiler::{CallingConvention, ModuleTranslationState, Target}; use wasmer_compiler::{ Compilation, CompileModuleInfo, CompiledFunction, CompiledFunctionFrameInfo, - CompiledFunctionUnwindInfo, Compiler, Dwarf, FunctionBody, FunctionBodyData, SectionIndex, + CompiledFunctionUnwindInfo, Compiler, Dwarf, FunctionBody, FunctionBodyData, + ModuleMiddlewareChain, SectionIndex, }; use wasmer_types::entity::{EntityRef, PrimaryMap}; use wasmer_types::{FunctionIndex, LocalFunctionIndex, SignatureIndex}; @@ -54,7 +56,7 @@ impl Compiler for CraneliftCompiler { fn compile_module( &self, target: &Target, - compile_info: &CompileModuleInfo, + compile_info: &mut CompileModuleInfo, module_translation_state: &ModuleTranslationState, function_body_inputs: PrimaryMap>, ) -> Result { @@ -62,6 +64,9 @@ impl Compiler for CraneliftCompiler { let frontend_config = isa.frontend_config(); let memory_styles = &compile_info.memory_styles; let table_styles = &compile_info.table_styles; + let mut module = (*compile_info.module).clone(); + self.config.middlewares.apply_on_module_info(&mut module); + compile_info.module = Arc::new(module); let module = &compile_info.module; let signatures = module .signatures @@ -77,7 +82,7 @@ impl Compiler for CraneliftCompiler { // FDEs will cause some issues in Linux. None } else { - use std::sync::{Arc, Mutex}; + use std::sync::Mutex; match target.triple().default_calling_convention() { Ok(CallingConvention::SystemV) => { match isa.create_systemv_cie() { @@ -125,7 +130,7 @@ impl Compiler for CraneliftCompiler { )?; let mut code_buf: Vec = Vec::new(); - let mut reloc_sink = RelocSink::new(module, func_index); + let mut reloc_sink = RelocSink::new(&module, func_index); let mut trap_sink = TrapSink::new(); let mut stackmap_sink = binemit::NullStackMapSink {}; context diff --git a/lib/compiler-cranelift/src/config.rs b/lib/compiler-cranelift/src/config.rs index 748851bde90..f11cb937648 100644 --- a/lib/compiler-cranelift/src/config.rs +++ b/lib/compiler-cranelift/src/config.rs @@ -3,7 +3,7 @@ use cranelift_codegen::isa::{lookup, TargetIsa}; use cranelift_codegen::settings::{self, Configurable}; use std::sync::Arc; use wasmer_compiler::{ - Architecture, Compiler, CompilerConfig, CpuFeature, FunctionMiddlewareGenerator, Target, + Architecture, Compiler, CompilerConfig, CpuFeature, ModuleMiddleware, Target, }; // Runtime Environment @@ -35,7 +35,7 @@ pub struct Cranelift { enable_pic: bool, opt_level: OptLevel, /// The middleware chain. - pub(crate) middlewares: Vec>, + pub(crate) middlewares: Vec>, } impl Cranelift { @@ -199,7 +199,7 @@ impl CompilerConfig for Cranelift { } /// Pushes a middleware onto the back of the middleware chain. - fn push_middleware(&mut self, middleware: Arc) { + fn push_middleware(&mut self, middleware: Arc) { self.middlewares.push(middleware); } } diff --git a/lib/compiler-cranelift/src/translator/func_translator.rs b/lib/compiler-cranelift/src/translator/func_translator.rs index 94dcd8d8064..7c8ec3e4e09 100644 --- a/lib/compiler-cranelift/src/translator/func_translator.rs +++ b/lib/compiler-cranelift/src/translator/func_translator.rs @@ -19,7 +19,7 @@ use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; use tracing::info; use wasmer_compiler::wasmparser; use wasmer_compiler::{ - to_wasm_error, wasm_unsupported, GenerateMiddlewareChain, MiddlewareBinaryReader, + to_wasm_error, wasm_unsupported, MiddlewareBinaryReader, ModuleMiddlewareChain, ModuleTranslationState, WasmResult, }; use wasmer_types::LocalFunctionIndex; @@ -75,7 +75,7 @@ impl FuncTranslator { reader.set_middleware_chain( config .middlewares - .generate_middleware_chain(local_function_index), + .generate_function_middleware_chain(local_function_index), ); self.translate_from_reader(module_translation_state, reader, func, environ) } diff --git a/lib/compiler-llvm/src/compiler.rs b/lib/compiler-llvm/src/compiler.rs index 9b344b61ead..a8c5d86ce0c 100644 --- a/lib/compiler-llvm/src/compiler.rs +++ b/lib/compiler-llvm/src/compiler.rs @@ -8,15 +8,16 @@ use inkwell::module::{Linkage, Module}; use inkwell::targets::FileType; use inkwell::DLLStorageClass; use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; +use std::sync::Arc; use wasmer_compiler::{ Compilation, CompileError, CompileModuleInfo, Compiler, CustomSection, CustomSectionProtection, - Dwarf, FunctionBodyData, ModuleTranslationState, RelocationTarget, SectionBody, SectionIndex, - Symbol, SymbolRegistry, Target, + Dwarf, FunctionBodyData, ModuleMiddlewareChain, ModuleTranslationState, RelocationTarget, + SectionBody, SectionIndex, Symbol, SymbolRegistry, Target, }; use wasmer_types::entity::{EntityRef, PrimaryMap}; use wasmer_types::{FunctionIndex, LocalFunctionIndex, SignatureIndex}; -//use std::sync::{Arc, Mutex}; +//use std::sync::Mutex; /// A compiler that compiles a WebAssembly module with LLVM, translating the Wasm to LLVM IR, /// optimizing it and then translating to assembly. @@ -210,7 +211,7 @@ impl Compiler for LLVMCompiler { fn experimental_native_compile_module<'data, 'module>( &self, target: &Target, - module: &'module CompileModuleInfo, + compile_info: &'module mut CompileModuleInfo, module_translation: &ModuleTranslationState, // The list of function bodies function_body_inputs: &PrimaryMap>, @@ -218,9 +219,13 @@ impl Compiler for LLVMCompiler { // The metadata to inject into the wasmer_metadata section of the object file. wasmer_metadata: &[u8], ) -> Option, CompileError>> { + let mut module = (*compile_info.module).clone(); + self.config.middlewares.apply_on_module_info(&mut module); + compile_info.module = Arc::new(module); + Some(self.compile_native_object( target, - module, + compile_info, module_translation, function_body_inputs, symbol_registry, @@ -233,13 +238,17 @@ impl Compiler for LLVMCompiler { fn compile_module<'data, 'module>( &self, target: &Target, - compile_info: &'module CompileModuleInfo, + compile_info: &'module mut CompileModuleInfo, module_translation: &ModuleTranslationState, function_body_inputs: PrimaryMap>, ) -> Result { //let data = Arc::new(Mutex::new(0)); let memory_styles = &compile_info.memory_styles; let table_styles = &compile_info.table_styles; + + let mut module = (*compile_info.module).clone(); + self.config.middlewares.apply_on_module_info(&mut module); + compile_info.module = Arc::new(module); let module = &compile_info.module; // TODO: merge constants in sections. @@ -260,7 +269,7 @@ impl Compiler for LLVMCompiler { // TODO: remove (to serialize) //let _data = data.lock().unwrap(); func_translator.translate( - &module, + module, module_translation, i, input, diff --git a/lib/compiler-llvm/src/config.rs b/lib/compiler-llvm/src/config.rs index 328a365f485..a7d1e44cec2 100644 --- a/lib/compiler-llvm/src/config.rs +++ b/lib/compiler-llvm/src/config.rs @@ -8,7 +8,7 @@ use itertools::Itertools; use std::fmt::Debug; use std::sync::Arc; use target_lexicon::Architecture; -use wasmer_compiler::{Compiler, CompilerConfig, FunctionMiddlewareGenerator, Target, Triple}; +use wasmer_compiler::{Compiler, CompilerConfig, ModuleMiddleware, Target, Triple}; use wasmer_types::{FunctionType, LocalFunctionIndex}; /// The InkWell ModuleInfo type @@ -45,7 +45,7 @@ pub struct LLVM { is_pic: bool, pub(crate) callbacks: Option>, /// The middleware chain. - pub(crate) middlewares: Vec>, + pub(crate) middlewares: Vec>, } impl LLVM { @@ -212,7 +212,7 @@ impl CompilerConfig for LLVM { } /// Pushes a middleware onto the back of the middleware chain. - fn push_middleware(&mut self, middleware: Arc) { + fn push_middleware(&mut self, middleware: Arc) { self.middlewares.push(middleware); } } diff --git a/lib/compiler-llvm/src/translator/code.rs b/lib/compiler-llvm/src/translator/code.rs index 52dcde51a2a..584d2e48685 100644 --- a/lib/compiler-llvm/src/translator/code.rs +++ b/lib/compiler-llvm/src/translator/code.rs @@ -26,8 +26,8 @@ use crate::config::{CompiledKind, LLVM}; use crate::object_file::{load_object_file, CompiledFunction}; use wasmer_compiler::wasmparser::{MemoryImmediate, Operator}; use wasmer_compiler::{ - to_wasm_error, wptype_to_type, CompileError, FunctionBodyData, GenerateMiddlewareChain, - MiddlewareBinaryReader, ModuleTranslationState, RelocationTarget, Symbol, SymbolRegistry, + to_wasm_error, wptype_to_type, CompileError, FunctionBodyData, MiddlewareBinaryReader, + ModuleMiddlewareChain, ModuleTranslationState, RelocationTarget, Symbol, SymbolRegistry, }; use wasmer_types::entity::PrimaryMap; use wasmer_types::{ @@ -150,7 +150,7 @@ impl FuncTranslator { reader.set_middleware_chain( config .middlewares - .generate_middleware_chain(*local_func_index), + .generate_function_middleware_chain(*local_func_index), ); let mut params = vec![]; diff --git a/lib/compiler-singlepass/src/compiler.rs b/lib/compiler-singlepass/src/compiler.rs index 448e8f19ca4..2c90a6d3a04 100644 --- a/lib/compiler-singlepass/src/compiler.rs +++ b/lib/compiler-singlepass/src/compiler.rs @@ -13,7 +13,7 @@ use wasmer_compiler::wasmparser::BinaryReaderError; use wasmer_compiler::TrapInformation; use wasmer_compiler::{Compilation, CompileError, CompiledFunction, Compiler, SectionIndex}; use wasmer_compiler::{ - CompileModuleInfo, CompilerConfig, GenerateMiddlewareChain, MiddlewareBinaryReader, + CompileModuleInfo, CompilerConfig, MiddlewareBinaryReader, ModuleMiddlewareChain, ModuleTranslationState, Target, }; use wasmer_compiler::{FunctionBody, FunctionBodyData}; @@ -47,16 +47,19 @@ impl Compiler for SinglepassCompiler { fn compile_module( &self, _target: &Target, - compile_info: &CompileModuleInfo, + compile_info: &mut CompileModuleInfo, _module_translation: &ModuleTranslationState, function_body_inputs: PrimaryMap>, ) -> Result { if compile_info.features.multi_value { return Err(CompileError::UnsupportedFeature("multivalue".to_string())); } - let vmoffsets = VMOffsets::new(8, &compile_info.module); let memory_styles = &compile_info.memory_styles; let table_styles = &compile_info.table_styles; + let mut module = (*compile_info.module).clone(); + self.config.middlewares.apply_on_module_info(&mut module); + compile_info.module = Arc::new(module); + let vmoffsets = VMOffsets::new(8, &compile_info.module); let module = &compile_info.module; let import_trampolines: PrimaryMap = (0..module.num_imported_functions) .map(FunctionIndex::new) @@ -73,7 +76,10 @@ impl Compiler for SinglepassCompiler { .collect::)>>() .par_iter() .map(|(i, input)| { - let middleware_chain = self.config.middlewares.generate_middleware_chain(*i); + let middleware_chain = self + .config + .middlewares + .generate_function_middleware_chain(*i); let mut reader = MiddlewareBinaryReader::new_with_offset(input.data, input.module_offset); reader.set_middleware_chain(middleware_chain); diff --git a/lib/compiler-singlepass/src/config.rs b/lib/compiler-singlepass/src/config.rs index d59fd938666..b6a198a4c97 100644 --- a/lib/compiler-singlepass/src/config.rs +++ b/lib/compiler-singlepass/src/config.rs @@ -3,7 +3,7 @@ use crate::compiler::SinglepassCompiler; use std::sync::Arc; -use wasmer_compiler::{Compiler, CompilerConfig, CpuFeature, FunctionMiddlewareGenerator, Target}; +use wasmer_compiler::{Compiler, CompilerConfig, CpuFeature, ModuleMiddleware, Target}; use wasmer_types::Features; #[derive(Debug, Clone)] @@ -11,7 +11,7 @@ pub struct Singlepass { pub(crate) enable_nan_canonicalization: bool, pub(crate) enable_stack_check: bool, /// The middleware chain. - pub(crate) middlewares: Vec>, + pub(crate) middlewares: Vec>, } impl Singlepass { @@ -66,7 +66,7 @@ impl CompilerConfig for Singlepass { } /// Pushes a middleware onto the back of the middleware chain. - fn push_middleware(&mut self, middleware: Arc) { + fn push_middleware(&mut self, middleware: Arc) { self.middlewares.push(middleware); } } diff --git a/lib/compiler/README.md b/lib/compiler/README.md index c439cffaa17..dd6a60d3f5e 100644 --- a/lib/compiler/README.md +++ b/lib/compiler/README.md @@ -34,7 +34,7 @@ pub trait Compiler { fn compile_module<'data, 'module>( &self, target: &Target, - compile_info: &'module CompileModuleInfo, + compile_info: &'module mut CompileModuleInfo, module_translation: &ModuleTranslationState, // The list of function bodies function_body_inputs: PrimaryMap>, diff --git a/lib/compiler/src/compiler.rs b/lib/compiler/src/compiler.rs index d94df768e5f..6d462851ebf 100644 --- a/lib/compiler/src/compiler.rs +++ b/lib/compiler/src/compiler.rs @@ -7,7 +7,7 @@ use crate::lib::std::boxed::Box; use crate::lib::std::sync::Arc; use crate::module::CompileModuleInfo; use crate::target::Target; -use crate::translator::FunctionMiddlewareGenerator; +use crate::translator::ModuleMiddleware; use crate::FunctionBodyData; use crate::ModuleTranslationState; use crate::SectionIndex; @@ -45,7 +45,7 @@ pub trait CompilerConfig { } /// Pushes a middleware onto the back of the middleware chain. - fn push_middleware(&mut self, middleware: Arc); + fn push_middleware(&mut self, middleware: Arc); } /// An implementation of a Compiler from parsed WebAssembly module to Compiled native code. @@ -84,7 +84,7 @@ pub trait Compiler { fn compile_module<'data, 'module>( &self, target: &Target, - module: &'module CompileModuleInfo, + module: &'module mut CompileModuleInfo, module_translation: &ModuleTranslationState, // The list of function bodies function_body_inputs: PrimaryMap>, @@ -96,7 +96,7 @@ pub trait Compiler { fn experimental_native_compile_module<'data, 'module>( &self, _target: &Target, - _module: &'module CompileModuleInfo, + _module: &'module mut CompileModuleInfo, _module_translation: &ModuleTranslationState, // The list of function bodies _function_body_inputs: &PrimaryMap>, diff --git a/lib/compiler/src/lib.rs b/lib/compiler/src/lib.rs index 10f5c32ae51..e9171cc7b35 100644 --- a/lib/compiler/src/lib.rs +++ b/lib/compiler/src/lib.rs @@ -86,8 +86,8 @@ pub use crate::target::{ #[cfg(feature = "translator")] pub use crate::translator::{ to_wasm_error, translate_module, wptype_to_type, FunctionBodyData, FunctionMiddleware, - FunctionMiddlewareGenerator, GenerateMiddlewareChain, MiddlewareBinaryReader, - MiddlewareReaderState, ModuleEnvironment, ModuleInfoTranslation, ModuleTranslationState, + MiddlewareBinaryReader, MiddlewareReaderState, ModuleEnvironment, ModuleInfoTranslation, + ModuleMiddleware, ModuleMiddlewareChain, ModuleTranslationState, }; pub use crate::trap::TrapInformation; pub use crate::unwind::CompiledFunctionUnwindInfo; diff --git a/lib/compiler/src/translator/middleware.rs b/lib/compiler/src/translator/middleware.rs index 51dc1fcd3c9..e7f21c574b7 100644 --- a/lib/compiler/src/translator/middleware.rs +++ b/lib/compiler/src/translator/middleware.rs @@ -6,17 +6,28 @@ use std::collections::VecDeque; use std::fmt::Debug; use std::ops::Deref; use wasmer_types::LocalFunctionIndex; +use wasmer_vm::ModuleInfo; use wasmparser::{BinaryReader, Operator, Result as WpResult, Type}; /// A shared builder for function middlewares. -pub trait FunctionMiddlewareGenerator: Debug + Send + Sync { +pub trait ModuleMiddleware: Debug + Send + Sync { /// Generates a `FunctionMiddleware` for a given function. - fn generate(&self, local_function_index: LocalFunctionIndex) -> Box; + /// + /// Here we generate a separate object for each function instead of executing directly on per-function operators, + /// in order to enable concurrent middleware application. Takes immutable `&self` because this function can be called + /// concurrently from multiple compilation threads. + fn generate_function_middleware( + &self, + local_function_index: LocalFunctionIndex, + ) -> Box; + + /// Transforms a `ModuleInfo` struct in-place. This is called before application on functions begins. + fn transform_module_info(&self, _: &mut ModuleInfo) {} } /// A function middleware specialized for a single function. pub trait FunctionMiddleware: Debug { - /// Processes the given event, module info and sink. + /// Processes the given operator. fn feed<'a>( &mut self, operator: Operator<'a>, @@ -48,24 +59,34 @@ pub struct MiddlewareReaderState<'a> { } /// Trait for generating middleware chains from "prototype" (generator) chains. -pub trait GenerateMiddlewareChain { - /// Generates a middleware chain. - fn generate_middleware_chain( +pub trait ModuleMiddlewareChain { + /// Generates a function middleware chain. + fn generate_function_middleware_chain( &self, local_function_index: LocalFunctionIndex, ) -> Vec>; + + /// Applies the chain on a `ModuleInfo` struct. + fn apply_on_module_info(&self, module_info: &mut ModuleInfo); } -impl> GenerateMiddlewareChain for [T] { - /// Generates a middleware chain. - fn generate_middleware_chain( +impl> ModuleMiddlewareChain for [T] { + /// Generates a function middleware chain. + fn generate_function_middleware_chain( &self, local_function_index: LocalFunctionIndex, ) -> Vec> { self.iter() - .map(|x| x.generate(local_function_index)) + .map(|x| x.generate_function_middleware(local_function_index)) .collect() } + + /// Applies the chain on a `ModuleInfo` struct. + fn apply_on_module_info(&self, module_info: &mut ModuleInfo) { + for item in self { + item.transform_module_info(module_info); + } + } } impl<'a> MiddlewareReaderState<'a> { @@ -75,6 +96,18 @@ impl<'a> MiddlewareReaderState<'a> { } } +impl<'a> Extend> for MiddlewareReaderState<'a> { + fn extend>>(&mut self, iter: I) { + self.pending_operations.extend(iter); + } +} + +impl<'a: 'b, 'b> Extend<&'b Operator<'a>> for MiddlewareReaderState<'a> { + fn extend>>(&mut self, iter: I) { + self.pending_operations.extend(iter.into_iter().cloned()); + } +} + impl<'a> MiddlewareBinaryReader<'a> { /// Constructs a `MiddlewareBinaryReader` with an explicit starting offset. pub fn new_with_offset(data: &'a [u8], original_offset: usize) -> Self { @@ -107,6 +140,11 @@ impl<'a> MiddlewareBinaryReader<'a> { /// Reads the next available `Operator`. pub fn read_operator(&mut self) -> WpResult> { + if self.chain.is_empty() { + // We short-circuit in case no chain is used + return self.state.inner.read_operator(); + } + // Try to fill the `self.pending_operations` buffer, until it is non-empty. while self.state.pending_operations.is_empty() { let raw_op = self.state.inner.read_operator()?; diff --git a/lib/compiler/src/translator/mod.rs b/lib/compiler/src/translator/mod.rs index 210e9012ea6..a3b4fcf178c 100644 --- a/lib/compiler/src/translator/mod.rs +++ b/lib/compiler/src/translator/mod.rs @@ -16,8 +16,8 @@ mod sections; pub use self::environ::{FunctionBodyData, ModuleEnvironment, ModuleInfoTranslation}; pub use self::error::to_wasm_error; pub use self::middleware::{ - FunctionMiddleware, FunctionMiddlewareGenerator, GenerateMiddlewareChain, - MiddlewareBinaryReader, MiddlewareReaderState, + FunctionMiddleware, MiddlewareBinaryReader, MiddlewareReaderState, ModuleMiddleware, + ModuleMiddlewareChain, }; pub use self::module::translate_module; pub use self::sections::wptype_to_type; diff --git a/lib/engine-jit/src/artifact.rs b/lib/engine-jit/src/artifact.rs index e89af2aa2ab..e9d91e10bdc 100644 --- a/lib/engine-jit/src/artifact.rs +++ b/lib/engine-jit/src/artifact.rs @@ -70,7 +70,7 @@ impl JITArtifact { .map(|table_type| tunables.table_style(table_type)) .collect(); - let compile_info = CompileModuleInfo { + let mut compile_info = CompileModuleInfo { module: Arc::new(translation.module), features: features.clone(), memory_styles, @@ -82,7 +82,7 @@ impl JITArtifact { // Compile the Module let compilation = compiler.compile_module( &jit.target(), - &compile_info, + &mut compile_info, // SAFETY: Calling `unwrap` is correct since // `environ.translate()` above will write some data into // `module_translation_state`. diff --git a/lib/engine-native/src/artifact.rs b/lib/engine-native/src/artifact.rs index 2cf7d5f6918..95754f4f9de 100644 --- a/lib/engine-native/src/artifact.rs +++ b/lib/engine-native/src/artifact.rs @@ -176,7 +176,7 @@ impl NativeArtifact { .map(|_function_body| 0u64) .collect::>(); - let metadata = ModuleMetadata { + let mut metadata = ModuleMetadata { compile_info, prefix: engine_inner.get_prefix(&data), data_initializers, @@ -190,12 +190,13 @@ impl NativeArtifact { .expect("Should write number"); metadata_binary.extend(serialized_data); + let (mut compile_info, symbol_registry) = metadata.split(); let maybe_obj_bytes = compiler.experimental_native_compile_module( &target, - &metadata.compile_info, + &mut compile_info, module_translation.as_ref().unwrap(), &function_body_inputs, - &metadata, + &symbol_registry, &metadata_binary, ); @@ -216,14 +217,14 @@ impl NativeArtifact { None => { let compilation = compiler.compile_module( &target, - &metadata.compile_info, + &mut compile_info, module_translation.as_ref().unwrap(), function_body_inputs, )?; let mut obj = get_object_for_target(&target_triple).map_err(to_compile_error)?; emit_data(&mut obj, WASMER_METADATA_SYMBOL, &metadata_binary) .map_err(to_compile_error)?; - emit_compilation(&mut obj, compilation, &metadata, &target_triple) + emit_compilation(&mut obj, compilation, &symbol_registry, &target_triple) .map_err(to_compile_error)?; let file = tempfile::Builder::new() .prefix("wasmer_native") @@ -365,8 +366,9 @@ impl NativeArtifact { let mut finished_functions: PrimaryMap = PrimaryMap::new(); for (function_local_index, _function_len) in metadata.function_body_lengths.iter() { - let function_name = - metadata.symbol_to_name(Symbol::LocalFunction(function_local_index)); + let function_name = metadata + .get_symbol_registry() + .symbol_to_name(Symbol::LocalFunction(function_local_index)); unsafe { // We use a fake function signature `fn()` because we just // want to get the function address. @@ -383,7 +385,9 @@ impl NativeArtifact { let mut finished_function_call_trampolines: PrimaryMap = PrimaryMap::with_capacity(metadata.compile_info.module.signatures.len()); for sig_index in metadata.compile_info.module.signatures.keys() { - let function_name = metadata.symbol_to_name(Symbol::FunctionCallTrampoline(sig_index)); + let function_name = metadata + .get_symbol_registry() + .symbol_to_name(Symbol::FunctionCallTrampoline(sig_index)); unsafe { let trampoline: LibrarySymbol = lib .get(function_name.as_bytes()) @@ -403,8 +407,9 @@ impl NativeArtifact { .keys() .take(metadata.compile_info.module.num_imported_functions) { - let function_name = - metadata.symbol_to_name(Symbol::DynamicFunctionTrampoline(func_index)); + let function_name = metadata + .get_symbol_registry() + .symbol_to_name(Symbol::DynamicFunctionTrampoline(func_index)); unsafe { let trampoline: LibrarySymbol = lib .get(function_name.as_bytes()) diff --git a/lib/engine-native/src/serialize.rs b/lib/engine-native/src/serialize.rs index 644b63d0383..88fa9965d27 100644 --- a/lib/engine-native/src/serialize.rs +++ b/lib/engine-native/src/serialize.rs @@ -13,7 +13,29 @@ pub struct ModuleMetadata { pub function_body_lengths: PrimaryMap, } -impl SymbolRegistry for ModuleMetadata { +pub struct ModuleMetadataSymbolRegistry<'a> { + pub prefix: &'a String, +} + +impl ModuleMetadata { + pub fn split<'a>( + &'a mut self, + ) -> (&'a mut CompileModuleInfo, ModuleMetadataSymbolRegistry<'a>) { + let compile_info = &mut self.compile_info; + let symbol_registry = ModuleMetadataSymbolRegistry { + prefix: &self.prefix, + }; + (compile_info, symbol_registry) + } + + pub fn get_symbol_registry<'a>(&'a self) -> ModuleMetadataSymbolRegistry<'a> { + ModuleMetadataSymbolRegistry { + prefix: &self.prefix, + } + } +} + +impl<'a> SymbolRegistry for ModuleMetadataSymbolRegistry<'a> { fn symbol_to_name(&self, symbol: Symbol) -> String { match symbol { Symbol::LocalFunction(index) => { diff --git a/lib/engine-object-file/src/artifact.rs b/lib/engine-object-file/src/artifact.rs index d11b9b20c0d..5efacd35b04 100644 --- a/lib/engine-object-file/src/artifact.rs +++ b/lib/engine-object-file/src/artifact.rs @@ -2,7 +2,7 @@ //! done as separate steps. use crate::engine::{ObjectFileEngine, ObjectFileEngineInner}; -use crate::serialize::ModuleMetadata; +use crate::serialize::{ModuleMetadata, ModuleMetadataSymbolRegistry}; use std::collections::BTreeMap; use std::error::Error; use std::mem; @@ -39,6 +39,7 @@ pub struct ObjectFileArtifact { signatures: BoxedSlice, /// Length of the serialized metadata metadata_length: usize, + symbol_registry: ModuleMetadataSymbolRegistry, } fn to_compile_error(err: impl Error) -> CompileError { @@ -162,7 +163,7 @@ impl ObjectFileArtifact { .map(|_function_body| 0u64) .collect::>(); - let metadata = ModuleMetadata { + let mut metadata = ModuleMetadata { compile_info, prefix: engine_inner.get_prefix(&data), data_initializers, @@ -194,12 +195,13 @@ impl ObjectFileArtifact { metadata_binary.extend(serialized_data); let metadata_length = metadata_binary.len(); + let (compile_info, symbol_registry) = metadata.split(); let maybe_obj_bytes = compiler.experimental_native_compile_module( &target, - &metadata.compile_info, + compile_info, module_translation.as_ref().unwrap(), &function_body_inputs, - &metadata, + &symbol_registry, &metadata_binary, ); @@ -208,7 +210,7 @@ impl ObjectFileArtifact { } else { let compilation = compiler.compile_module( &target, - &metadata.compile_info, + &mut metadata.compile_info, module_translation.as_ref().unwrap(), function_body_inputs, )?; @@ -224,7 +226,7 @@ impl ObjectFileArtifact { let mut obj = get_object_for_target(&target_triple).map_err(to_compile_error)?; emit_data(&mut obj, WASMER_METADATA_SYMBOL, &metadata_binary) .map_err(to_compile_error)?; - emit_compilation(&mut obj, compilation, &metadata, &target_triple) + emit_compilation(&mut obj, compilation, &symbol_registry, &target_triple) .map_err(to_compile_error)?; obj.write().map_err(to_compile_error)? }; @@ -261,6 +263,7 @@ impl ObjectFileArtifact { .map(|sig| signature_registry.register(sig)) .collect::>(); + let symbol_registry = metadata.get_symbol_registry(); Ok(Self { metadata, module_bytes, @@ -271,6 +274,7 @@ impl ObjectFileArtifact { .into_boxed_slice(), signatures: signatures.into_boxed_slice(), metadata_length, + symbol_registry, }) } @@ -367,6 +371,7 @@ impl ObjectFileArtifact { finished_dynamic_function_trampolines.push(fp); } + let symbol_registry = metadata.get_symbol_registry(); Ok(Self { metadata, module_bytes: bytes.to_owned(), @@ -377,12 +382,13 @@ impl ObjectFileArtifact { .into_boxed_slice(), signatures: signatures.into_boxed_slice(), metadata_length: 0, + symbol_registry, }) } /// Get the `SymbolRegistry` used to generate the names used in the Artifact. pub fn symbol_registry(&self) -> &dyn SymbolRegistry { - &self.metadata + &self.symbol_registry } /// The length in bytes of the metadata in the serialized output. diff --git a/lib/engine-object-file/src/serialize.rs b/lib/engine-object-file/src/serialize.rs index 644b63d0383..8ec7da0302d 100644 --- a/lib/engine-object-file/src/serialize.rs +++ b/lib/engine-object-file/src/serialize.rs @@ -13,7 +13,27 @@ pub struct ModuleMetadata { pub function_body_lengths: PrimaryMap, } -impl SymbolRegistry for ModuleMetadata { +pub struct ModuleMetadataSymbolRegistry { + pub prefix: String, +} + +impl ModuleMetadata { + pub fn split(&mut self) -> (&mut CompileModuleInfo, ModuleMetadataSymbolRegistry) { + let compile_info = &mut self.compile_info; + let symbol_registry = ModuleMetadataSymbolRegistry { + prefix: self.prefix.clone(), + }; + (compile_info, symbol_registry) + } + + pub fn get_symbol_registry(&self) -> ModuleMetadataSymbolRegistry { + ModuleMetadataSymbolRegistry { + prefix: self.prefix.clone(), + } + } +} + +impl SymbolRegistry for ModuleMetadataSymbolRegistry { fn symbol_to_name(&self, symbol: Symbol) -> String { match symbol { Symbol::LocalFunction(index) => { diff --git a/lib/middlewares/Cargo.toml b/lib/middlewares/Cargo.toml new file mode 100644 index 00000000000..8ac948381d5 --- /dev/null +++ b/lib/middlewares/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "wasmer-middlewares" +version = "1.0.0-alpha5" +authors = ["Wasmer Engineering Team "] +description = "A collection of various useful middlewares" +license = "(Apache-2.0 WITH LLVM-exception) or MIT" +categories = ["wasm"] +keywords = ["webassembly", "wasm"] +repository = "https://github.com/wasmerio/wasmer" +readme = "README.md" +edition = "2018" + +[dependencies] +wasmer = { path = "../api", version = "1.0.0-alpha5" } +wasmer-types = { path = "../wasmer-types", version = "1.0.0-alpha5" } +wasmer-vm = { path = "../vm", version = "1.0.0-alpha5" } + +[badges] +maintenance = { status = "actively-developed" } diff --git a/lib/middlewares/README.md b/lib/middlewares/README.md new file mode 100644 index 00000000000..9f40322ea2a --- /dev/null +++ b/lib/middlewares/README.md @@ -0,0 +1,5 @@ +# Wasmer Middlewares + +The `wasmer-middlewares` crate is a collection of various useful middlewares: + +- `metering`: A middleware for tracking how many operators are executed in total and putting a limit on the total number of operators executed. diff --git a/lib/middlewares/src/lib.rs b/lib/middlewares/src/lib.rs new file mode 100644 index 00000000000..884fcf82242 --- /dev/null +++ b/lib/middlewares/src/lib.rs @@ -0,0 +1,3 @@ +pub mod metering; + +pub use metering::Metering; diff --git a/lib/middlewares/src/metering.rs b/lib/middlewares/src/metering.rs new file mode 100644 index 00000000000..68a010a9794 --- /dev/null +++ b/lib/middlewares/src/metering.rs @@ -0,0 +1,160 @@ +//! `metering` is a middleware for tracking how many operators are executed in total +//! and putting a limit on the total number of operators executed. + +use std::fmt; +use std::sync::Mutex; +use wasmer::wasmparser::{ + Operator, Result as WpResult, Type as WpType, TypeOrFuncType as WpTypeOrFuncType, +}; +use wasmer::{ + FunctionMiddleware, GlobalInit, GlobalType, LocalFunctionIndex, MiddlewareReaderState, + ModuleMiddleware, Mutability, Type, +}; +use wasmer_types::GlobalIndex; +use wasmer_vm::ModuleInfo; + +/// The module-level metering middleware. +/// +/// # Panic +/// +/// An instance of `Metering` should not be shared among different modules, since it tracks +/// module-specific information like the global index to store metering state. Attempts to use +/// a `Metering` instance from multiple modules will result in a panic. +pub struct Metering u64 + Copy + Clone + Send + Sync> { + /// Initial limit of points. + initial_limit: u64, + + /// Function that maps each operator to a cost in "points". + cost_function: F, + + /// The global index in the current module for remaining points. + remaining_points_index: Mutex>, +} + +/// The function-level metering middleware. +pub struct FunctionMetering u64 + Copy + Clone + Send + Sync> { + /// Function that maps each operator to a cost in "points". + cost_function: F, + + /// The global index in the current module for remaining points. + remaining_points_index: GlobalIndex, + + /// Accumulated cost of the current basic block. + accumulated_cost: u64, +} + +impl u64 + Copy + Clone + Send + Sync> Metering { + /// Creates a `Metering` middleware. + pub fn new(initial_limit: u64, cost_function: F) -> Self { + Self { + initial_limit, + cost_function, + remaining_points_index: Mutex::new(None), + } + } +} + +impl u64 + Copy + Clone + Send + Sync> fmt::Debug for Metering { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Metering") + .field("initial_limit", &self.initial_limit) + .field("cost_function", &"") + .field("remaining_points_index", &self.remaining_points_index) + .finish() + } +} + +impl u64 + Copy + Clone + Send + Sync + 'static> ModuleMiddleware + for Metering +{ + /// Generates a `FunctionMiddleware` for a given function. + fn generate_function_middleware(&self, _: LocalFunctionIndex) -> Box { + Box::new(FunctionMetering { + cost_function: self.cost_function, + remaining_points_index: self.remaining_points_index.lock().unwrap().expect( + "Metering::generate_function_middleware: Remaining points index not set up.", + ), + accumulated_cost: 0, + }) + } + + /// Transforms a `ModuleInfo` struct in-place. This is called before application on functions begins. + fn transform_module_info(&self, module_info: &mut ModuleInfo) { + let mut remaining_points_index = self.remaining_points_index.lock().unwrap(); + if remaining_points_index.is_some() { + panic!("Metering::transform_module_info: Attempting to use a `Metering` middleware from multiple modules."); + } + + // Append a global for remaining points and initialize it. + *remaining_points_index = Some( + module_info + .globals + .push(GlobalType::new(Type::I64, Mutability::Var)), + ); + module_info + .global_initializers + .push(GlobalInit::I64Const(self.initial_limit as i64)); + } +} + +impl u64 + Copy + Clone + Send + Sync> fmt::Debug for FunctionMetering { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("FunctionMetering") + .field("cost_function", &"") + .field("remaining_points_index", &self.remaining_points_index) + .finish() + } +} + +impl u64 + Copy + Clone + Send + Sync> FunctionMiddleware + for FunctionMetering +{ + fn feed<'a>( + &mut self, + operator: Operator<'a>, + state: &mut MiddlewareReaderState<'a>, + ) -> WpResult<()> { + // Get the cost of the current operator, and add it to the accumulator. + // This needs to be done before the metering logic, to prevent operators like `Call` from escaping metering in some + // corner cases. + self.accumulated_cost += (self.cost_function)(&operator); + + // Possible sources and targets of a branch. Finalize the cost of the previous basic block and perform necessary checks. + match operator { + Operator::Loop { .. } // loop headers are branch targets + | Operator::End // block ends are branch targets + | Operator::Else // "else" is the "end" of an if branch + | Operator::Br { .. } // branch source + | Operator::BrTable { .. } // branch source + | Operator::BrIf { .. } // branch source + | Operator::Call { .. } // function call - branch source + | Operator::CallIndirect { .. } // function call - branch source + | Operator::Return // end of function - branch source + => { + if self.accumulated_cost > 0 { + state.extend(&[ + // if unsigned(globals[remaining_points_index]) < unsigned(self.accumulated_cost) { throw(); } + Operator::GlobalGet { global_index: self.remaining_points_index.as_u32() }, + Operator::I64Const { value: self.accumulated_cost as i64 }, + Operator::I64LtU, + Operator::If { ty: WpTypeOrFuncType::Type(WpType::EmptyBlockType) }, + Operator::Unreachable, // FIXME: Signal the error properly. + Operator::End, + + // globals[remaining_points_index] -= self.accumulated_cost; + Operator::GlobalGet { global_index: self.remaining_points_index.as_u32() }, + Operator::I64Const { value: self.accumulated_cost as i64 }, + Operator::I64Sub, + Operator::GlobalSet { global_index: self.remaining_points_index.as_u32() }, + ]); + + self.accumulated_cost = 0; + } + } + _ => {} + } + state.push_operator(operator); + + Ok(()) + } +} diff --git a/lib/vm/src/module.rs b/lib/vm/src/module.rs index e483d583943..47f48b5d032 100644 --- a/lib/vm/src/module.rs +++ b/lib/vm/src/module.rs @@ -19,7 +19,7 @@ use wasmer_types::{ TableIndex, TableInitializer, TableType, }; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct ModuleId { id: usize, } @@ -41,7 +41,7 @@ impl Default for ModuleId { /// A translated WebAssembly module, excluding the function bodies and /// memory initializers. -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct ModuleInfo { /// A unique identifier (within this process) for this module. /// diff --git a/tests/compilers/main.rs b/tests/compilers/main.rs index 135af8e2a23..1fb24c18640 100644 --- a/tests/compilers/main.rs +++ b/tests/compilers/main.rs @@ -5,6 +5,7 @@ //! on what's available on the target. mod imports; +mod metering; mod middlewares; mod multi_value_imports; mod native_functions; diff --git a/tests/compilers/metering.rs b/tests/compilers/metering.rs new file mode 100644 index 00000000000..77509136ca3 --- /dev/null +++ b/tests/compilers/metering.rs @@ -0,0 +1,168 @@ +use crate::utils::get_store_with_middlewares; +use anyhow::Result; +use wasmer_middlewares::Metering; + +use std::sync::Arc; +use wasmer::wasmparser::Operator; +use wasmer::*; + +fn cost_always_one(_: &Operator) -> u64 { + 1 +} + +fn run_add_with_limit(limit: u64) -> Result<()> { + let store = get_store_with_middlewares(std::iter::once(Arc::new(Metering::new( + limit, + cost_always_one, + )) as Arc)); + let wat = r#"(module + (func (export "add") (param i32 i32) (result i32) + (i32.add (local.get 0) + (local.get 1))) +)"#; + let module = Module::new(&store, wat).unwrap(); + + let import_object = imports! {}; + + let instance = Instance::new(&module, &import_object)?; + + let f: NativeFunc<(i32, i32), i32> = instance.exports.get_native_function("add")?; + f.call(4, 6)?; + Ok(()) +} + +fn run_loop(limit: u64, iter_count: i32) -> Result<()> { + let store = get_store_with_middlewares(std::iter::once(Arc::new(Metering::new( + limit, + cost_always_one, + )) as Arc)); + let wat = r#"(module + (func (export "test") (param i32) + (local i32) + (local.set 1 (i32.const 0)) + (loop + (local.get 1) + (i32.const 1) + (i32.add) + (local.tee 1) + (local.get 0) + (i32.ne) + (br_if 0) + ) + ) +)"#; + let module = Module::new(&store, wat).unwrap(); + + let import_object = imports! {}; + + let instance = Instance::new(&module, &import_object)?; + + let f: NativeFunc = instance.exports.get_native_function("test")?; + f.call(iter_count)?; + Ok(()) +} + +#[test] +fn metering_ok() -> Result<()> { + assert!(run_add_with_limit(4).is_ok()); + Ok(()) +} + +#[test] +fn metering_fail() -> Result<()> { + assert!(run_add_with_limit(3).is_err()); + Ok(()) +} + +#[test] +fn loop_once() -> Result<()> { + assert!(run_loop(12, 1).is_ok()); + assert!(run_loop(11, 1).is_err()); + Ok(()) +} + +#[test] +fn loop_twice() -> Result<()> { + assert!(run_loop(19, 2).is_ok()); + assert!(run_loop(18, 2).is_err()); + Ok(()) +} + +/// Ported from https://github.com/wasmerio/wasmer/blob/master/tests/middleware_common.rs +#[test] +fn complex_loop() -> Result<()> { + // Assemblyscript + // export function add_to(x: i32, y: i32): i32 { + // for(var i = 0; i < x; i++){ + // if(i % 1 == 0){ + // y += i; + // } else { + // y *= i + // } + // } + // return y; + // } + static WAT: &'static str = r#" + (module + (type $t0 (func (param i32 i32) (result i32))) + (type $t1 (func)) + (func $add_to (export "add_to") (type $t0) (param $p0 i32) (param $p1 i32) (result i32) + (local $l0 i32) + block $B0 + i32.const 0 + set_local $l0 + loop $L1 + get_local $l0 + get_local $p0 + i32.lt_s + i32.eqz + br_if $B0 + get_local $l0 + i32.const 1 + i32.rem_s + i32.const 0 + i32.eq + if $I2 + get_local $p1 + get_local $l0 + i32.add + set_local $p1 + else + get_local $p1 + get_local $l0 + i32.mul + set_local $p1 + end + get_local $l0 + i32.const 1 + i32.add + set_local $l0 + br $L1 + unreachable + end + unreachable + end + get_local $p1) + (func $f1 (type $t1)) + (table $table (export "table") 1 anyfunc) + (memory $memory (export "memory") 0) + (global $g0 i32 (i32.const 8)) + (elem (i32.const 0) $f1)) + "#; + let store = get_store_with_middlewares(std::iter::once(Arc::new(Metering::new( + 100, + cost_always_one, + )) as Arc)); + let module = Module::new(&store, WAT).unwrap(); + + let import_object = imports! {}; + + let instance = Instance::new(&module, &import_object)?; + + let f: NativeFunc<(i32, i32), i32> = instance.exports.get_native_function("add_to")?; + + // FIXME: Since now a metering error is signaled with an `unreachable`, it is impossible to verify + // the error type. Fix this later. + f.call(10_000_000, 4).unwrap_err(); + Ok(()) +} diff --git a/tests/compilers/middlewares.rs b/tests/compilers/middlewares.rs index 7b350109e0a..939c72b090f 100644 --- a/tests/compilers/middlewares.rs +++ b/tests/compilers/middlewares.rs @@ -15,8 +15,8 @@ struct Add2Mul { value_off: i32, } -impl FunctionMiddlewareGenerator for Add2MulGen { - fn generate<'a>(&self, _: LocalFunctionIndex) -> Box { +impl ModuleMiddleware for Add2MulGen { + fn generate_function_middleware(&self, _: LocalFunctionIndex) -> Box { Box::new(Add2Mul { value_off: self.value_off, }) @@ -55,8 +55,8 @@ struct Fusion { state: i32, } -impl FunctionMiddlewareGenerator for FusionGen { - fn generate<'a>(&self, _: LocalFunctionIndex) -> Box { +impl ModuleMiddleware for FusionGen { + fn generate_function_middleware(&self, _: LocalFunctionIndex) -> Box { Box::new(Fusion { state: 0 }) } } @@ -91,7 +91,7 @@ impl FunctionMiddleware for Fusion { #[test] fn middleware_basic() -> Result<()> { let store = get_store_with_middlewares(std::iter::once( - Arc::new(Add2MulGen { value_off: 0 }) as Arc + Arc::new(Add2MulGen { value_off: 0 }) as Arc )); let wat = r#"(module (func (export "add") (param i32 i32) (result i32) @@ -113,7 +113,7 @@ fn middleware_basic() -> Result<()> { #[test] fn middleware_one_to_multi() -> Result<()> { let store = get_store_with_middlewares(std::iter::once( - Arc::new(Add2MulGen { value_off: 1 }) as Arc + Arc::new(Add2MulGen { value_off: 1 }) as Arc )); let wat = r#"(module (func (export "add") (param i32 i32) (result i32) @@ -135,7 +135,7 @@ fn middleware_one_to_multi() -> Result<()> { #[test] fn middleware_multi_to_one() -> Result<()> { let store = get_store_with_middlewares(std::iter::once( - Arc::new(FusionGen) as Arc + Arc::new(FusionGen) as Arc )); let wat = r#"(module (func (export "testfunc") (param i32 i32) (result i32) @@ -161,8 +161,8 @@ fn middleware_multi_to_one() -> Result<()> { fn middleware_chain_order_1() -> Result<()> { let store = get_store_with_middlewares( vec![ - Arc::new(Add2MulGen { value_off: 0 }) as Arc, - Arc::new(Add2MulGen { value_off: 2 }) as Arc, + Arc::new(Add2MulGen { value_off: 0 }) as Arc, + Arc::new(Add2MulGen { value_off: 2 }) as Arc, ] .into_iter(), ); @@ -187,8 +187,8 @@ fn middleware_chain_order_1() -> Result<()> { fn middleware_chain_order_2() -> Result<()> { let store = get_store_with_middlewares( vec![ - Arc::new(Add2MulGen { value_off: 2 }) as Arc, - Arc::new(Add2MulGen { value_off: 0 }) as Arc, + Arc::new(Add2MulGen { value_off: 2 }) as Arc, + Arc::new(Add2MulGen { value_off: 0 }) as Arc, ] .into_iter(), ); diff --git a/tests/compilers/utils.rs b/tests/compilers/utils.rs index 7173ecc20ac..9936cca0400 100644 --- a/tests/compilers/utils.rs +++ b/tests/compilers/utils.rs @@ -1,5 +1,5 @@ use std::sync::Arc; -use wasmer::{FunctionMiddlewareGenerator, Store}; +use wasmer::{ModuleMiddleware, Store}; use wasmer_compiler::CompilerConfig; use wasmer_engine::Engine; #[cfg(feature = "test-jit")] @@ -50,7 +50,7 @@ pub fn get_store(canonicalize_nans: bool) -> Store { Store::new(&get_engine(canonicalize_nans)) } -pub fn get_store_with_middlewares>>( +pub fn get_store_with_middlewares>>( middlewares: I, ) -> Store { let mut compiler_config = get_compiler(false);