mirror of
https://github.com/fluencelabs/parity-wasm
synced 2025-06-14 15:31:44 +00:00
flush
This commit is contained in:
@ -224,6 +224,7 @@ impl<F> FuncBodyBuilder<F> where F: Invoke<elements::FuncBody> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct FunctionDefinition {
|
pub struct FunctionDefinition {
|
||||||
|
pub is_main: bool,
|
||||||
pub signature: Signature,
|
pub signature: Signature,
|
||||||
pub code: elements::FuncBody,
|
pub code: elements::FuncBody,
|
||||||
}
|
}
|
||||||
@ -231,6 +232,7 @@ pub struct FunctionDefinition {
|
|||||||
impl Default for FunctionDefinition {
|
impl Default for FunctionDefinition {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
FunctionDefinition {
|
FunctionDefinition {
|
||||||
|
is_main: false,
|
||||||
signature: Signature::TypeReference(0),
|
signature: Signature::TypeReference(0),
|
||||||
code: elements::FuncBody::empty(),
|
code: elements::FuncBody::empty(),
|
||||||
}
|
}
|
||||||
@ -256,6 +258,11 @@ impl<F> FunctionBuilder<F> where F: Invoke<FunctionDefinition> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn main(mut self) -> Self {
|
||||||
|
self.func.is_main = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn signature(self) -> SignatureBuilder<Self> {
|
pub fn signature(self) -> SignatureBuilder<Self> {
|
||||||
SignatureBuilder::with_callback(self)
|
SignatureBuilder::with_callback(self)
|
||||||
}
|
}
|
||||||
|
49
src/builder/memory.rs
Normal file
49
src/builder/memory.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
use super::invoke::{Invoke, Identity};
|
||||||
|
|
||||||
|
pub struct MemoryDefinition {
|
||||||
|
pub min: u32,
|
||||||
|
pub max: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MemoryBuilder<F=Identity> {
|
||||||
|
callback: F,
|
||||||
|
memory: MemoryDefinition,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemoryBuilder {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
MemoryBuilder::with_callback(Identity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F> MemoryBuilder<F> where F: Invoke<MemoryDefinition> {
|
||||||
|
pub fn with_callback(callback: F) -> Self {
|
||||||
|
MemoryBuilder {
|
||||||
|
callback: callback,
|
||||||
|
memory: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_min(mut self, min: u32) -> Self {
|
||||||
|
self.memory.min = min;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_max(mut self, max: Option<u32>) -> Self {
|
||||||
|
self.memory.max = max;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(self) -> F::Result {
|
||||||
|
self.callback.invoke(self.memory)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MemoryDefinition {
|
||||||
|
fn default() -> Self {
|
||||||
|
MemoryDefinition {
|
||||||
|
min: 1,
|
||||||
|
max: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ mod module;
|
|||||||
mod code;
|
mod code;
|
||||||
mod misc;
|
mod misc;
|
||||||
mod import;
|
mod import;
|
||||||
|
mod memory;
|
||||||
|
|
||||||
pub use self::module::{module, from_module, ModuleBuilder};
|
pub use self::module::{module, from_module, ModuleBuilder};
|
||||||
pub use self::code::{signatures, signature, function};
|
pub use self::code::{signatures, signature, function};
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use super::invoke::{Invoke, Identity};
|
use super::invoke::{Invoke, Identity};
|
||||||
use super::code::{self, SignaturesBuilder, FunctionBuilder};
|
use super::code::{self, SignaturesBuilder, FunctionBuilder};
|
||||||
|
use super::memory::{self, MemoryBuilder};
|
||||||
use super::import;
|
use super::import;
|
||||||
use elements;
|
use elements;
|
||||||
|
|
||||||
@ -190,12 +191,23 @@ impl<F> ModuleBuilder<F> where F: Invoke<elements::Module> {
|
|||||||
self.module.code.bodies_mut().push(body);
|
self.module.code.bodies_mut().push(body);
|
||||||
let body_index = self.module.code.bodies_mut().len() as u32 - 1;
|
let body_index = self.module.code.bodies_mut().len() as u32 - 1;
|
||||||
|
|
||||||
|
if func.is_main {
|
||||||
|
self.module.start = Some(body_index);
|
||||||
|
}
|
||||||
|
|
||||||
CodeLocation {
|
CodeLocation {
|
||||||
signature: signature_index,
|
signature: signature_index,
|
||||||
body: body_index,
|
body: body_index,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Push linear memory region
|
||||||
|
pub fn push_memory(&mut self, memory: memory::MemoryDefinition) -> u32 {
|
||||||
|
let entries = self.module.memory.entries_mut();
|
||||||
|
entries.push(elements::MemoryType::new(memory.min, memory.max));
|
||||||
|
(entries.len() - 1) as u32
|
||||||
|
}
|
||||||
|
|
||||||
fn resolve_type_ref(&mut self, signature: code::Signature) -> u32 {
|
fn resolve_type_ref(&mut self, signature: code::Signature) -> u32 {
|
||||||
match signature {
|
match signature {
|
||||||
code::Signature::Inline(func_type) => {
|
code::Signature::Inline(func_type) => {
|
||||||
@ -237,6 +249,11 @@ impl<F> ModuleBuilder<F> where F: Invoke<elements::Module> {
|
|||||||
FunctionBuilder::with_callback(self)
|
FunctionBuilder::with_callback(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add new linear memory using dedicated builder
|
||||||
|
pub fn memory(self) -> MemoryBuilder<Self> {
|
||||||
|
MemoryBuilder::with_callback(self)
|
||||||
|
}
|
||||||
|
|
||||||
/// Define functions section
|
/// Define functions section
|
||||||
pub fn functions(self) -> SignaturesBuilder<Self> {
|
pub fn functions(self) -> SignaturesBuilder<Self> {
|
||||||
SignaturesBuilder::with_callback(self)
|
SignaturesBuilder::with_callback(self)
|
||||||
@ -292,6 +309,18 @@ impl<F> Invoke<code::FunctionDefinition> for ModuleBuilder<F>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<F> Invoke<memory::MemoryDefinition> for ModuleBuilder<F>
|
||||||
|
where F: Invoke<elements::Module>
|
||||||
|
{
|
||||||
|
type Result = Self;
|
||||||
|
|
||||||
|
fn invoke(self, def: memory::MemoryDefinition) -> Self {
|
||||||
|
let mut b = self;
|
||||||
|
b.push_memory(def);
|
||||||
|
b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<F> Invoke<elements::ImportEntry> for ModuleBuilder<F>
|
impl<F> Invoke<elements::ImportEntry> for ModuleBuilder<F>
|
||||||
where F: Invoke<elements::Module>
|
where F: Invoke<elements::Module>
|
||||||
{
|
{
|
||||||
|
@ -129,6 +129,14 @@ impl Module {
|
|||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Start section, if any.
|
||||||
|
pub fn start_section(&self) -> Option<u32> {
|
||||||
|
for section in self.sections() {
|
||||||
|
if let &Section::Start(sect) = section { return Some(sect); }
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for Module {
|
impl Deserialize for Module {
|
||||||
|
@ -361,6 +361,11 @@ impl MemorySection {
|
|||||||
pub fn entries(&self) -> &[MemoryType] {
|
pub fn entries(&self) -> &[MemoryType] {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Mutable list of all memory entries in the section
|
||||||
|
pub fn entries_mut(&mut self) -> &mut Vec<MemoryType> {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for MemorySection {
|
impl Deserialize for MemorySection {
|
||||||
|
@ -5,6 +5,7 @@ use interpreter::imports::ModuleImports;
|
|||||||
use interpreter::memory::MemoryInstance;
|
use interpreter::memory::MemoryInstance;
|
||||||
use interpreter::program::ProgramInstanceEssence;
|
use interpreter::program::ProgramInstanceEssence;
|
||||||
use interpreter::runner::{Interpreter, FunctionContext};
|
use interpreter::runner::{Interpreter, FunctionContext};
|
||||||
|
use interpreter::stack::StackWithLimit;
|
||||||
use interpreter::table::TableInstance;
|
use interpreter::table::TableInstance;
|
||||||
use interpreter::value::{RuntimeValue, TryInto};
|
use interpreter::value::{RuntimeValue, TryInto};
|
||||||
use interpreter::variable::{VariableInstance, VariableType};
|
use interpreter::variable::{VariableInstance, VariableType};
|
||||||
@ -34,6 +35,13 @@ pub struct ModuleInstance {
|
|||||||
globals: Vec<Arc<VariableInstance>>,
|
globals: Vec<Arc<VariableInstance>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Caller context.
|
||||||
|
pub struct CallerContext<'a> {
|
||||||
|
pub value_stack_limit: usize,
|
||||||
|
pub frame_stack_limit: usize,
|
||||||
|
pub value_stack: &'a mut StackWithLimit<RuntimeValue>,
|
||||||
|
}
|
||||||
|
|
||||||
impl ModuleInstance {
|
impl ModuleInstance {
|
||||||
/// Instantiate given module within program context.
|
/// Instantiate given module within program context.
|
||||||
pub fn new(program: Weak<ProgramInstanceEssence>, module: Module) -> Result<Self, Error> {
|
pub fn new(program: Weak<ProgramInstanceEssence>, module: Module) -> Result<Self, Error> {
|
||||||
@ -105,8 +113,12 @@ impl ModuleInstance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Execute start function of the module.
|
/// Execute start function of the module.
|
||||||
pub fn execute_main(&self, _args: &[RuntimeValue]) -> Result<Option<RuntimeValue>, Error> {
|
pub fn execute_main(&self, args: Vec<RuntimeValue>) -> Result<Option<RuntimeValue>, Error> {
|
||||||
unimplemented!()
|
let index = self.module.start_section().ok_or(Error::Program("module has no start section".into()))?;
|
||||||
|
let args_len = args.len();
|
||||||
|
let mut args = StackWithLimit::with_data(args, args_len);
|
||||||
|
let caller_context = CallerContext::topmost(&mut args);
|
||||||
|
self.call_function(caller_context, ItemIndex::IndexSpace(index))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get module description reference.
|
/// Get module description reference.
|
||||||
@ -157,7 +169,7 @@ impl ModuleInstance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Call function with given index in functions index space.
|
/// Call function with given index in functions index space.
|
||||||
pub fn call_function(&self, outer: &mut FunctionContext, 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) => {
|
ItemIndex::Internal(index) => {
|
||||||
@ -195,8 +207,8 @@ impl ModuleInstance {
|
|||||||
// but there's global stack limit
|
// but there's global stack limit
|
||||||
// args, locals
|
// args, locals
|
||||||
let function_code = function_body.code().elements();
|
let function_code = function_body.code().elements();
|
||||||
let value_stack_limit = outer.value_stack().limit() - outer.value_stack().len();
|
let value_stack_limit = outer.value_stack_limit;
|
||||||
let frame_stack_limit = outer.frame_stack().limit() - outer.frame_stack().len();
|
let frame_stack_limit = outer.frame_stack_limit;
|
||||||
let locals = prepare_function_locals(function_type, function_body, outer)?;
|
let locals = prepare_function_locals(function_type, function_body, outer)?;
|
||||||
let mut innner = FunctionContext::new(self, value_stack_limit, frame_stack_limit, function_type, function_code, locals)?;
|
let mut innner = FunctionContext::new(self, value_stack_limit, frame_stack_limit, function_type, function_code, locals)?;
|
||||||
Interpreter::run_function(&mut innner, function_code)
|
Interpreter::run_function(&mut innner, function_code)
|
||||||
@ -211,7 +223,7 @@ impl ModuleInstance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Call function with given index in the given table.
|
/// Call function with given index in the given table.
|
||||||
pub fn call_function_indirect(&self, outer: &mut FunctionContext, 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> {
|
||||||
// TODO: check signature
|
// TODO: check signature
|
||||||
match self.imports.parse_table_index(table_index) {
|
match self.imports.parse_table_index(table_index) {
|
||||||
ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"),
|
ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"),
|
||||||
@ -240,11 +252,29 @@ impl ModuleInstance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_function_locals(function_type: &FunctionType, function_body: &FuncBody, outer: &mut FunctionContext) -> Result<Vec<VariableInstance>, Error> {
|
impl<'a> CallerContext<'a> {
|
||||||
|
pub fn topmost(args: &'a mut StackWithLimit<RuntimeValue>) -> Self {
|
||||||
|
CallerContext {
|
||||||
|
value_stack_limit: 1024,
|
||||||
|
frame_stack_limit: 1024,
|
||||||
|
value_stack: args,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn nested(outer: &'a mut FunctionContext) -> Self {
|
||||||
|
CallerContext {
|
||||||
|
value_stack_limit: outer.value_stack().limit() - outer.value_stack().len(),
|
||||||
|
frame_stack_limit: outer.frame_stack().limit() - outer.frame_stack().len(),
|
||||||
|
value_stack: outer.value_stack_mut(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prepare_function_locals(function_type: &FunctionType, function_body: &FuncBody, outer: CallerContext) -> Result<Vec<VariableInstance>, Error> {
|
||||||
// locals = function arguments + defined locals
|
// locals = function arguments + defined locals
|
||||||
function_type.params().iter().rev()
|
function_type.params().iter().rev()
|
||||||
.map(|param_type| {
|
.map(|param_type| {
|
||||||
let param_value = outer.value_stack_mut().pop()?;
|
let param_value = outer.value_stack.pop()?;
|
||||||
let actual_type = param_value.variable_type();
|
let actual_type = param_value.variable_type();
|
||||||
let expected_type = (*param_type).into();
|
let expected_type = (*param_type).into();
|
||||||
if actual_type != Some(expected_type) {
|
if actual_type != Some(expected_type) {
|
||||||
|
@ -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, ItemIndex};
|
use interpreter::module::{ModuleInstance, 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};
|
||||||
@ -880,11 +880,11 @@ impl<'a> FunctionContext<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn call_function(&mut self, index: u32) -> Result<Option<RuntimeValue>, Error> {
|
pub fn call_function(&mut self, index: u32) -> Result<Option<RuntimeValue>, Error> {
|
||||||
self.module.call_function(self, ItemIndex::IndexSpace(index))
|
self.module.call_function(CallerContext::nested(self), ItemIndex::IndexSpace(index))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call_function_indirect(&mut self, table_index: u32, type_index: u32, func_index: u32) -> Result<Option<RuntimeValue>, Error> {
|
pub fn call_function_indirect(&mut self, table_index: u32, type_index: u32, func_index: u32) -> Result<Option<RuntimeValue>, Error> {
|
||||||
self.module.call_function_indirect(self, ItemIndex::IndexSpace(table_index), type_index, func_index)
|
self.module.call_function_indirect(CallerContext::nested(self), ItemIndex::IndexSpace(table_index), type_index, func_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_local(&mut self, index: usize, value: RuntimeValue) -> Result<InstructionOutcome, Error> {
|
pub fn set_local(&mut self, index: usize, value: RuntimeValue) -> Result<InstructionOutcome, Error> {
|
||||||
|
@ -12,6 +12,13 @@ pub struct StackWithLimit<T> where T: Clone {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T> StackWithLimit<T> where T: Clone {
|
impl<T> StackWithLimit<T> where T: Clone {
|
||||||
|
pub fn with_data(data: Vec<T>, limit: usize) -> Self {
|
||||||
|
StackWithLimit {
|
||||||
|
values: data.into_iter().collect(),
|
||||||
|
limit: limit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_limit(limit: usize) -> Self {
|
pub fn with_limit(limit: usize) -> Self {
|
||||||
StackWithLimit {
|
StackWithLimit {
|
||||||
values: VecDeque::new(),
|
values: VecDeque::new(),
|
||||||
|
@ -450,6 +450,42 @@ fn return_test() {
|
|||||||
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/return-void.txt
|
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/return-void.txt
|
||||||
#[test]
|
#[test]
|
||||||
fn return_void() {
|
fn return_void() {
|
||||||
|
use builder::module;
|
||||||
|
use interpreter::module::ItemIndex;
|
||||||
|
use interpreter::program::ProgramInstance;
|
||||||
|
|
||||||
|
let body = Opcodes::new(vec![
|
||||||
|
Opcode::GetLocal(0),
|
||||||
|
Opcode::I32Const(0),
|
||||||
|
Opcode::I32Eq,
|
||||||
|
Opcode::If(BlockType::NoResult,
|
||||||
|
Opcodes::new(vec![
|
||||||
|
Opcode::Return,
|
||||||
|
Opcode::End,
|
||||||
|
])),
|
||||||
|
Opcode::I32Const(0),
|
||||||
|
Opcode::I32Const(1),
|
||||||
|
Opcode::I32Store(2, 0),
|
||||||
|
Opcode::End,
|
||||||
|
]);
|
||||||
|
|
||||||
|
let module = module()
|
||||||
|
.memory().build()
|
||||||
|
.function().main()
|
||||||
|
.signature().param().i32().build()
|
||||||
|
.body().with_opcodes(body).build()
|
||||||
|
.build()
|
||||||
|
.build();
|
||||||
|
let program = ProgramInstance::new();
|
||||||
|
let module = program.add_module("main", module).unwrap();
|
||||||
|
|
||||||
|
module.execute_main(vec![RuntimeValue::I32(0)]).unwrap();
|
||||||
|
let memory = module.memory(ItemIndex::IndexSpace(0)).unwrap();
|
||||||
|
assert_eq!(memory.get(0, 4).unwrap(), vec![0, 0, 0, 0]);
|
||||||
|
|
||||||
|
module.execute_main(vec![RuntimeValue::I32(1)]).unwrap();
|
||||||
|
let memory = module.memory(ItemIndex::IndexSpace(0)).unwrap();
|
||||||
|
assert_eq!(memory.get(0, 4).unwrap(), vec![0, 0, 0, 1]);
|
||||||
// TODO: linear memory required
|
// TODO: linear memory required
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user