make the value stack limit and call stack limit as a config parameter

This commit is contained in:
Guanqun Lu 2018-08-02 16:55:26 +08:00
parent 8ca6b4b860
commit a05fe3f9cd
13 changed files with 102 additions and 57 deletions

View File

@ -8,7 +8,7 @@ extern crate wabt;
use std::error; use std::error;
use std::fs::File; use std::fs::File;
use wasmi::{ImportsBuilder, Module, ModuleInstance, NopExternals, RuntimeValue}; use wasmi::{ImportsBuilder, InterpreterConfig, Module, ModuleInstance, NopExternals, RuntimeValue};
use test::Bencher; use test::Bencher;
@ -30,7 +30,7 @@ fn bench_tiny_keccak(b: &mut Bencher) {
"./wasm-kernel/target/wasm32-unknown-unknown/release/wasm_kernel.wasm", "./wasm-kernel/target/wasm32-unknown-unknown/release/wasm_kernel.wasm",
).expect("failed to load wasm_kernel. Is `build.rs` broken?"); ).expect("failed to load wasm_kernel. Is `build.rs` broken?");
let instance = ModuleInstance::new(&wasm_kernel, &ImportsBuilder::default()) let instance = ModuleInstance::new(&wasm_kernel, &ImportsBuilder::default(), &InterpreterConfig::default())
.expect("failed to instantiate wasm module") .expect("failed to instantiate wasm module")
.assert_no_start(); .assert_no_start();
@ -52,7 +52,7 @@ fn bench_rev_comp(b: &mut Bencher) {
"./wasm-kernel/target/wasm32-unknown-unknown/release/wasm_kernel.wasm", "./wasm-kernel/target/wasm32-unknown-unknown/release/wasm_kernel.wasm",
).expect("failed to load wasm_kernel. Is `build.rs` broken?"); ).expect("failed to load wasm_kernel. Is `build.rs` broken?");
let instance = ModuleInstance::new(&wasm_kernel, &ImportsBuilder::default()) let instance = ModuleInstance::new(&wasm_kernel, &ImportsBuilder::default(), &InterpreterConfig::default())
.expect("failed to instantiate wasm module") .expect("failed to instantiate wasm module")
.assert_no_start(); .assert_no_start();
@ -107,7 +107,7 @@ fn bench_regex_redux(b: &mut Bencher) {
"./wasm-kernel/target/wasm32-unknown-unknown/release/wasm_kernel.wasm", "./wasm-kernel/target/wasm32-unknown-unknown/release/wasm_kernel.wasm",
).expect("failed to load wasm_kernel. Is `build.rs` broken?"); ).expect("failed to load wasm_kernel. Is `build.rs` broken?");
let instance = ModuleInstance::new(&wasm_kernel, &ImportsBuilder::default()) let instance = ModuleInstance::new(&wasm_kernel, &ImportsBuilder::default(), &InterpreterConfig::default())
.expect("failed to instantiate wasm module") .expect("failed to instantiate wasm module")
.assert_no_start(); .assert_no_start();
@ -163,7 +163,7 @@ r#"
let module = Module::from_buffer(&wasm).unwrap(); let module = Module::from_buffer(&wasm).unwrap();
let instance = ModuleInstance::new(&module, &ImportsBuilder::default()) let instance = ModuleInstance::new(&module, &ImportsBuilder::default(), &InterpreterConfig::default())
.expect("failed to instantiate wasm module") .expect("failed to instantiate wasm module")
.assert_no_start(); .assert_no_start();
@ -197,7 +197,7 @@ r#"
let module = Module::from_buffer(&wasm).unwrap(); let module = Module::from_buffer(&wasm).unwrap();
let instance = ModuleInstance::new(&module, &ImportsBuilder::default()) let instance = ModuleInstance::new(&module, &ImportsBuilder::default(), &InterpreterConfig::default())
.expect("failed to instantiate wasm module") .expect("failed to instantiate wasm module")
.assert_no_start(); .assert_no_start();
@ -232,7 +232,7 @@ fn recursive_ok(b: &mut Bencher) {
).unwrap(); ).unwrap();
let module = Module::from_buffer(&wasm).unwrap(); let module = Module::from_buffer(&wasm).unwrap();
let instance = ModuleInstance::new(&module, &ImportsBuilder::default()) let instance = ModuleInstance::new(&module, &ImportsBuilder::default(), &InterpreterConfig::default())
.expect("failed to instantiate wasm module") .expect("failed to instantiate wasm module")
.assert_no_start(); .assert_no_start();
@ -266,7 +266,7 @@ fn recursive_trap(b: &mut Bencher) {
).unwrap(); ).unwrap();
let module = Module::from_buffer(&wasm).unwrap(); let module = Module::from_buffer(&wasm).unwrap();
let instance = ModuleInstance::new(&module, &ImportsBuilder::default()) let instance = ModuleInstance::new(&module, &ImportsBuilder::default(), &InterpreterConfig::default())
.expect("failed to instantiate wasm module") .expect("failed to instantiate wasm module")
.assert_no_start(); .assert_no_start();

