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 is_main: bool,
|
||||
pub signature: Signature,
|
||||
pub code: elements::FuncBody,
|
||||
}
|
||||
@ -231,6 +232,7 @@ pub struct FunctionDefinition {
|
||||
impl Default for FunctionDefinition {
|
||||
fn default() -> Self {
|
||||
FunctionDefinition {
|
||||
is_main: false,
|
||||
signature: Signature::TypeReference(0),
|
||||
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> {
|
||||
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 misc;
|
||||
mod import;
|
||||
mod memory;
|
||||
|
||||
pub use self::module::{module, from_module, ModuleBuilder};
|
||||
pub use self::code::{signatures, signature, function};
|
||||
|
@ -1,5 +1,6 @@
|
||||
use super::invoke::{Invoke, Identity};
|
||||
use super::code::{self, SignaturesBuilder, FunctionBuilder};
|
||||
use super::memory::{self, MemoryBuilder};
|
||||
use super::import;
|
||||
use elements;
|
||||
|
||||
@ -190,12 +191,23 @@ impl<F> ModuleBuilder<F> where F: Invoke<elements::Module> {
|
||||
self.module.code.bodies_mut().push(body);
|
||||
let body_index = self.module.code.bodies_mut().len() as u32 - 1;
|
||||
|
||||
if func.is_main {
|
||||
self.module.start = Some(body_index);
|
||||
}
|
||||
|
||||
CodeLocation {
|
||||
signature: signature_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 {
|
||||
match signature {
|
||||
code::Signature::Inline(func_type) => {
|
||||
@ -237,6 +249,11 @@ impl<F> ModuleBuilder<F> where F: Invoke<elements::Module> {
|
||||
FunctionBuilder::with_callback(self)
|
||||
}
|
||||
|
||||
/// Add new linear memory using dedicated builder
|
||||
pub fn memory(self) -> MemoryBuilder<Self> {
|
||||
MemoryBuilder::with_callback(self)
|
||||
}
|
||||
|
||||
/// Define functions section
|
||||
pub fn functions(self) -> SignaturesBuilder<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>
|
||||
where F: Invoke<elements::Module>
|
||||
{
|
||||
|
@ -129,6 +129,14 @@ impl Module {
|
||||
}
|
||||
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 {
|
||||
|
@ -361,6 +361,11 @@ impl MemorySection {
|
||||
pub fn entries(&self) -> &[MemoryType] {
|
||||
&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 {
|
||||
|
@ -5,6 +5,7 @@ use interpreter::imports::ModuleImports;
|
||||
use interpreter::memory::MemoryInstance;
|
||||
use interpreter::program::ProgramInstanceEssence;
|
||||
use interpreter::runner::{Interpreter, FunctionContext};
|
||||
use interpreter::stack::StackWithLimit;
|
||||
use interpreter::table::TableInstance;
|
||||
use interpreter::value::{RuntimeValue, TryInto};
|
||||
use interpreter::variable::{VariableInstance, VariableType};
|
||||
@ -34,6 +35,13 @@ pub struct ModuleInstance {
|
||||
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 {
|
||||
/// Instantiate given module within program context.
|
||||
pub fn new(program: Weak<ProgramInstanceEssence>, module: Module) -> Result<Self, Error> {
|
||||
@ -105,8 +113,12 @@ impl ModuleInstance {
|
||||
}
|
||||
|
||||
/// Execute start function of the module.
|
||||
pub fn execute_main(&self, _args: &[RuntimeValue]) -> Result<Option<RuntimeValue>, Error> {
|
||||
unimplemented!()
|
||||
pub 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 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.
|
||||
@ -157,7 +169,7 @@ impl ModuleInstance {
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"),
|
||||
ItemIndex::Internal(index) => {
|
||||
@ -195,8 +207,8 @@ impl ModuleInstance {
|
||||
// but there's global stack limit
|
||||
// args, locals
|
||||
let function_code = function_body.code().elements();
|
||||
let value_stack_limit = outer.value_stack().limit() - outer.value_stack().len();
|
||||
let frame_stack_limit = outer.frame_stack().limit() - outer.frame_stack().len();
|
||||
let value_stack_limit = outer.value_stack_limit;
|
||||
let frame_stack_limit = outer.frame_stack_limit;
|
||||
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)?;
|
||||
Interpreter::run_function(&mut innner, function_code)
|
||||
@ -211,7 +223,7 @@ impl ModuleInstance {
|
||||
}
|
||||
|
||||
/// 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
|
||||
match self.imports.parse_table_index(table_index) {
|
||||
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
|
||||
function_type.params().iter().rev()
|
||||
.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 expected_type = (*param_type).into();
|
||||
if actual_type != Some(expected_type) {
|
||||
|
@ -4,7 +4,7 @@ use std::u32;
|
||||
use std::fmt::Display;
|
||||
use elements::{Opcode, BlockType, FunctionType};
|
||||
use interpreter::Error;
|
||||
use interpreter::module::{ModuleInstance, ItemIndex};
|
||||
use interpreter::module::{ModuleInstance, CallerContext, ItemIndex};
|
||||
use interpreter::stack::StackWithLimit;
|
||||
use interpreter::value::{RuntimeValue, TryInto, WrapInto, TryTruncateInto, ExtendInto, TransmuteInto,
|
||||
ArithmeticOps, Integer, Float, LittleEndianConvert};
|
||||
@ -880,11 +880,11 @@ impl<'a> FunctionContext<'a> {
|
||||
}
|
||||
|
||||
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> {
|
||||
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> {
|
||||
|
@ -12,6 +12,13 @@ pub struct 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 {
|
||||
StackWithLimit {
|
||||
values: VecDeque::new(),
|
||||
|
@ -450,6 +450,42 @@ fn return_test() {
|
||||
/// https://github.com/WebAssembly/wabt/blob/8e1f6031e9889ba770c7be4a9b084da5f14456a0/test/interp/return-void.txt
|
||||
#[test]
|
||||
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
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user