feat(interface-types) Check signature of the exported function to call.

This commit is contained in:
Ivan Enderlin 2019-09-20 14:31:15 +02:00
parent b7b37d2e99
commit 56afb4da63
2 changed files with 78 additions and 2 deletions

View File

@ -1,6 +1,6 @@
use crate::instructions::{
stack::{Stack, Stackable},
wasm::{self, Value},
wasm::{self, Type, Value},
Instruction,
};
use std::{convert::TryFrom, marker::PhantomData};
@ -105,6 +105,20 @@ where
match runtime.stack.pop(inputs_cardinality) {
Some(inputs) => {
let input_types = inputs
.iter()
.map(|input| input.into())
.collect::<Vec<Type>>();
if input_types != export.inputs() {
return Err(format!(
"`{}` cannot call the exported function `{}` because the value types in the stack mismatch the function signature (expects {:?}).",
instruction_name,
export_name,
export.inputs(),
))
}
match export.call(&inputs) {
Ok(outputs) => {
for output in outputs.iter() {
@ -117,7 +131,7 @@ where
}
}
None => Err(format!(
"`{}` cannot call the exported function `{}` because there is no enought data in the stack for the arguments (need {}).",
"`{}` cannot call the exported function `{}` because there is no enought data in the stack for the arguments (needs {}).",
instruction_name,
export_name,
inputs_cardinality,
@ -339,4 +353,53 @@ mod tests {
String::from(r#"`call-export "bar"` cannot call the exported function `bar` because it doesn't exist."#)
);
}
#[test]
fn test_interpreter_call_export_too_small_stack() {
let interpreter: Interpreter<Instance, Export> = (&vec![
Instruction::ArgumentGet(0),
Instruction::CallExport("sum"),
// ^^^ `sum` expects 2 values in the stack, only one is present
])
.try_into()
.unwrap();
let invocation_inputs = vec![Value::I32(3), Value::I32(4)];
let instance = Instance::new();
let run = interpreter.run(&invocation_inputs, &instance);
assert!(run.is_err());
let error = run.unwrap_err();
assert_eq!(
error,
String::from(r#"`call-export "sum"` cannot call the exported function `sum` because there is no enought data in the stack for the arguments (needs 2)."#)
);
}
#[test]
fn test_interpreter_call_export_invalid_types_in_the_stack() {
let interpreter: Interpreter<Instance, Export> = (&vec![
Instruction::ArgumentGet(1),
Instruction::ArgumentGet(0),
Instruction::CallExport("sum"),
])
.try_into()
.unwrap();
let invocation_inputs = vec![Value::I32(3), Value::I64(4)];
// ^^^ mismatch with `sum` signature
let instance = Instance::new();
let run = interpreter.run(&invocation_inputs, &instance);
assert!(run.is_err());
let error = run.unwrap_err();
assert_eq!(
error,
String::from(r#"`call-export "sum"` cannot call the exported function `sum` because the value types in the stack mismatch the function signature (expects [I32, I32])."#)
);
}
}

View File

@ -1,5 +1,6 @@
use std::convert::TryFrom;
#[derive(Debug, PartialEq)]
pub enum Type {
I32,
I64,
@ -17,6 +18,18 @@ pub enum Value {
V128(u128),
}
impl From<&Value> for Type {
fn from(value: &Value) -> Self {
match value {
Value::I32(_) => Type::I32,
Value::I64(_) => Type::I64,
Value::F32(_) => Type::F32,
Value::F64(_) => Type::F64,
Value::V128(_) => Type::V128,
}
}
}
impl Default for Value {
fn default() -> Self {
Self::I32(0)