0
# Function Invocation
1
2
Function calling interface supporting both Python-defined host functions and WebAssembly-exported functions. Provides comprehensive parameter marshalling, result handling, caller context access, and instance management for seamless interoperability between Python and WebAssembly code.
3
4
## Capabilities
5
6
### Function Objects
7
8
WebAssembly function wrapper providing type-safe function invocation, parameter validation, and result handling for both host-defined and WebAssembly-exported functions.
9
10
```python { .api }
11
class Func:
12
def __init__(self, store: Store, ty: FuncType, func: Callable, access_caller: bool = False):
13
"""
14
Create a WebAssembly function from Python callable.
15
16
Parameters:
17
- store: Store for function execution context
18
- ty: Function type signature
19
- func: Python callable implementing the function
20
- access_caller: Whether function needs caller context access
21
"""
22
23
def type(self, store: Store) -> FuncType:
24
"""
25
Get the function type signature.
26
27
Parameters:
28
- store: Store context
29
30
Returns:
31
Function type with parameter and result types
32
"""
33
34
def param_arity(self) -> int:
35
"""
36
Get the number of parameters.
37
38
Returns:
39
Number of function parameters
40
"""
41
42
def result_arity(self) -> int:
43
"""
44
Get the number of results.
45
46
Returns:
47
Number of function return values
48
"""
49
50
def call(self, store: Store, *args) -> Union[Val, List[Val], None]:
51
"""
52
Call the function with given arguments.
53
54
Parameters:
55
- store: Store execution context
56
- *args: Function arguments (Python values or Val objects)
57
58
Returns:
59
- None for functions with no results
60
- Single Val for functions with one result
61
- List[Val] for functions with multiple results
62
63
Raises:
64
Trap: If function execution traps
65
WasmtimeError: If arguments don't match function signature
66
"""
67
```
68
69
### Caller Context
70
71
Caller context providing access to the calling instance's exports during host function execution, enabling host functions to interact with WebAssembly module state.
72
73
```python { .api }
74
class Caller:
75
def get_export(self, name: str):
76
"""
77
Get an export from the calling instance.
78
79
Parameters:
80
- name: Name of the export to retrieve
81
82
Returns:
83
Export object (Func, Memory, Table, or Global)
84
85
Raises:
86
WasmtimeError: If export doesn't exist
87
"""
88
```
89
90
### Instance Management
91
92
WebAssembly module instances providing access to instantiated modules, their exports, and runtime state. Instances represent live WebAssembly modules with allocated memory and callable functions.
93
94
```python { .api }
95
class Instance:
96
def __init__(self, store: Store, module: Module, imports: List):
97
"""
98
Instantiate a WebAssembly module.
99
100
Parameters:
101
- store: Store for instance execution context
102
- module: Compiled WebAssembly module
103
- imports: List of import objects matching module's import requirements
104
105
Raises:
106
WasmtimeError: If instantiation fails or imports don't match requirements
107
"""
108
109
def exports(self, store: Store):
110
"""
111
Get all exports as a mapping.
112
113
Parameters:
114
- store: Store context
115
116
Returns:
117
Dictionary-like object mapping export names to export objects
118
"""
119
120
def get_export(self, store: Store, name: str):
121
"""
122
Get a specific export by name.
123
124
Parameters:
125
- store: Store context
126
- name: Export name to retrieve
127
128
Returns:
129
Export object (Func, Memory, Table, or Global)
130
131
Raises:
132
WasmtimeError: If export doesn't exist
133
"""
134
```
135
136
## Usage Examples
137
138
### Calling WebAssembly Functions
139
140
```python
141
import wasmtime
142
143
# Setup engine, store, and module
144
engine = wasmtime.Engine()
145
store = wasmtime.Store(engine)
146
wasm_bytes = wasmtime.wat2wasm('''
147
(module
148
(func (export "add") (param i32 i32) (result i32)
149
local.get 0
150
local.get 1
151
i32.add)
152
(func (export "multiply_add") (param f64 f64 f64) (result f64)
153
local.get 0
154
local.get 1
155
f64.mul
156
local.get 2
157
f64.add)
158
)
159
''')
160
161
module = wasmtime.Module(engine, wasm_bytes)
162
instance = wasmtime.Instance(store, module, [])
163
164
# Get exported functions
165
exports = instance.exports(store)
166
add_func = exports["add"]
167
multiply_add_func = exports["multiply_add"]
168
169
# Call functions with Python values (automatic conversion)
170
result = add_func(store, 5, 3)
171
print(f"5 + 3 = {result}") # Output: 5 + 3 = 8
172
173
# Call with explicit Val objects
174
result = multiply_add_func(store, 2.5, 3.0, 1.0)
175
print(f"2.5 * 3.0 + 1.0 = {result}") # Output: 2.5 * 3.0 + 1.0 = 8.5
176
177
# Check function signatures
178
add_type = add_func.type(store)
179
print(f"Add function: {len(add_type.params)} params -> {len(add_type.results)} results")
180
```
181
182
### Creating Host Functions
183
184
```python
185
import wasmtime
186
187
# Define host function
188
def host_log(caller: wasmtime.Caller, message_ptr: int, message_len: int) -> None:
189
"""Host function that logs messages from WebAssembly"""
190
# Get memory from caller
191
memory = caller.get_export("memory")
192
193
# Read string from WebAssembly memory
194
message_bytes = memory.read(caller, message_ptr, message_ptr + message_len)
195
message = message_bytes.decode('utf-8')
196
print(f"[WASM LOG]: {message}")
197
198
# Create function type: (i32, i32) -> ()
199
log_type = wasmtime.FuncType(
200
[wasmtime.ValType.I32, wasmtime.ValType.I32],
201
[]
202
)
203
204
# Create host function with caller access
205
engine = wasmtime.Engine()
206
store = wasmtime.Store(engine)
207
log_func = wasmtime.Func(store, log_type, host_log, access_caller=True)
208
209
# Use in module instantiation
210
imports = [log_func]
211
# ... instantiate module with imports
212
```
213
214
### Multiple Return Values
215
216
```python
217
import wasmtime
218
219
# WebAssembly function returning multiple values
220
wasm_bytes = wasmtime.wat2wasm('''
221
(module
222
(func (export "divmod") (param i32 i32) (result i32 i32)
223
local.get 0
224
local.get 1
225
i32.div_s
226
local.get 0
227
local.get 1
228
i32.rem_s)
229
)
230
''')
231
232
engine = wasmtime.Engine()
233
store = wasmtime.Store(engine)
234
module = wasmtime.Module(engine, wasm_bytes)
235
instance = wasmtime.Instance(store, module, [])
236
237
# Call function returning multiple values
238
divmod_func = instance.exports(store)["divmod"]
239
results = divmod_func(store, 17, 5)
240
241
print(f"17 divmod 5 = {results}") # List of Val objects
242
print(f"Quotient: {results[0].value}, Remainder: {results[1].value}")
243
```
244
245
### Host Function with Complex Logic
246
247
```python
248
import wasmtime
249
import json
250
251
def json_parse_host(caller: wasmtime.Caller, json_ptr: int, json_len: int, result_ptr: int) -> int:
252
"""
253
Host function that parses JSON and writes result to WebAssembly memory.
254
Returns 1 on success, 0 on error.
255
"""
256
try:
257
# Get memory from caller instance
258
memory = caller.get_export("memory")
259
260
# Read JSON string from WebAssembly memory
261
json_bytes = memory.read(caller, json_ptr, json_ptr + json_len)
262
json_str = json_bytes.decode('utf-8')
263
264
# Parse JSON
265
parsed = json.loads(json_str)
266
267
# For simplicity, just write the number of keys back
268
if isinstance(parsed, dict):
269
key_count = len(parsed)
270
# Write 4-byte integer to result_ptr
271
memory.write(caller, key_count.to_bytes(4, 'little'), result_ptr)
272
return 1
273
else:
274
return 0
275
except Exception as e:
276
print(f"JSON parse error: {e}")
277
return 0
278
279
# Create function type: (i32, i32, i32) -> i32
280
json_parse_type = wasmtime.FuncType(
281
[wasmtime.ValType.I32, wasmtime.ValType.I32, wasmtime.ValType.I32],
282
[wasmtime.ValType.I32]
283
)
284
285
# Create host function
286
engine = wasmtime.Engine()
287
store = wasmtime.Store(engine)
288
json_parse_func = wasmtime.Func(store, json_parse_type, json_parse_host, access_caller=True)
289
```
290
291
### Function Introspection
292
293
```python
294
import wasmtime
295
296
# Load and inspect a WebAssembly module
297
engine = wasmtime.Engine()
298
module = wasmtime.Module.from_file(engine, "complex_module.wasm")
299
300
# Examine exported functions
301
for export in module.exports:
302
if isinstance(export.type, wasmtime.FuncType):
303
func_type = export.type
304
print(f"Function {export.name}:")
305
print(f" Parameters: {len(func_type.params)}")
306
for i, param_type in enumerate(func_type.params):
307
print(f" param[{i}]: {param_type}")
308
print(f" Results: {len(func_type.results)}")
309
for i, result_type in enumerate(func_type.results):
310
print(f" result[{i}]: {result_type}")
311
312
# After instantiation, check function arities
313
store = wasmtime.Store(engine)
314
instance = wasmtime.Instance(store, module, imports)
315
316
for name in ["add", "process", "calculate"]:
317
try:
318
func = instance.get_export(store, name)
319
if isinstance(func, wasmtime.Func):
320
print(f"{name}: {func.param_arity()} params -> {func.result_arity()} results")
321
except wasmtime.WasmtimeError:
322
print(f"Function {name} not found")
323
```
324
325
### Error Handling in Function Calls
326
327
```python
328
import wasmtime
329
330
def safe_divide_host(x: int, y: int) -> int:
331
"""Host function that safely divides two numbers"""
332
if y == 0:
333
# Raise trap for division by zero
334
raise wasmtime.Trap("Division by zero")
335
return x // y
336
337
# Create function type and host function
338
divide_type = wasmtime.FuncType(
339
[wasmtime.ValType.I32, wasmtime.ValType.I32],
340
[wasmtime.ValType.I32]
341
)
342
343
engine = wasmtime.Engine()
344
store = wasmtime.Store(engine)
345
divide_func = wasmtime.Func(store, divide_type, safe_divide_host)
346
347
# Call function with error handling
348
try:
349
result = divide_func(store, 10, 2)
350
print(f"10 / 2 = {result}") # Success
351
352
result = divide_func(store, 10, 0) # This will trap
353
except wasmtime.Trap as trap:
354
print(f"Function trapped: {trap.message}")
355
except wasmtime.WasmtimeError as error:
356
print(f"Runtime error: {error}")
357
```