View File

@ -4,7 +4,7 @@ extern crate wasmi;
use std::env::args; use std::env::args;
use std::fs::File; use std::fs::File;
use wasmi::{ModuleInstance, NopExternals, RuntimeValue, ImportsBuilder, Module}; use wasmi::{ModuleInstance, NopExternals, RuntimeValue, ImportsBuilder, InterpreterConfig, Module};
fn load_from_file(filename: &str) -> Module { fn load_from_file(filename: &str) -> Module {
use std::io::prelude::*; use std::io::prelude::*;
@ -31,7 +31,7 @@ fn main() {
// - a module declaration // - a module declaration
// - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here // - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here
// This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197 // This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197
let main = ModuleInstance::new(&module, &ImportsBuilder::default()) let main = ModuleInstance::new(&module, &ImportsBuilder::default(), &InterpreterConfig::default())
.expect("Failed to instantiate module") .expect("Failed to instantiate module")
.run_start(&mut NopExternals) .run_start(&mut NopExternals)
.expect("Failed to run start function in module"); .expect("Failed to run start function in module");

View File

@ -4,7 +4,7 @@ extern crate wasmi;
use std::env::args; use std::env::args;
use parity_wasm::elements::{Internal, External, Type, FunctionType, ValueType}; use parity_wasm::elements::{Internal, External, Type, FunctionType, ValueType};
use wasmi::{RuntimeValue, ModuleInstance, NopExternals, ImportsBuilder}; use wasmi::{RuntimeValue, ModuleInstance, NopExternals, ImportsBuilder, InterpreterConfig};
fn main() { fn main() {
@ -76,7 +76,7 @@ fn main() {
// - a module declaration // - a module declaration
// - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here // - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here
// This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197 // This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197
let main = ModuleInstance::new(&loaded_module, &ImportsBuilder::default()) let main = ModuleInstance::new(&loaded_module, &ImportsBuilder::default(), &InterpreterConfig::default())
.expect("Failed to instantiate module") .expect("Failed to instantiate module")
.run_start(&mut NopExternals) .run_start(&mut NopExternals)
.expect("Failed to run start function in module"); .expect("Failed to run start function in module");

View File

@ -7,8 +7,8 @@ use std::fs::File;
use wasmi::{ use wasmi::{
Error as InterpreterError, ModuleInstance, ModuleRef, Error as InterpreterError, ModuleInstance, ModuleRef,
Externals, RuntimeValue, FuncRef, ModuleImportResolver, Externals, RuntimeValue, FuncRef, ModuleImportResolver,
FuncInstance, HostError, ImportsBuilder, Signature, ValueType, FuncInstance, HostError, ImportsBuilder, InterpreterConfig, Signature,
RuntimeArgs, Trap, ValueType, RuntimeArgs, Trap,
}; };
#[derive(Debug)] #[derive(Debug)]
@ -201,7 +201,7 @@ fn instantiate(path: &str) -> Result<ModuleRef, Error> {
let mut imports = ImportsBuilder::new(); let mut imports = ImportsBuilder::new();
imports.push_resolver("env", &RuntimeModuleImportResolver); imports.push_resolver("env", &RuntimeModuleImportResolver);
let instance = ModuleInstance::new(&module, &imports)? let instance = ModuleInstance::new(&module, &imports, &InterpreterConfig::default())?
.assert_no_start(); .assert_no_start();
Ok(instance) Ok(instance)

View File

@ -7,9 +7,9 @@ use std::env::args;
use std::fs::File; use std::fs::File;
use wasmi::{ use wasmi::{
Error, FuncInstance, FuncRef, GlobalDescriptor, GlobalInstance, GlobalRef, Error, FuncInstance, FuncRef, GlobalDescriptor, GlobalInstance, GlobalRef,
ImportsBuilder, MemoryDescriptor, MemoryInstance, MemoryRef, Module, ImportsBuilder, InterpreterConfig, MemoryDescriptor, MemoryInstance,
ModuleImportResolver, ModuleInstance, NopExternals, RuntimeValue, Signature, MemoryRef, Module, ModuleImportResolver, ModuleInstance, NopExternals,
TableDescriptor, TableInstance, TableRef}; RuntimeValue, Signature, TableDescriptor, TableInstance, TableRef};
use wasmi::memory_units::*; use wasmi::memory_units::*;
fn load_from_file(filename: &str) -> Module { fn load_from_file(filename: &str) -> Module {
@ -75,6 +75,7 @@ fn main() {
.with_resolver("global.Math", &ResolveAll) .with_resolver("global.Math", &ResolveAll)
.with_resolver("asm2wasm", &ResolveAll) .with_resolver("asm2wasm", &ResolveAll)
.with_resolver("spectest", &ResolveAll), .with_resolver("spectest", &ResolveAll),
&InterpreterConfig::default()
).expect("Failed to instantiate module") ).expect("Failed to instantiate module")
.run_start(&mut NopExternals) .run_start(&mut NopExternals)
.expect("Failed to run start function in module"); .expect("Failed to run start function in module");

View File

@ -3,7 +3,7 @@ use std::fmt;
use parity_wasm::elements::Local; use parity_wasm::elements::Local;
use {Trap, TrapKind, Signature}; use {Trap, TrapKind, Signature};
use host::Externals; use host::Externals;
use runner::{check_function_args, Interpreter, InterpreterState}; use runner::{check_function_args, InterpreterConfig, Interpreter, InterpreterState};
use value::RuntimeValue; use value::RuntimeValue;
use types::ValueType; use types::ValueType;
use module::ModuleInstance; use module::ModuleInstance;
@ -141,11 +141,12 @@ impl FuncInstance {
func: &FuncRef, func: &FuncRef,
args: &[RuntimeValue], args: &[RuntimeValue],
externals: &mut E, externals: &mut E,
config: &InterpreterConfig,
) -> Result<Option<RuntimeValue>, Trap> { ) -> Result<Option<RuntimeValue>, Trap> {
check_function_args(func.signature(), &args).map_err(|_| TrapKind::UnexpectedSignature)?; check_function_args(func.signature(), &args).map_err(|_| TrapKind::UnexpectedSignature)?;
match *func.as_internal() { match *func.as_internal() {
FuncInstanceInternal::Internal { .. } => { FuncInstanceInternal::Internal { .. } => {
let mut interpreter = Interpreter::new(func, args)?; let mut interpreter = Interpreter::new(func, args, config)?;
interpreter.start_execution(externals) interpreter.start_execution(externals)
} }
FuncInstanceInternal::Host { FuncInstanceInternal::Host {
@ -172,11 +173,12 @@ impl FuncInstance {
pub fn invoke_resumable<'args>( pub fn invoke_resumable<'args>(
func: &FuncRef, func: &FuncRef,
args: &'args [RuntimeValue], args: &'args [RuntimeValue],
config: &InterpreterConfig,
) -> Result<FuncInvocation<'args>, Trap> { ) -> Result<FuncInvocation<'args>, Trap> {
check_function_args(func.signature(), &args).map_err(|_| TrapKind::UnexpectedSignature)?; check_function_args(func.signature(), &args).map_err(|_| TrapKind::UnexpectedSignature)?;
match *func.as_internal() { match *func.as_internal() {
FuncInstanceInternal::Internal { .. } => { FuncInstanceInternal::Internal { .. } => {
let interpreter = Interpreter::new(func, args)?; let interpreter = Interpreter::new(func, args, config)?;
Ok(FuncInvocation { Ok(FuncInvocation {
kind: FuncInvocationKind::Internal(interpreter), kind: FuncInvocationKind::Internal(interpreter),
}) })

View File

@ -80,19 +80,19 @@ pub trait ImportResolver {
/// # Examples /// # Examples
/// ///
/// ```rust /// ```rust
/// use wasmi::{ModuleInstance, ImportsBuilder}; /// use wasmi::{ModuleInstance, ImportsBuilder, InterpreterConfig};
/// # /// #
/// # struct EnvModuleResolver; /// # struct EnvModuleResolver;
/// # impl ::wasmi::ModuleImportResolver for EnvModuleResolver { } /// # impl ::wasmi::ModuleImportResolver for EnvModuleResolver { }
/// # fn func() -> Result<(), ::wasmi::Error> { /// # fn func() -> Result<(), ::wasmi::Error> {
/// # let module = wasmi::Module::from_buffer(&[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]).unwrap(); /// # let module = wasmi::Module::from_buffer(&[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]).unwrap();
/// # let other_instance = ModuleInstance::new(&module, &ImportsBuilder::default())?.assert_no_start(); /// # let other_instance = ModuleInstance::new(&module, &ImportsBuilder::default(), &InterpreterConfig::default())?.assert_no_start();
/// ///
/// let imports = ImportsBuilder::new() /// let imports = ImportsBuilder::new()
/// .with_resolver("env", &EnvModuleResolver) /// .with_resolver("env", &EnvModuleResolver)
/// // Note, that ModuleInstance can be a resolver too. /// // Note, that ModuleInstance can be a resolver too.
/// .with_resolver("other_instance", &other_instance); /// .with_resolver("other_instance", &other_instance);
/// let instance = ModuleInstance::new(&module, &imports)?.assert_no_start(); /// let instance = ModuleInstance::new(&module, &imports, &InterpreterConfig::default())?.assert_no_start();
/// ///
/// # Ok(()) /// # Ok(())
/// # } /// # }

View File

@ -51,7 +51,7 @@
//! extern crate wasmi; //! extern crate wasmi;
//! extern crate wabt; //! extern crate wabt;
//! //!
//! use wasmi::{ModuleInstance, ImportsBuilder, NopExternals, RuntimeValue}; //! use wasmi::{ModuleInstance, ImportsBuilder, InterpreterConfig, NopExternals, RuntimeValue};
//! //!
//! fn main() { //! fn main() {
//! // Parse WAT (WebAssembly Text format) into wasm bytecode. //! // Parse WAT (WebAssembly Text format) into wasm bytecode.
@ -76,7 +76,8 @@
//! let instance = //! let instance =
//! ModuleInstance::new( //! ModuleInstance::new(
//! &module, //! &module,
//! &ImportsBuilder::default() //! &ImportsBuilder::default(),
//! &InterpreterConfig::default()
//! ) //! )
//! .expect("failed to instantiate wasm module") //! .expect("failed to instantiate wasm module")
//! .assert_no_start(); //! .assert_no_start();
@ -380,6 +381,7 @@ pub use self::module::{ModuleInstance, ModuleRef, ExternVal, NotStartedModuleRef
pub use self::global::{GlobalInstance, GlobalRef}; pub use self::global::{GlobalInstance, GlobalRef};
pub use self::func::{FuncInstance, FuncRef, FuncInvocation, ResumableError}; pub use self::func::{FuncInstance, FuncRef, FuncInvocation, ResumableError};
pub use self::types::{Signature, ValueType, GlobalDescriptor, TableDescriptor, MemoryDescriptor}; pub use self::types::{Signature, ValueType, GlobalDescriptor, TableDescriptor, MemoryDescriptor};
pub use self::runner::InterpreterConfig;
/// WebAssembly-specific sizes and units. /// WebAssembly-specific sizes and units.
pub mod memory_units { pub mod memory_units {

View File

@ -9,6 +9,7 @@ use {Module, Error, Signature, MemoryInstance, RuntimeValue, TableInstance};
use imports::ImportResolver; use imports::ImportResolver;
use global::{GlobalInstance, GlobalRef}; use global::{GlobalInstance, GlobalRef};
use func::{FuncRef, FuncBody, FuncInstance}; use func::{FuncRef, FuncBody, FuncInstance};
use runner::InterpreterConfig;
use table::TableRef; use table::TableRef;
use memory::MemoryRef; use memory::MemoryRef;
use host::Externals; use host::Externals;
@ -155,6 +156,7 @@ pub struct ModuleInstance {
memories: RefCell<Vec<MemoryRef>>, memories: RefCell<Vec<MemoryRef>>,
globals: RefCell<Vec<GlobalRef>>, globals: RefCell<Vec<GlobalRef>>,
exports: RefCell<HashMap<String, ExternVal>>, exports: RefCell<HashMap<String, ExternVal>>,
config: InterpreterConfig,
} }
impl ModuleInstance { impl ModuleInstance {
@ -166,6 +168,7 @@ impl ModuleInstance {
memories: RefCell::new(Vec::new()), memories: RefCell::new(Vec::new()),
globals: RefCell::new(Vec::new()), globals: RefCell::new(Vec::new()),
exports: RefCell::new(HashMap::new()), exports: RefCell::new(HashMap::new()),
config: Default::default(),
} }
} }
@ -399,6 +402,7 @@ impl ModuleInstance {
pub fn with_externvals<'a, 'i, I: Iterator<Item = &'i ExternVal>>( pub fn with_externvals<'a, 'i, I: Iterator<Item = &'i ExternVal>>(
loaded_module: &'a Module, loaded_module: &'a Module,
extern_vals: I, extern_vals: I,
config: &InterpreterConfig,
) -> Result<NotStartedModuleRef<'a>, Error> { ) -> Result<NotStartedModuleRef<'a>, Error> {
let module = loaded_module.module(); let module = loaded_module.module();
@ -449,6 +453,7 @@ impl ModuleInstance {
Ok(NotStartedModuleRef { Ok(NotStartedModuleRef {
loaded_module, loaded_module,
instance: module_ref, instance: module_ref,
config: config.clone(),
}) })
} }
@ -474,14 +479,15 @@ impl ModuleInstance {
/// # Examples /// # Examples
/// ///
/// ```rust /// ```rust
/// use wasmi::{ModuleInstance, ImportsBuilder, NopExternals}; /// use wasmi::{ModuleInstance, ImportsBuilder, InterpreterConfig, NopExternals};
/// # fn func() -> Result<(), ::wasmi::Error> { /// # fn func() -> Result<(), ::wasmi::Error> {
/// # let module = wasmi::Module::from_buffer(&[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]).unwrap(); /// # let module = wasmi::Module::from_buffer(&[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]).unwrap();
/// ///
/// // ModuleInstance::new returns instance which `start` function isn't called. /// // ModuleInstance::new returns instance which `start` function isn't called.
/// let not_started = ModuleInstance::new( /// let not_started = ModuleInstance::new(
/// &module, /// &module,
/// &ImportsBuilder::default() /// &ImportsBuilder::default(),
/// &InterpreterConfig::default()
/// )?; /// )?;
/// // Call `start` function if any. /// // Call `start` function if any.
/// let instance = not_started.run_start(&mut NopExternals)?; /// let instance = not_started.run_start(&mut NopExternals)?;
@ -494,14 +500,15 @@ impl ModuleInstance {
/// instantiated module without calling `start` function. /// instantiated module without calling `start` function.
/// ///
/// ```rust /// ```rust
/// use wasmi::{ModuleInstance, ImportsBuilder, NopExternals}; /// use wasmi::{ModuleInstance, ImportsBuilder, InterpreterConfig, NopExternals};
/// # fn func() -> Result<(), ::wasmi::Error> { /// # fn func() -> Result<(), ::wasmi::Error> {
/// # let module = wasmi::Module::from_buffer(&[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]).unwrap(); /// # let module = wasmi::Module::from_buffer(&[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]).unwrap();
/// ///
/// // This will panic if the module actually contain `start` function. /// // This will panic if the module actually contain `start` function.
/// let not_started = ModuleInstance::new( /// let not_started = ModuleInstance::new(
/// &module, /// &module,
/// &ImportsBuilder::default() /// &ImportsBuilder::default(),
/// &InterpreterConfig::default()
/// )?.assert_no_start(); /// )?.assert_no_start();
/// ///
/// # Ok(()) /// # Ok(())
@ -515,6 +522,7 @@ impl ModuleInstance {
pub fn new<'m, I: ImportResolver>( pub fn new<'m, I: ImportResolver>(
loaded_module: &'m Module, loaded_module: &'m Module,
imports: &I, imports: &I,
config: &InterpreterConfig
) -> Result<NotStartedModuleRef<'m>, Error> { ) -> Result<NotStartedModuleRef<'m>, Error> {
let module = loaded_module.module(); let module = loaded_module.module();
@ -551,7 +559,7 @@ impl ModuleInstance {
extern_vals.push(extern_val); extern_vals.push(extern_val);
} }
Self::with_externvals(loaded_module, extern_vals.iter()) Self::with_externvals(loaded_module, extern_vals.iter(), config)
} }
/// Invoke exported function by a name. /// Invoke exported function by a name.
@ -574,7 +582,7 @@ impl ModuleInstance {
/// ```rust /// ```rust
/// # extern crate wasmi; /// # extern crate wasmi;
/// # extern crate wabt; /// # extern crate wabt;
/// # use wasmi::{ModuleInstance, ImportsBuilder, NopExternals, RuntimeValue}; /// # use wasmi::{ModuleInstance, ImportsBuilder, InterpreterConfig, NopExternals, RuntimeValue};
/// # fn main() { /// # fn main() {
/// # let wasm_binary: Vec<u8> = wabt::wat2wasm( /// # let wasm_binary: Vec<u8> = wabt::wat2wasm(
/// # r#" /// # r#"
@ -590,7 +598,8 @@ impl ModuleInstance {
/// # let module = wasmi::Module::from_buffer(&wasm_binary).expect("failed to load wasm"); /// # let module = wasmi::Module::from_buffer(&wasm_binary).expect("failed to load wasm");
/// # let instance = ModuleInstance::new( /// # let instance = ModuleInstance::new(
/// # &module, /// # &module,
/// # &ImportsBuilder::default() /// # &ImportsBuilder::default(),
/// # &InterpreterConfig::default()
/// # ).expect("failed to instantiate wasm module").assert_no_start(); /// # ).expect("failed to instantiate wasm module").assert_no_start();
/// assert_eq!( /// assert_eq!(
/// instance.invoke_export( /// instance.invoke_export(
@ -624,7 +633,7 @@ impl ModuleInstance {
}; };
check_function_args(func_instance.signature(), &args)?; check_function_args(func_instance.signature(), &args)?;
FuncInstance::invoke(&func_instance, args, externals) FuncInstance::invoke(&func_instance, args, externals, &self.config)
.map_err(|t| Error::Trap(t)) .map_err(|t| Error::Trap(t))
} }
@ -657,6 +666,7 @@ impl ModuleInstance {
pub struct NotStartedModuleRef<'a> { pub struct NotStartedModuleRef<'a> {
loaded_module: &'a Module, loaded_module: &'a Module,
instance: ModuleRef, instance: ModuleRef,
config: InterpreterConfig,
} }
impl<'a> NotStartedModuleRef<'a> { impl<'a> NotStartedModuleRef<'a> {
@ -683,7 +693,7 @@ impl<'a> NotStartedModuleRef<'a> {
let start_func = self.instance.func_by_index(start_fn_idx).expect( let start_func = self.instance.func_by_index(start_fn_idx).expect(
"Due to validation start function should exists", "Due to validation start function should exists",
); );
FuncInstance::invoke(&start_func, &[], state)?; FuncInstance::invoke(&start_func, &[], state, &self.config)?;
} }
Ok(self.instance) Ok(self.instance)
} }
@ -765,6 +775,7 @@ pub fn check_limits(limits: &ResizableLimits) -> Result<(), Error> {
mod tests { mod tests {
use imports::ImportsBuilder; use imports::ImportsBuilder;
use func::FuncInstance; use func::FuncInstance;
use runner::InterpreterConfig;
use types::{Signature, ValueType}; use types::{Signature, ValueType};
use super::{ModuleInstance, ExternVal}; use super::{ModuleInstance, ExternVal};
use tests::parse_wat; use tests::parse_wat;
@ -781,7 +792,8 @@ mod tests {
); );
ModuleInstance::new( ModuleInstance::new(
&module_with_start, &module_with_start,
&ImportsBuilder::default() &ImportsBuilder::default(),
&InterpreterConfig::default()
).unwrap().assert_no_start(); ).unwrap().assert_no_start();
} }
@ -801,6 +813,7 @@ mod tests {
[ [
ExternVal::Func(FuncInstance::alloc_host(Signature::new(&[][..], None), 0),) ExternVal::Func(FuncInstance::alloc_host(Signature::new(&[][..], None), 0),)
].iter(), ].iter(),
&InterpreterConfig::default()
).is_ok() ).is_ok()
); );
@ -812,11 +825,12 @@ mod tests {
ExternVal::Func(FuncInstance::alloc_host(Signature::new(&[][..], None), 0)), ExternVal::Func(FuncInstance::alloc_host(Signature::new(&[][..], None), 0)),
ExternVal::Func(FuncInstance::alloc_host(Signature::new(&[][..], None), 1)), ExternVal::Func(FuncInstance::alloc_host(Signature::new(&[][..], None), 1)),
].iter(), ].iter(),
&InterpreterConfig::default()
).is_err() ).is_err()
); );
// externval vector is shorter than import count. // externval vector is shorter than import count.
assert!(ModuleInstance::with_externvals(&module_with_single_import, [].iter(),).is_err()); assert!(ModuleInstance::with_externvals(&module_with_single_import, [].iter(), &InterpreterConfig::default()).is_err());
// externval vector has an unexpected type. // externval vector has an unexpected type.
assert!( assert!(
@ -828,6 +842,7 @@ mod tests {
0 0
),) ),)
].iter(), ].iter(),
&InterpreterConfig::default()
).is_err() ).is_err()
); );
} }

View File

@ -19,10 +19,9 @@ use nan_preserving_float::{F32, F64};
use isa; use isa;
/// Maximum number of entries in value stack. /// Maximum number of entries in value stack.
pub const DEFAULT_VALUE_STACK_LIMIT: usize = (1024 * 1024) / ::std::mem::size_of::<RuntimeValue>(); const DEFAULT_VALUE_STACK_LIMIT: usize = (1024 * 1024) / ::std::mem::size_of::<RuntimeValue>();
// TODO: Make these parameters changeble. const DEFAULT_CALL_STACK_LIMIT: usize = 64 * 1024;
pub const DEFAULT_CALL_STACK_LIMIT: usize = 64 * 1024;
/// Interpreter action to execute after executing instruction. /// Interpreter action to execute after executing instruction.
pub enum InstructionOutcome { pub enum InstructionOutcome {
@ -65,17 +64,35 @@ enum RunResult {
NestedCall(FuncRef), NestedCall(FuncRef),
} }
#[derive(Clone, Debug)]
/// Config parameters for interpreter
pub struct InterpreterConfig {
pub value_stack_limit: usize,
pub call_stack_limit: usize,
}
impl Default for InterpreterConfig {
fn default() -> Self {
return InterpreterConfig {
value_stack_limit: DEFAULT_VALUE_STACK_LIMIT,
call_stack_limit: DEFAULT_CALL_STACK_LIMIT,
}
}
}
/// Function interpreter. /// Function interpreter.
pub struct Interpreter { pub struct Interpreter {
value_stack: ValueStack, value_stack: ValueStack,
call_stack: Vec<FunctionContext>, call_stack: Vec<FunctionContext>,
return_type: Option<ValueType>, return_type: Option<ValueType>,
state: InterpreterState, state: InterpreterState,
config: InterpreterConfig,
} }
impl Interpreter { impl Interpreter {
pub fn new(func: &FuncRef, args: &[RuntimeValue]) -> Result<Interpreter, Trap> { pub fn new(func: &FuncRef, args: &[RuntimeValue], config: &InterpreterConfig) -> Result<Interpreter, Trap> {
let mut value_stack = ValueStack::with_limit(DEFAULT_VALUE_STACK_LIMIT); let mut value_stack = ValueStack::with_limit(config.value_stack_limit);
for arg in args { for arg in args {
value_stack value_stack
.push(*arg) .push(*arg)
@ -97,6 +114,7 @@ impl Interpreter {
call_stack, call_stack,
return_type, return_type,
state: InterpreterState::Initialized, state: InterpreterState::Initialized,
config: config.clone(),
}) })
} }
@ -187,7 +205,7 @@ impl Interpreter {
} }
}, },
RunResult::NestedCall(nested_func) => { RunResult::NestedCall(nested_func) => {
if self.call_stack.len() + 1 >= DEFAULT_CALL_STACK_LIMIT { if self.call_stack.len() + 1 >= self.config.call_stack_limit {
return Err(TrapKind::StackOverflow.into()); return Err(TrapKind::StackOverflow.into());
} }
@ -202,7 +220,7 @@ impl Interpreter {
// We push the function context first. If the VM is not resumable, it does no harm. If it is, we then save the context here. // We push the function context first. If the VM is not resumable, it does no harm. If it is, we then save the context here.
self.call_stack.push(function_context); self.call_stack.push(function_context);
let return_val = match FuncInstance::invoke(&nested_func, &args, externals) { let return_val = match FuncInstance::invoke(&nested_func, &args, externals, &self.config) {
Ok(val) => val, Ok(val) => val,
Err(trap) => { Err(trap) => {
if trap.kind().is_host() { if trap.kind().is_host() {

View File

@ -1,5 +1,5 @@
use { use {
Error, Signature, Externals, FuncInstance, FuncRef, HostError, ImportsBuilder, Error, Signature, Externals, FuncInstance, FuncRef, HostError, ImportsBuilder, InterpreterConfig,
MemoryInstance, MemoryRef, TableInstance, TableRef, ModuleImportResolver, ModuleInstance, ModuleRef, MemoryInstance, MemoryRef, TableInstance, TableRef, ModuleImportResolver, ModuleInstance, ModuleRef,
RuntimeValue, RuntimeArgs, TableDescriptor, MemoryDescriptor, Trap, TrapKind, ResumableError, RuntimeValue, RuntimeArgs, TableDescriptor, MemoryDescriptor, Trap, TrapKind, ResumableError,
}; };
@ -239,7 +239,7 @@ fn call_host_func() {
let mut env = TestHost::new(); let mut env = TestHost::new();
let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env), &InterpreterConfig::default())
.expect("Failed to instantiate module") .expect("Failed to instantiate module")
.assert_no_start(); .assert_no_start();
@ -270,14 +270,14 @@ fn resume_call_host_func() {
let mut env = TestHost::new(); let mut env = TestHost::new();
let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env), &InterpreterConfig::default())
.expect("Failed to instantiate module") .expect("Failed to instantiate module")
.assert_no_start(); .assert_no_start();
let export = instance.export_by_name("test").unwrap(); let export = instance.export_by_name("test").unwrap();
let func_instance = export.as_func().unwrap(); let func_instance = export.as_func().unwrap();
let mut invocation = FuncInstance::invoke_resumable(&func_instance, &[]).unwrap(); let mut invocation = FuncInstance::invoke_resumable(&func_instance, &[], &InterpreterConfig::default()).unwrap();
let result = invocation.start_execution(&mut env); let result = invocation.start_execution(&mut env);
match result { match result {
Err(ResumableError::Trap(_)) => {}, Err(ResumableError::Trap(_)) => {},
@ -312,7 +312,7 @@ fn host_err() {
let mut env = TestHost::new(); let mut env = TestHost::new();
let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env), &InterpreterConfig::default())
.expect("Failed to instantiate module") .expect("Failed to instantiate module")
.assert_no_start(); .assert_no_start();
@ -347,7 +347,7 @@ fn modify_mem_with_host_funcs() {
let mut env = TestHost::new(); let mut env = TestHost::new();
let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env), &InterpreterConfig::default())
.expect("Failed to instantiate module") .expect("Failed to instantiate module")
.assert_no_start(); .assert_no_start();
@ -391,7 +391,7 @@ fn pull_internal_mem_from_module() {
trap_sub_result: None, trap_sub_result: None,
}; };
let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env), &InterpreterConfig::default())
.expect("Failed to instantiate module") .expect("Failed to instantiate module")
.assert_no_start(); .assert_no_start();
@ -442,7 +442,7 @@ fn recursion() {
let mut env = TestHost::new(); let mut env = TestHost::new();
let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env)) let instance = ModuleInstance::new(&module, &ImportsBuilder::new().with_resolver("env", &env), &InterpreterConfig::default())
.expect("Failed to instantiate module") .expect("Failed to instantiate module")
.assert_no_start(); .assert_no_start();
@ -554,6 +554,7 @@ fn defer_providing_externals() {
let instance = ModuleInstance::new( let instance = ModuleInstance::new(
&module, &module,
&ImportsBuilder::new().with_resolver("host", &host_import_resolver), &ImportsBuilder::new().with_resolver("host", &host_import_resolver),
&InterpreterConfig::default()
).expect("Failed to instantiate module") ).expect("Failed to instantiate module")
.assert_no_start(); .assert_no_start();
@ -673,6 +674,7 @@ fn two_envs_one_externals() {
let trusted_instance = ModuleInstance::new( let trusted_instance = ModuleInstance::new(
&trusted_module, &trusted_module,
&ImportsBuilder::new().with_resolver("env", &PrivilegedResolver), &ImportsBuilder::new().with_resolver("env", &PrivilegedResolver),
&InterpreterConfig::default()
).expect("Failed to instantiate module") ).expect("Failed to instantiate module")
.assert_no_start(); .assert_no_start();
@ -681,6 +683,7 @@ fn two_envs_one_externals() {
&ImportsBuilder::new() &ImportsBuilder::new()
.with_resolver("env", &OrdinaryResolver) .with_resolver("env", &OrdinaryResolver)
.with_resolver("trusted", &trusted_instance), .with_resolver("trusted", &trusted_instance),
&InterpreterConfig::default()
).expect("Failed to instantiate module") ).expect("Failed to instantiate module")
.assert_no_start(); .assert_no_start();
@ -788,6 +791,7 @@ fn dynamically_add_host_func() {
let instance = ModuleInstance::new( let instance = ModuleInstance::new(
&module, &module,
&ImportsBuilder::new().with_resolver("env", &host_externals), &ImportsBuilder::new().with_resolver("env", &host_externals),
&InterpreterConfig::default()
).expect("Failed to instantiate module") ).expect("Failed to instantiate module")
.assert_no_start(); .assert_no_start();

View File

@ -1,7 +1,8 @@
use { use {
Error, Signature, FuncRef, GlobalInstance, GlobalRef, ImportsBuilder, MemoryInstance, Error, Signature, FuncRef, GlobalInstance, GlobalRef, ImportsBuilder, MemoryInstance,
MemoryRef, ModuleImportResolver, ModuleInstance, NopExternals, RuntimeValue, MemoryRef, ModuleImportResolver, ModuleInstance, NopExternals, RuntimeValue,
TableInstance, TableRef, Module, GlobalDescriptor, TableDescriptor, MemoryDescriptor, TableInstance, TableRef, Module, GlobalDescriptor, TableDescriptor, MemoryDescriptor,
InterpreterConfig
}; };
use memory_units::Pages; use memory_units::Pages;
use std::fs::File; use std::fs::File;
@ -93,6 +94,7 @@ fn interpreter_inc_i32() {
let instance = ModuleInstance::new( let instance = ModuleInstance::new(
&module, &module,
&ImportsBuilder::new().with_resolver("env", &env), &ImportsBuilder::new().with_resolver("env", &env),
&InterpreterConfig::default()
).expect("Failed to instantiate module") ).expect("Failed to instantiate module")
.assert_no_start(); .assert_no_start();
@ -124,6 +126,7 @@ fn interpreter_accumulate_u8() {
let instance = ModuleInstance::new( let instance = ModuleInstance::new(
&module, &module,
&ImportsBuilder::new().with_resolver("env", &env), &ImportsBuilder::new().with_resolver("env", &env),
&InterpreterConfig::default()
).expect("Failed to instantiate module") ).expect("Failed to instantiate module")
.assert_no_start(); .assert_no_start();

View File

@ -6,7 +6,7 @@ use std::collections::HashMap;
use wabt::script::{self, Action, Command, CommandKind, ScriptParser, Value}; use wabt::script::{self, Action, Command, CommandKind, ScriptParser, Value};
use wasmi::memory_units::Pages; use wasmi::memory_units::Pages;
use wasmi::{Error as InterpreterError, Externals, FuncInstance, FuncRef, GlobalDescriptor, use wasmi::{Error as InterpreterError, Externals, FuncInstance, FuncRef, GlobalDescriptor,
GlobalInstance, GlobalRef, ImportResolver, ImportsBuilder, MemoryDescriptor, GlobalInstance, GlobalRef, ImportResolver, ImportsBuilder, InterpreterConfig, MemoryDescriptor,
MemoryInstance, MemoryRef, Module, ModuleImportResolver, ModuleInstance, ModuleRef, MemoryInstance, MemoryRef, Module, ModuleImportResolver, ModuleInstance, ModuleRef,
RuntimeArgs, RuntimeValue, Signature, TableDescriptor, TableInstance, TableRef, Trap}; RuntimeArgs, RuntimeValue, Signature, TableDescriptor, TableInstance, TableRef, Trap};
@ -261,7 +261,7 @@ fn try_load_module(wasm: &[u8]) -> Result<Module, Error> {
fn try_load(wasm: &[u8], spec_driver: &mut SpecDriver) -> Result<(), Error> { fn try_load(wasm: &[u8], spec_driver: &mut SpecDriver) -> Result<(), Error> {
let module = try_load_module(wasm)?; let module = try_load_module(wasm)?;
let instance = ModuleInstance::new(&module, &ImportsBuilder::default())?; let instance = ModuleInstance::new(&module, &ImportsBuilder::default(), &InterpreterConfig::default())?;
instance instance
.run_start(spec_driver.spec_module()) .run_start(spec_driver.spec_module())
.map_err(|trap| Error::Start(trap))?; .map_err(|trap| Error::Start(trap))?;
@ -274,7 +274,7 @@ fn load_module(
spec_driver: &mut SpecDriver, spec_driver: &mut SpecDriver,
) -> Result<ModuleRef, Error> { ) -> Result<ModuleRef, Error> {
let module = try_load_module(wasm)?; let module = try_load_module(wasm)?;
let instance = ModuleInstance::new(&module, spec_driver) let instance = ModuleInstance::new(&module, spec_driver, &InterpreterConfig::default())
.map_err(|e| Error::Load(e.to_string()))? .map_err(|e| Error::Load(e.to_string()))?
.run_start(spec_driver.spec_module()) .run_start(spec_driver.spec_module())
.map_err(|trap| Error::Start(trap))?; .map_err(|trap| Error::Start(trap))?;