mirror of
https://github.com/fluencelabs/parity-wasm
synced 2025-06-22 19:21:59 +00:00
env module stub
This commit is contained in:
66
src/interpreter/env.rs
Normal file
66
src/interpreter/env.rs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
use builder::module;
|
||||||
|
use elements::{Module, FunctionType};
|
||||||
|
use interpreter::Error;
|
||||||
|
use interpreter::module::{ModuleInstanceInterface, ItemIndex, CallerContext};
|
||||||
|
use interpreter::memory::MemoryInstance;
|
||||||
|
use interpreter::table::TableInstance;
|
||||||
|
use interpreter::value::RuntimeValue;
|
||||||
|
use interpreter::variable::VariableInstance;
|
||||||
|
|
||||||
|
pub struct EnvModuleInstance {
|
||||||
|
module: Module,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EnvModuleInstance {
|
||||||
|
pub fn new(module: Module) -> Result<Self, Error> {
|
||||||
|
Ok(EnvModuleInstance {
|
||||||
|
module: module,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModuleInstanceInterface for EnvModuleInstance {
|
||||||
|
fn execute_main(&self, _args: Vec<RuntimeValue>) -> Result<Option<RuntimeValue>, Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute(&self, _index: u32, _args: Vec<RuntimeValue>) -> Result<Option<RuntimeValue>, Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn module(&self) -> &Module {
|
||||||
|
&self.module
|
||||||
|
}
|
||||||
|
|
||||||
|
fn table(&self, _index: ItemIndex) -> Result<Arc<TableInstance>, Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn memory(&self, _index: ItemIndex) -> Result<Arc<MemoryInstance>, Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn global(&self, _index: ItemIndex) -> Result<Arc<VariableInstance>, Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_function(&self, _outer: CallerContext, _index: ItemIndex) -> Result<Option<RuntimeValue>, Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_function_indirect(&self, _outer: CallerContext, _table_index: ItemIndex, _type_index: u32, _func_index: u32) -> Result<Option<RuntimeValue>, Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_internal_function(&self, _outer: CallerContext, _index: u32, _function_type: Option<&FunctionType>) -> Result<Option<RuntimeValue>, Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn env_module() -> Result<EnvModuleInstance, Error> {
|
||||||
|
let module = module()
|
||||||
|
.memory().build() // TODO: limits
|
||||||
|
.build();
|
||||||
|
EnvModuleInstance::new(module)
|
||||||
|
}
|
@ -2,7 +2,7 @@ use std::sync::{Arc, Weak};
|
|||||||
use elements::{ImportSection, ImportEntry, External, Internal};
|
use elements::{ImportSection, ImportEntry, External, Internal};
|
||||||
use interpreter::Error;
|
use interpreter::Error;
|
||||||
use interpreter::memory::MemoryInstance;
|
use interpreter::memory::MemoryInstance;
|
||||||
use interpreter::module::{ModuleInstance, ItemIndex};
|
use interpreter::module::{ModuleInstanceInterface, ItemIndex};
|
||||||
use interpreter::program::ProgramInstanceEssence;
|
use interpreter::program::ProgramInstanceEssence;
|
||||||
use interpreter::table::TableInstance;
|
use interpreter::table::TableInstance;
|
||||||
use interpreter::variable::VariableInstance;
|
use interpreter::variable::VariableInstance;
|
||||||
@ -94,7 +94,7 @@ impl ModuleImports {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get module reference.
|
/// Get module reference.
|
||||||
pub fn module(&self, name: &str) -> Result<Arc<ModuleInstance>, Error> {
|
pub fn module(&self, name: &str) -> Result<Arc<ModuleInstanceInterface>, Error> {
|
||||||
self.program
|
self.program
|
||||||
.upgrade()
|
.upgrade()
|
||||||
.ok_or(Error::Program("program unloaded".into()))
|
.ok_or(Error::Program("program unloaded".into()))
|
||||||
@ -131,7 +131,7 @@ impl ModuleImports {
|
|||||||
Err(Error::Program(format!("wrong import {} from module {} (expecting global)", import.field(), import.module())))
|
Err(Error::Program(format!("wrong import {} from module {} (expecting global)", import.field(), import.module())))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn external_export(&self, import: &ImportEntry) -> Result<(Arc<ModuleInstance>, Internal), Error> {
|
fn external_export(&self, import: &ImportEntry) -> Result<(Arc<ModuleInstanceInterface>, Internal), Error> {
|
||||||
self.module(import.module())
|
self.module(import.module())
|
||||||
.and_then(|m| m.module().export_section()
|
.and_then(|m| m.module().export_section()
|
||||||
.ok_or(Error::Program(format!("trying to import from module {} without export section", import.module())))
|
.ok_or(Error::Program(format!("trying to import from module {} without export section", import.module())))
|
||||||
|
@ -48,6 +48,7 @@ impl Into<String> for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod env;
|
||||||
mod imports;
|
mod imports;
|
||||||
mod memory;
|
mod memory;
|
||||||
mod module;
|
mod module;
|
||||||
@ -61,6 +62,6 @@ mod variable;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
pub use self::module::ModuleInstance;
|
pub use self::module::{ModuleInstance, ModuleInstanceInterface};
|
||||||
pub use self::program::ProgramInstance;
|
pub use self::program::ProgramInstance;
|
||||||
pub use self::value::RuntimeValue;
|
pub use self::value::RuntimeValue;
|
@ -10,6 +10,28 @@ use interpreter::table::TableInstance;
|
|||||||
use interpreter::value::{RuntimeValue, TryInto, TransmuteInto};
|
use interpreter::value::{RuntimeValue, TryInto, TransmuteInto};
|
||||||
use interpreter::variable::{VariableInstance, VariableType};
|
use interpreter::variable::{VariableInstance, VariableType};
|
||||||
|
|
||||||
|
/// Module instance API.
|
||||||
|
pub trait ModuleInstanceInterface {
|
||||||
|
/// Execute start function of the module.
|
||||||
|
fn execute_main(&self, args: Vec<RuntimeValue>) -> Result<Option<RuntimeValue>, Error>;
|
||||||
|
/// Execute function with the given index.
|
||||||
|
fn execute(&self, index: u32, args: Vec<RuntimeValue>) -> Result<Option<RuntimeValue>, Error>;
|
||||||
|
/// Get module description reference.
|
||||||
|
fn module(&self) -> &Module;
|
||||||
|
/// Get table reference.
|
||||||
|
fn table(&self, index: ItemIndex) -> Result<Arc<TableInstance>, Error>;
|
||||||
|
/// Get memory reference.
|
||||||
|
fn memory(&self, index: ItemIndex) -> Result<Arc<MemoryInstance>, Error>;
|
||||||
|
/// Get global reference.
|
||||||
|
fn global(&self, index: ItemIndex) -> Result<Arc<VariableInstance>, Error>;
|
||||||
|
/// Call function with given index in functions index space.
|
||||||
|
fn call_function(&self, outer: CallerContext, index: ItemIndex) -> Result<Option<RuntimeValue>, Error>;
|
||||||
|
/// Call function with given index in the given table.
|
||||||
|
fn call_function_indirect(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result<Option<RuntimeValue>, Error>;
|
||||||
|
/// Call function with internal index.
|
||||||
|
fn call_internal_function(&self, outer: CallerContext, index: u32, function_type: Option<&FunctionType>) -> Result<Option<RuntimeValue>, Error>;
|
||||||
|
}
|
||||||
|
|
||||||
/// Item index in items index space.
|
/// Item index in items index space.
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum ItemIndex {
|
pub enum ItemIndex {
|
||||||
@ -92,27 +114,52 @@ impl ModuleInstance {
|
|||||||
Ok(module)
|
Ok(module)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute start function of the module.
|
/// Complete module initialization.
|
||||||
pub fn execute_main(&self, args: Vec<RuntimeValue>) -> Result<Option<RuntimeValue>, Error> {
|
fn complete_initialization(&mut self) -> Result<(), Error> {
|
||||||
|
// use data section to initialize linear memory regions
|
||||||
|
if let Some(data_section) = self.module.data_section() {
|
||||||
|
for (data_segment_index, data_segment) in data_section.entries().iter().enumerate() {
|
||||||
|
let offset: u32 = get_initializer(data_segment.offset(), &self.module, &self.imports)?.try_into()?;
|
||||||
|
self.memory(ItemIndex::IndexSpace(data_segment.index()))
|
||||||
|
.map_err(|e| Error::Initialization(format!("DataSegment {} initializes non-existant MemoryInstance {}: {:?}", data_segment_index, data_segment.index(), e)))
|
||||||
|
.and_then(|m| m.set(offset, data_segment.value()))
|
||||||
|
.map_err(|e| Error::Initialization(e.into()))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// use element section to fill tables
|
||||||
|
if let Some(element_section) = self.module.elements_section() {
|
||||||
|
for (element_segment_index, element_segment) in element_section.entries().iter().enumerate() {
|
||||||
|
let offset: u32 = get_initializer(element_segment.offset(), &self.module, &self.imports)?.try_into()?;
|
||||||
|
self.table(ItemIndex::IndexSpace(element_segment.index()))
|
||||||
|
.map_err(|e| Error::Initialization(format!("ElementSegment {} initializes non-existant Table {}: {:?}", element_segment_index, element_segment.index(), e)))
|
||||||
|
.and_then(|m| m.set_raw(offset, element_segment.members()))
|
||||||
|
.map_err(|e| Error::Initialization(e.into()))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModuleInstanceInterface for ModuleInstance {
|
||||||
|
fn execute_main(&self, args: Vec<RuntimeValue>) -> Result<Option<RuntimeValue>, Error> {
|
||||||
let index = self.module.start_section().ok_or(Error::Program("module has no start section".into()))?;
|
let index = self.module.start_section().ok_or(Error::Program("module has no start section".into()))?;
|
||||||
self.execute(index, args)
|
self.execute(index, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute function with the given index.
|
fn execute(&self, index: u32, args: Vec<RuntimeValue>) -> Result<Option<RuntimeValue>, Error> {
|
||||||
pub fn execute(&self, index: u32, args: Vec<RuntimeValue>) -> Result<Option<RuntimeValue>, Error> {
|
|
||||||
let args_len = args.len();
|
let args_len = args.len();
|
||||||
let mut args = StackWithLimit::with_data(args, args_len);
|
let mut args = StackWithLimit::with_data(args, args_len);
|
||||||
let caller_context = CallerContext::topmost(&mut args);
|
let caller_context = CallerContext::topmost(&mut args);
|
||||||
self.call_function(caller_context, ItemIndex::IndexSpace(index))
|
self.call_function(caller_context, ItemIndex::IndexSpace(index))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get module description reference.
|
fn module(&self) -> &Module {
|
||||||
pub fn module(&self) -> &Module {
|
|
||||||
&self.module
|
&self.module
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get table reference.
|
fn table(&self, index: ItemIndex) -> Result<Arc<TableInstance>, Error> {
|
||||||
pub fn table(&self, index: ItemIndex) -> Result<Arc<TableInstance>, Error> {
|
|
||||||
match self.imports.parse_table_index(index) {
|
match self.imports.parse_table_index(index) {
|
||||||
ItemIndex::IndexSpace(_) => unreachable!("parse_table_index resolves IndexSpace option"),
|
ItemIndex::IndexSpace(_) => unreachable!("parse_table_index resolves IndexSpace option"),
|
||||||
ItemIndex::Internal(index) => self.tables.get(index as usize).cloned()
|
ItemIndex::Internal(index) => self.tables.get(index as usize).cloned()
|
||||||
@ -125,8 +172,7 @@ impl ModuleInstance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get memory reference.
|
fn memory(&self, index: ItemIndex) -> Result<Arc<MemoryInstance>, Error> {
|
||||||
pub fn memory(&self, index: ItemIndex) -> Result<Arc<MemoryInstance>, Error> {
|
|
||||||
match self.imports.parse_memory_index(index) {
|
match self.imports.parse_memory_index(index) {
|
||||||
ItemIndex::IndexSpace(_) => unreachable!("parse_memory_index resolves IndexSpace option"),
|
ItemIndex::IndexSpace(_) => unreachable!("parse_memory_index resolves IndexSpace option"),
|
||||||
ItemIndex::Internal(index) => self.memory.get(index as usize).cloned()
|
ItemIndex::Internal(index) => self.memory.get(index as usize).cloned()
|
||||||
@ -139,8 +185,7 @@ impl ModuleInstance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get global reference.
|
fn global(&self, index: ItemIndex) -> Result<Arc<VariableInstance>, Error> {
|
||||||
pub fn global(&self, index: ItemIndex) -> Result<Arc<VariableInstance>, Error> {
|
|
||||||
match self.imports.parse_global_index(index) {
|
match self.imports.parse_global_index(index) {
|
||||||
ItemIndex::IndexSpace(_) => unreachable!("parse_global_index resolves IndexSpace option"),
|
ItemIndex::IndexSpace(_) => unreachable!("parse_global_index resolves IndexSpace option"),
|
||||||
ItemIndex::Internal(index) => self.globals.get(index as usize).cloned()
|
ItemIndex::Internal(index) => self.globals.get(index as usize).cloned()
|
||||||
@ -153,8 +198,7 @@ impl ModuleInstance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call function with given index in functions index space.
|
fn call_function(&self, outer: CallerContext, index: ItemIndex) -> Result<Option<RuntimeValue>, Error> {
|
||||||
pub fn call_function(&self, outer: CallerContext, index: ItemIndex) -> Result<Option<RuntimeValue>, Error> {
|
|
||||||
match self.imports.parse_function_index(index) {
|
match self.imports.parse_function_index(index) {
|
||||||
ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"),
|
ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"),
|
||||||
ItemIndex::Internal(index) => self.call_internal_function(outer, index, None),
|
ItemIndex::Internal(index) => self.call_internal_function(outer, index, None),
|
||||||
@ -168,8 +212,7 @@ impl ModuleInstance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call function with given index in the given table.
|
fn call_function_indirect(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result<Option<RuntimeValue>, Error> {
|
||||||
pub fn call_function_indirect(&self, outer: CallerContext, table_index: ItemIndex, type_index: u32, func_index: u32) -> Result<Option<RuntimeValue>, Error> {
|
|
||||||
let function_type = match self.module.type_section()
|
let function_type = match self.module.type_section()
|
||||||
.ok_or(Error::Function(format!("trying to indirect call function {} with non-existent function section", func_index)))
|
.ok_or(Error::Function(format!("trying to indirect call function {} with non-existent function section", func_index)))
|
||||||
.and_then(|s| s.types().get(type_index as usize)
|
.and_then(|s| s.types().get(type_index as usize)
|
||||||
@ -203,34 +246,6 @@ impl ModuleInstance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Complete module initialization.
|
|
||||||
fn complete_initialization(&mut self) -> Result<(), Error> {
|
|
||||||
// use data section to initialize linear memory regions
|
|
||||||
if let Some(data_section) = self.module.data_section() {
|
|
||||||
for (data_segment_index, data_segment) in data_section.entries().iter().enumerate() {
|
|
||||||
let offset: u32 = get_initializer(data_segment.offset(), &self.module, &self.imports)?.try_into()?;
|
|
||||||
self.memory(ItemIndex::IndexSpace(data_segment.index()))
|
|
||||||
.map_err(|e| Error::Initialization(format!("DataSegment {} initializes non-existant MemoryInstance {}: {:?}", data_segment_index, data_segment.index(), e)))
|
|
||||||
.and_then(|m| m.set(offset, data_segment.value()))
|
|
||||||
.map_err(|e| Error::Initialization(e.into()))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// use element section to fill tables
|
|
||||||
if let Some(element_section) = self.module.elements_section() {
|
|
||||||
for (element_segment_index, element_segment) in element_section.entries().iter().enumerate() {
|
|
||||||
let offset: u32 = get_initializer(element_segment.offset(), &self.module, &self.imports)?.try_into()?;
|
|
||||||
self.table(ItemIndex::IndexSpace(element_segment.index()))
|
|
||||||
.map_err(|e| Error::Initialization(format!("ElementSegment {} initializes non-existant Table {}: {:?}", element_segment_index, element_segment.index(), e)))
|
|
||||||
.and_then(|m| m.set_raw(offset, element_segment.members()))
|
|
||||||
.map_err(|e| Error::Initialization(e.into()))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Call function with internal index.
|
|
||||||
fn call_internal_function(&self, outer: CallerContext, index: u32, function_type: Option<&FunctionType>) -> Result<Option<RuntimeValue>, Error> {
|
fn call_internal_function(&self, outer: CallerContext, index: u32, function_type: Option<&FunctionType>) -> Result<Option<RuntimeValue>, Error> {
|
||||||
// TODO: cache
|
// TODO: cache
|
||||||
// internal index = index of function in functions section && index of code in code section
|
// internal index = index of function in functions section && index of code in code section
|
||||||
|
@ -4,7 +4,8 @@ use std::collections::hash_map::Entry;
|
|||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use elements::Module;
|
use elements::Module;
|
||||||
use interpreter::Error;
|
use interpreter::Error;
|
||||||
use interpreter::module::ModuleInstance;
|
use interpreter::env::env_module;
|
||||||
|
use interpreter::module::{ModuleInstance, ModuleInstanceInterface};
|
||||||
|
|
||||||
/// Program instance. Program is a set of instantiated modules.
|
/// Program instance. Program is a set of instantiated modules.
|
||||||
pub struct ProgramInstance {
|
pub struct ProgramInstance {
|
||||||
@ -15,15 +16,15 @@ pub struct ProgramInstance {
|
|||||||
/// Program instance essence.
|
/// Program instance essence.
|
||||||
pub struct ProgramInstanceEssence {
|
pub struct ProgramInstanceEssence {
|
||||||
/// Loaded modules.
|
/// Loaded modules.
|
||||||
modules: RwLock<HashMap<String, Arc<ModuleInstance>>>,
|
modules: RwLock<HashMap<String, Arc<ModuleInstanceInterface>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProgramInstance {
|
impl ProgramInstance {
|
||||||
/// Create new program instance.
|
/// Create new program instance.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Result<Self, Error> {
|
||||||
ProgramInstance {
|
Ok(ProgramInstance {
|
||||||
essence: Arc::new(ProgramInstanceEssence::new()),
|
essence: Arc::new(ProgramInstanceEssence::new()?),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Instantiate module.
|
/// Instantiate module.
|
||||||
@ -42,14 +43,17 @@ impl ProgramInstance {
|
|||||||
|
|
||||||
impl ProgramInstanceEssence {
|
impl ProgramInstanceEssence {
|
||||||
/// Create new program essence.
|
/// Create new program essence.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Result<Self, Error> {
|
||||||
ProgramInstanceEssence {
|
let mut modules = HashMap::new();
|
||||||
modules: RwLock::new(HashMap::new()),
|
let env_module: Arc<ModuleInstanceInterface> = Arc::new(env_module()?);
|
||||||
}
|
modules.insert("env".into(), env_module);
|
||||||
|
Ok(ProgramInstanceEssence {
|
||||||
|
modules: RwLock::new(modules),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get module reference.
|
/// Get module reference.
|
||||||
pub fn module(&self, name: &str) -> Option<Arc<ModuleInstance>> {
|
pub fn module(&self, name: &str) -> Option<Arc<ModuleInstanceInterface>> {
|
||||||
self.modules.read().get(name).cloned()
|
self.modules.read().get(name).cloned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ use std::u32;
|
|||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use elements::{Opcode, BlockType, FunctionType};
|
use elements::{Opcode, BlockType, FunctionType};
|
||||||
use interpreter::Error;
|
use interpreter::Error;
|
||||||
use interpreter::module::{ModuleInstance, CallerContext, ItemIndex};
|
use interpreter::module::{ModuleInstance, ModuleInstanceInterface, CallerContext, ItemIndex};
|
||||||
use interpreter::stack::StackWithLimit;
|
use interpreter::stack::StackWithLimit;
|
||||||
use interpreter::value::{RuntimeValue, TryInto, WrapInto, TryTruncateInto, ExtendInto, TransmuteInto,
|
use interpreter::value::{RuntimeValue, TryInto, WrapInto, TryTruncateInto, ExtendInto, TransmuteInto,
|
||||||
ArithmeticOps, Integer, Float, LittleEndianConvert};
|
ArithmeticOps, Integer, Float, LittleEndianConvert};
|
||||||
|
@ -20,5 +20,6 @@ pub use elements::{
|
|||||||
pub use interpreter::{
|
pub use interpreter::{
|
||||||
ProgramInstance,
|
ProgramInstance,
|
||||||
ModuleInstance,
|
ModuleInstance,
|
||||||
|
ModuleInstanceInterface,
|
||||||
RuntimeValue,
|
RuntimeValue,
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user