Use embedding api in python extension (#569)
Now embedding API is used in the Python extension, this allows us to remove ModuleData::invoke() from wasmtime-interface-types
This commit is contained in:
@@ -4,32 +4,30 @@ extern crate alloc;
|
||||
|
||||
use crate::value::{pyobj_to_value, value_to_pyobj};
|
||||
use alloc::rc::Rc;
|
||||
use core::cell::RefCell;
|
||||
use cranelift_codegen::ir;
|
||||
use pyo3::exceptions::Exception;
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::types::PyTuple;
|
||||
use pyo3::types::{PyAny, PyDict, PyTuple};
|
||||
use wasmtime_api as api;
|
||||
use wasmtime_interface_types::ModuleData;
|
||||
use wasmtime_jit::{Context, InstanceHandle};
|
||||
use wasmtime_runtime::Export;
|
||||
|
||||
// TODO support non-export functions
|
||||
#[pyclass]
|
||||
pub struct Function {
|
||||
pub context: Rc<RefCell<Context>>,
|
||||
pub instance: InstanceHandle,
|
||||
pub instance: api::HostRef<api::Instance>,
|
||||
pub export_name: String,
|
||||
pub args_types: Vec<ir::Type>,
|
||||
pub args_types: Vec<api::ValType>,
|
||||
pub data: Rc<ModuleData>,
|
||||
}
|
||||
|
||||
impl Function {
|
||||
pub fn get_signature(&self) -> ir::Signature {
|
||||
let mut instance = self.instance.clone();
|
||||
if let Some(Export::Function { signature, .. }) = instance.lookup(&self.export_name) {
|
||||
signature
|
||||
} else {
|
||||
panic!()
|
||||
}
|
||||
pub fn func(&self) -> api::HostRef<api::Func> {
|
||||
let e = self
|
||||
.instance
|
||||
.borrow()
|
||||
.find_export_by_name(&self.export_name)
|
||||
.expect("named export")
|
||||
.clone();
|
||||
e.func().expect("function export").clone()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,16 +40,9 @@ impl Function {
|
||||
for item in args.iter() {
|
||||
runtime_args.push(pyobj_to_value(py, item)?);
|
||||
}
|
||||
let mut instance = self.instance.clone();
|
||||
let mut cx = self.context.borrow_mut();
|
||||
let results = self
|
||||
.data
|
||||
.invoke(
|
||||
&mut cx,
|
||||
&mut instance,
|
||||
self.export_name.as_str(),
|
||||
&runtime_args,
|
||||
)
|
||||
.invoke_export(&self.instance, self.export_name.as_str(), &runtime_args)
|
||||
.map_err(crate::err2py)?;
|
||||
let mut py_results = Vec::new();
|
||||
for result in results {
|
||||
@@ -64,3 +55,108 @@ impl Function {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_annotation_type(s: &str) -> api::ValType {
|
||||
match s {
|
||||
"I32" | "i32" => api::ValType::I32,
|
||||
"I64" | "i64" => api::ValType::I64,
|
||||
"F32" | "f32" => api::ValType::F32,
|
||||
"F64" | "f64" => api::ValType::F64,
|
||||
_ => panic!("unknown type in annotations"),
|
||||
}
|
||||
}
|
||||
|
||||
struct WrappedFn {
|
||||
func: PyObject,
|
||||
returns_types: Vec<api::ValType>,
|
||||
}
|
||||
|
||||
impl WrappedFn {
|
||||
pub fn new(func: PyObject, returns_types: Vec<api::ValType>) -> Self {
|
||||
WrappedFn {
|
||||
func,
|
||||
returns_types,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl api::Callable for WrappedFn {
|
||||
fn call(
|
||||
&self,
|
||||
params: &[api::Val],
|
||||
returns: &mut [api::Val],
|
||||
) -> Result<(), api::HostRef<api::Trap>> {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
||||
let params = params
|
||||
.iter()
|
||||
.map(|p| match p {
|
||||
api::Val::I32(i) => i.clone().into_py(py),
|
||||
api::Val::I64(i) => i.clone().into_py(py),
|
||||
_ => {
|
||||
panic!();
|
||||
}
|
||||
})
|
||||
.collect::<Vec<PyObject>>();
|
||||
|
||||
let result = self
|
||||
.func
|
||||
.call(py, PyTuple::new(py, params), None)
|
||||
.expect("TODO: convert result to trap");
|
||||
|
||||
let result = if let Ok(t) = result.cast_as::<PyTuple>(py) {
|
||||
t
|
||||
} else {
|
||||
if result.is_none() {
|
||||
PyTuple::empty(py)
|
||||
} else {
|
||||
PyTuple::new(py, &[result])
|
||||
}
|
||||
};
|
||||
for (i, ty) in self.returns_types.iter().enumerate() {
|
||||
let result_item = result.get_item(i);
|
||||
returns[i] = match ty {
|
||||
api::ValType::I32 => api::Val::I32(result_item.extract::<i32>().unwrap()),
|
||||
api::ValType::I64 => api::Val::I64(result_item.extract::<i64>().unwrap()),
|
||||
_ => {
|
||||
panic!();
|
||||
}
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wrap_into_pyfunction(
|
||||
store: &api::HostRef<api::Store>,
|
||||
callable: &PyAny,
|
||||
) -> PyResult<api::HostRef<api::Func>> {
|
||||
if !callable.hasattr("__annotations__")? {
|
||||
// TODO support calls without annotations?
|
||||
return Err(PyErr::new::<Exception, _>(
|
||||
"import is not a function".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let annot = callable.getattr("__annotations__")?.cast_as::<PyDict>()?;
|
||||
let mut params = Vec::new();
|
||||
let mut returns = Vec::new();
|
||||
for (name, value) in annot.iter() {
|
||||
let ty = parse_annotation_type(&value.to_string());
|
||||
match name.to_string().as_str() {
|
||||
"return" => returns.push(ty),
|
||||
_ => params.push(ty),
|
||||
}
|
||||
}
|
||||
|
||||
let ft = api::FuncType::new(
|
||||
params.into_boxed_slice(),
|
||||
returns.clone().into_boxed_slice(),
|
||||
);
|
||||
|
||||
let gil = Python::acquire_gil();
|
||||
let wrapped = WrappedFn::new(callable.to_object(gil.python()), returns);
|
||||
let f = api::Func::new(store, ft, Rc::new(wrapped));
|
||||
Ok(api::HostRef::new(f))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user