mirror of
https://github.com/fluencelabs/parity-wasm
synced 2025-05-18 02:01:30 +00:00
callindirect_2
This commit is contained in:
parent
9510789c91
commit
3be7051015
@ -5,6 +5,7 @@ use super::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Type definition in types section. Currently can be only of the function type.
|
/// Type definition in types section. Currently can be only of the function type.
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
/// Function type.
|
/// Function type.
|
||||||
Function(FunctionType),
|
Function(FunctionType),
|
||||||
@ -115,6 +116,7 @@ impl Serialize for BlockType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Function signature type.
|
/// Function signature type.
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct FunctionType {
|
pub struct FunctionType {
|
||||||
form: u8,
|
form: u8,
|
||||||
params: Vec<ValueType>,
|
params: Vec<ValueType>,
|
||||||
|
@ -172,7 +172,53 @@ impl ModuleInstance {
|
|||||||
pub 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) => {
|
ItemIndex::Internal(index) => self.call_internal_function(outer, index, None),
|
||||||
|
ItemIndex::External(index) => self.module.import_section()
|
||||||
|
.ok_or(Error::Function(format!("trying to access external function with index {} in module without import section", index)))
|
||||||
|
.and_then(|s| s.entries().get(index as usize)
|
||||||
|
.ok_or(Error::Function(format!("trying to access external function with index {} in module with {}-entries import section", index, s.entries().len()))))
|
||||||
|
.and_then(|e| self.imports.module(e.module()))
|
||||||
|
.and_then(|m| m.call_internal_function(outer, index, None)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Call function with given index in the given table.
|
||||||
|
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()
|
||||||
|
.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)
|
||||||
|
.ok_or(Error::Function(format!("trying to indirect call function {} with non-existent type index {}", func_index, type_index))))? {
|
||||||
|
&Type::Function(ref function_type) => function_type,
|
||||||
|
};
|
||||||
|
|
||||||
|
match self.imports.parse_table_index(table_index) {
|
||||||
|
ItemIndex::IndexSpace(_) => unreachable!("parse_function_index resolves IndexSpace option"),
|
||||||
|
ItemIndex::Internal(table_index) => {
|
||||||
|
let table = self.table(ItemIndex::Internal(table_index))?;
|
||||||
|
let index = match table.get(func_index)? {
|
||||||
|
RuntimeValue::AnyFunc(index) => index,
|
||||||
|
_ => return Err(Error::Function(format!("trying to indirect call function {} via non-anyfunc table {}", func_index, table_index))),
|
||||||
|
};
|
||||||
|
self.call_internal_function(outer, index, Some(function_type))
|
||||||
|
},
|
||||||
|
ItemIndex::External(table_index) => {
|
||||||
|
let table = self.table(ItemIndex::External(table_index))?;
|
||||||
|
let index = match table.get(func_index)? {
|
||||||
|
RuntimeValue::AnyFunc(index) => index,
|
||||||
|
_ => return Err(Error::Function(format!("trying to indirect call function {} via non-anyfunc table {}", func_index, table_index))),
|
||||||
|
};
|
||||||
|
let module = self.module.import_section()
|
||||||
|
.ok_or(Error::Function(format!("trying to access external table with index {} in module without import section", table_index)))
|
||||||
|
.and_then(|s| s.entries().get(table_index as usize)
|
||||||
|
.ok_or(Error::Function(format!("trying to access external table with index {} in module with {}-entries import section", table_index, s.entries().len()))))
|
||||||
|
.and_then(|e| self.imports.module(e.module()))?;
|
||||||
|
module.call_internal_function(outer, index, Some(function_type))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Call function with internal index.
|
||||||
|
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
|
||||||
// get function type index
|
// get function type index
|
||||||
@ -191,9 +237,15 @@ impl ModuleInstance {
|
|||||||
.and_then(|s| s.types()
|
.and_then(|s| s.types()
|
||||||
.get(function_type_index as usize)
|
.get(function_type_index as usize)
|
||||||
.ok_or(Error::Function(format!("trying to call function with type index {} in module with {} types", index, s.types().len()))))?;
|
.ok_or(Error::Function(format!("trying to call function with type index {} in module with {} types", index, s.types().len()))))?;
|
||||||
let function_type = match item_type {
|
let actual_function_type = match item_type {
|
||||||
&Type::Function(ref function_type) => function_type,
|
&Type::Function(ref function_type) => function_type,
|
||||||
};
|
};
|
||||||
|
if let Some(ref function_type) = function_type {
|
||||||
|
if function_type != &actual_function_type {
|
||||||
|
return Err(Error::Function(format!("expected function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}",
|
||||||
|
function_type.params(), function_type.return_type(), actual_function_type.params(), actual_function_type.return_type())));
|
||||||
|
}
|
||||||
|
}
|
||||||
// get function body
|
// get function body
|
||||||
let function_body = self.module
|
let function_body = self.module
|
||||||
.code_section()
|
.code_section()
|
||||||
@ -202,53 +254,15 @@ impl ModuleInstance {
|
|||||||
.get(index as usize)
|
.get(index as usize)
|
||||||
.ok_or(Error::Function(format!("trying to call function with index {} in module with {} functions codes", index, s.bodies().len()))))?;
|
.ok_or(Error::Function(format!("trying to call function with index {} in module with {} functions codes", index, s.bodies().len()))))?;
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// each functions has its own value stack
|
// each functions has its own value stack
|
||||||
// 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;
|
let value_stack_limit = outer.value_stack_limit;
|
||||||
let frame_stack_limit = outer.frame_stack_limit;
|
let frame_stack_limit = outer.frame_stack_limit;
|
||||||
let locals = prepare_function_locals(function_type, function_body, outer)?;
|
let locals = prepare_function_locals(actual_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, actual_function_type, function_code, locals)?;
|
||||||
Interpreter::run_function(&mut innner, function_code)
|
Interpreter::run_function(&mut innner, function_code)
|
||||||
},
|
|
||||||
ItemIndex::External(index) => self.module.import_section()
|
|
||||||
.ok_or(Error::Function(format!("trying to access external function with index {} in module without import section", index)))
|
|
||||||
.and_then(|s| s.entries().get(index as usize)
|
|
||||||
.ok_or(Error::Function(format!("trying to access external function with index {} in module with {}-entries import section", index, s.entries().len()))))
|
|
||||||
.and_then(|e| self.imports.module(e.module()))
|
|
||||||
.and_then(|m| m.call_function(outer, ItemIndex::Internal(index))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Call function with given index in the given table.
|
|
||||||
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"),
|
|
||||||
ItemIndex::Internal(table_index) => {
|
|
||||||
let table = self.table(ItemIndex::Internal(table_index))?;
|
|
||||||
let index = match table.get(func_index)? {
|
|
||||||
RuntimeValue::AnyFunc(index) => index,
|
|
||||||
_ => return Err(Error::Function(format!("trying to indirect call function {} via non-anyfunc table {}", func_index, table_index))),
|
|
||||||
};
|
|
||||||
self.call_function(outer, ItemIndex::Internal(index))
|
|
||||||
},
|
|
||||||
ItemIndex::External(table_index) => {
|
|
||||||
let table = self.table(ItemIndex::External(table_index))?;
|
|
||||||
let index = match table.get(func_index)? {
|
|
||||||
RuntimeValue::AnyFunc(index) => index,
|
|
||||||
_ => return Err(Error::Function(format!("trying to indirect call function {} via non-anyfunc table {}", func_index, table_index))),
|
|
||||||
};
|
|
||||||
let module = self.module.import_section()
|
|
||||||
.ok_or(Error::Function(format!("trying to access external table with index {} in module without import section", table_index)))
|
|
||||||
.and_then(|s| s.entries().get(table_index as usize)
|
|
||||||
.ok_or(Error::Function(format!("trying to access external table with index {} in module with {}-entries import section", table_index, s.entries().len()))))
|
|
||||||
.and_then(|e| self.imports.module(e.module()))?;
|
|
||||||
module.call_function(outer, ItemIndex::Internal(index))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -721,6 +721,12 @@ fn callindirect_2() {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
let body3 = Opcodes::new(vec![
|
let body3 = Opcodes::new(vec![
|
||||||
|
Opcode::GetLocal(0),
|
||||||
|
Opcode::I32Ctz,
|
||||||
|
Opcode::End,
|
||||||
|
]);
|
||||||
|
|
||||||
|
let body4 = Opcodes::new(vec![
|
||||||
Opcode::GetLocal(0),
|
Opcode::GetLocal(0),
|
||||||
Opcode::GetLocal(1),
|
Opcode::GetLocal(1),
|
||||||
Opcode::GetLocal(2),
|
Opcode::GetLocal(2),
|
||||||
@ -730,8 +736,8 @@ fn callindirect_2() {
|
|||||||
|
|
||||||
let module = module()
|
let module = module()
|
||||||
.table()
|
.table()
|
||||||
.with_min(2)
|
.with_min(3)
|
||||||
.with_element(0, vec![0, 1])
|
.with_element(0, vec![0, 1, 2])
|
||||||
.build()
|
.build()
|
||||||
.function()
|
.function()
|
||||||
.signature()
|
.signature()
|
||||||
@ -747,6 +753,12 @@ fn callindirect_2() {
|
|||||||
.return_type().i32().build()
|
.return_type().i32().build()
|
||||||
.body().with_opcodes(body2).build()
|
.body().with_opcodes(body2).build()
|
||||||
.build()
|
.build()
|
||||||
|
.function()
|
||||||
|
.signature()
|
||||||
|
.param().i32()
|
||||||
|
.return_type().i32().build()
|
||||||
|
.body().with_opcodes(body3).build()
|
||||||
|
.build()
|
||||||
.function().main()
|
.function().main()
|
||||||
.signature()
|
.signature()
|
||||||
.param().i32()
|
.param().i32()
|
||||||
@ -754,7 +766,7 @@ fn callindirect_2() {
|
|||||||
.param().i32()
|
.param().i32()
|
||||||
.return_type().i32()
|
.return_type().i32()
|
||||||
.build()
|
.build()
|
||||||
.body().with_opcodes(body3).build()
|
.body().with_opcodes(body4).build()
|
||||||
.build()
|
.build()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@ -763,5 +775,7 @@ fn callindirect_2() {
|
|||||||
assert_eq!(module.execute_main(vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(0)]).unwrap().unwrap(), RuntimeValue::I32(14));
|
assert_eq!(module.execute_main(vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(0)]).unwrap().unwrap(), RuntimeValue::I32(14));
|
||||||
assert_eq!(module.execute_main(vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(1)]).unwrap().unwrap(), RuntimeValue::I32(6));
|
assert_eq!(module.execute_main(vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(1)]).unwrap().unwrap(), RuntimeValue::I32(6));
|
||||||
assert_eq!(module.execute_main(vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(2)]).unwrap_err(),
|
assert_eq!(module.execute_main(vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(2)]).unwrap_err(),
|
||||||
Error::Table("trying to read table item with index 2 when there are only 2 items".into()));
|
Error::Function("expected function with signature ([I32, I32]) -> Some(I32) when got with ([I32]) -> Some(I32)".into()));
|
||||||
|
assert_eq!(module.execute_main(vec![RuntimeValue::I32(10), RuntimeValue::I32(4), RuntimeValue::I32(3)]).unwrap_err(),
|
||||||
|
Error::Table("trying to read table item with index 3 when there are only 3 items".into()));
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user