Skip to content

Commit 383cad6

Browse files
FIXES #137: make calling wasm from python 7x faster
1 parent d383a05 commit 383cad6

File tree

1 file changed

+41
-8
lines changed

1 file changed

+41
-8
lines changed

wasmtime/_func.py

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
from typing import Callable, Optional, Generic, TypeVar, List, Union, Tuple, cast as cast_type, Sequence
88
from ._exportable import AsExtern
99
from ._store import Storelike
10-
from ._bindings import wasmtime_val_raw_t, wasm_valtype_kind
10+
from ._bindings import wasmtime_val_raw_t, wasm_valtype_kind, wasmtime_val_t, wasmtime_externref_t, wasmtime_func_t
11+
from ._value import _unintern
1112
from ._ffi import (
1213
WASMTIME_I32,
1314
WASMTIME_I64,
@@ -18,6 +19,7 @@
1819
WASMTIME_EXTERNREF,
1920
WASM_ANYREF,
2021
WASM_FUNCREF,
22+
wasmtime_externref_data,
2123
)
2224

2325

@@ -40,11 +42,41 @@
4042
def get_valtype_attr(ty: ValType):
4143
return val_id2attr[wasm_valtype_kind(ty._ptr)]
4244

45+
from struct import Struct
46+
47+
def val_getter(store_id, val_raw, attr):
48+
val = getattr(val_raw, attr)
49+
50+
if attr=='externref':
51+
ptr = ctypes.POINTER(wasmtime_externref_t)
52+
if not val: return None
53+
ffi = ptr.from_address(val)
54+
if not ffi: return
55+
extern_id = wasmtime_externref_data(ffi)
56+
ret = _unintern(extern_id)
57+
return ret
58+
elif attr=='funcref':
59+
if val==0: return None
60+
f=wasmtime_func_t()
61+
f.store_id=store_id
62+
f.index=val
63+
ret=Func._from_raw(f)
64+
return ret
65+
return val
66+
4367
def val_setter(dst, attr, val):
4468
if attr=='externref':
45-
# TODO: handle None
46-
v = Val.externref(val)
47-
casted = ctypes.addressof(v._raw.of.externref)
69+
if isinstance(val, Val) and val._raw.kind==WASMTIME_EXTERNREF.value:
70+
if val._raw.of.externref:
71+
extern_id = wasmtime_externref_data(val._raw.of.externref)
72+
casted = ctypes.addressof(val._raw.of.externref)
73+
else:
74+
v = Val.externref(val)
75+
casted = ctypes.addressof(v._raw.of.externref)
76+
elif attr=='funcref':
77+
if isinstance(val, Val) and val._raw.kind==WASMTIME_FUNCREF.value:
78+
casted = val._raw.of.funcref.index
79+
else: raise RuntimeError("foo")
4880
elif isinstance(val, Func):
4981
# TODO: handle null_funcref
5082
# TODO: validate same val._func.store_id
@@ -112,9 +144,10 @@ def _extract_return(self, vals_raw: ctypes.Array[wasmtime_val_raw_t]) -> Union[I
112144
if self._results_n==0:
113145
return None
114146
if self._results_n==1:
115-
return getattr(vals_raw[0], self._results_str0)
147+
ret = val_getter(self._func.store_id, vals_raw[0], self._results_str0)
148+
return ret
116149
# we can use tuple construct, but I'm using list for compatability
117-
return [getattr(val_raw, ret_str) for val_raw, ret_str in zip(vals_raw, self._results_str)]
150+
return [val_getter(self._func.store_id, val_raw, ret_str) for val_raw, ret_str in zip(vals_raw, self._results_str)]
118151

119152
def _init_call(self, ty: FuncType):
120153
"""init signature properties used by call"""
@@ -123,8 +156,8 @@ def _init_call(self, ty: FuncType):
123156
ty_results = ty.results
124157
params_n = len(ty_params)
125158
results_n = len(ty_results)
126-
self._params_str = (get_valtype_attr(i) for i in ty_params)
127-
self._results_str = (get_valtype_attr(i) for i in ty_results)
159+
self._params_str = [get_valtype_attr(i) for i in ty_params]
160+
self._results_str = [get_valtype_attr(i) for i in ty_results]
128161
self._results_str0 = get_valtype_attr(ty_results[0]) if results_n else None
129162
self._params_n = params_n
130163
self._results_n = results_n

0 commit comments

Comments
 (0)