0
# Utilities
1
2
Helper functions and utilities including WebAssembly text format conversion, table management, global variable handling, development aids, and convenience functions for common WebAssembly operations and debugging tasks.
3
4
## Capabilities
5
6
### Text Format Conversion
7
8
WebAssembly Text (WAT) to binary (WASM) conversion utility providing human-readable WebAssembly format support for development, testing, and educational purposes.
9
10
```python { .api }
11
def wat2wasm(wat: str) -> bytes:
12
"""
13
Convert WebAssembly Text format to binary format.
14
15
Parameters:
16
- wat: WebAssembly text format string
17
18
Returns:
19
Binary WebAssembly module bytes
20
21
Raises:
22
WasmtimeError: If WAT parsing or compilation fails
23
"""
24
```
25
26
### Table Management
27
28
WebAssembly table objects providing reference storage, dynamic table operations, element access, and table growth capabilities for function references and external references.
29
30
```python { .api }
31
class Table:
32
def __init__(self, store: Store, ty: TableType, init):
33
"""
34
Create a new table with specified type and initial value.
35
36
Parameters:
37
- store: Store for table allocation context
38
- ty: Table type specifying element type and size limits
39
- init: Initial value for all table elements
40
41
Raises:
42
WasmtimeError: If table creation fails
43
"""
44
45
def type(self, store: Store) -> TableType:
46
"""
47
Get the table type specification.
48
49
Parameters:
50
- store: Store context
51
52
Returns:
53
Table type with element type and current size limits
54
"""
55
56
def size(self, store: Store) -> int:
57
"""
58
Get current table size in elements.
59
60
Parameters:
61
- store: Store context
62
63
Returns:
64
Number of elements in the table
65
"""
66
67
def grow(self, store: Store, delta: int, init) -> int:
68
"""
69
Grow table by specified number of elements.
70
71
Parameters:
72
- store: Store context
73
- delta: Number of elements to add (must be non-negative)
74
- init: Initial value for new elements
75
76
Returns:
77
Previous table size in elements
78
79
Raises:
80
WasmtimeError: If growth fails or exceeds maximum size
81
"""
82
83
def get(self, store: Store, idx: int):
84
"""
85
Get element at specified index.
86
87
Parameters:
88
- store: Store context
89
- idx: Element index (zero-based)
90
91
Returns:
92
Element value at the specified index
93
94
Raises:
95
WasmtimeError: If index is out of bounds
96
"""
97
98
def set(self, store: Store, idx: int, val) -> None:
99
"""
100
Set element at specified index.
101
102
Parameters:
103
- store: Store context
104
- idx: Element index (zero-based)
105
- val: New value for the element
106
107
Raises:
108
WasmtimeError: If index is out of bounds or value type mismatch
109
"""
110
```
111
112
### Global Variables
113
114
WebAssembly global variable objects providing mutable and immutable global state, type-safe value access, and runtime global variable management for WebAssembly modules.
115
116
```python { .api }
117
class Global:
118
def __init__(self, store: Store, ty: GlobalType, val: Val):
119
"""
120
Create a new global variable with specified type and initial value.
121
122
Parameters:
123
- store: Store for global allocation context
124
- ty: Global type specifying value type and mutability
125
- val: Initial value for the global variable
126
127
Raises:
128
WasmtimeError: If global creation fails or value type mismatch
129
"""
130
131
def type(self, store: Store) -> GlobalType:
132
"""
133
Get the global variable type specification.
134
135
Parameters:
136
- store: Store context
137
138
Returns:
139
Global type with value type and mutability information
140
"""
141
142
def value(self, store: Store) -> Val:
143
"""
144
Get the current value of the global variable.
145
146
Parameters:
147
- store: Store context
148
149
Returns:
150
Current global variable value
151
"""
152
153
def set_value(self, store: Store, val: Val) -> None:
154
"""
155
Set the value of the global variable (if mutable).
156
157
Parameters:
158
- store: Store context
159
- val: New value for the global variable
160
161
Raises:
162
WasmtimeError: If global is immutable or value type mismatch
163
"""
164
```
165
166
## Usage Examples
167
168
### WAT to WASM Conversion
169
170
```python
171
import wasmtime
172
173
# Simple arithmetic module in WAT format
174
wat_code = '''
175
(module
176
(func (export "add") (param i32 i32) (result i32)
177
local.get 0
178
local.get 1
179
i32.add)
180
(func (export "multiply") (param f32 f32) (result f32)
181
local.get 0
182
local.get 1
183
f32.mul)
184
(memory (export "memory") 1)
185
(global (export "counter") (mut i32) (i32.const 0))
186
)
187
'''
188
189
# Convert WAT to WASM binary
190
try:
191
wasm_bytes = wasmtime.wat2wasm(wat_code)
192
print(f"Converted WAT to WASM: {len(wasm_bytes)} bytes")
193
194
# Use the compiled module
195
engine = wasmtime.Engine()
196
store = wasmtime.Store(engine)
197
module = wasmtime.Module(engine, wasm_bytes)
198
instance = wasmtime.Instance(store, module, [])
199
200
# Call the functions
201
add_func = instance.exports(store)["add"]
202
multiply_func = instance.exports(store)["multiply"]
203
204
result1 = add_func(store, 15, 27)
205
result2 = multiply_func(store, 3.5, 2.0)
206
207
print(f"15 + 27 = {result1}")
208
print(f"3.5 * 2.0 = {result2}")
209
210
except wasmtime.WasmtimeError as e:
211
print(f"WAT compilation failed: {e}")
212
```
213
214
### Complex WAT Example with Tables and Globals
215
216
```python
217
import wasmtime
218
219
# Advanced WAT example with tables and indirect calls
220
advanced_wat = '''
221
(module
222
;; Function type for binary operations
223
(type $binary_op (func (param i32 i32) (result i32)))
224
225
;; Function table for indirect calls
226
(table (export "functions") 4 funcref)
227
228
;; Global counter
229
(global $counter (mut i32) (i32.const 0))
230
(global (export "counter") (mut i32) (i32.const 0))
231
232
;; Binary operation functions
233
(func $add (type $binary_op)
234
local.get 0
235
local.get 1
236
i32.add)
237
238
(func $sub (type $binary_op)
239
local.get 0
240
local.get 1
241
i32.sub)
242
243
(func $mul (type $binary_op)
244
local.get 0
245
local.get 1
246
i32.mul)
247
248
(func $div (type $binary_op)
249
local.get 0
250
local.get 1
251
i32.div_s)
252
253
;; Initialize function table
254
(elem (i32.const 0) $add $sub $mul $div)
255
256
;; Indirect call function
257
(func (export "call_op") (param i32 i32 i32) (result i32)
258
;; Increment counter
259
global.get $counter
260
i32.const 1
261
i32.add
262
global.set $counter
263
264
;; Indirect call
265
local.get 1 ;; first operand
266
local.get 2 ;; second operand
267
local.get 0 ;; function index
268
call_indirect (type $binary_op))
269
270
;; Get counter value
271
(func (export "get_counter") (result i32)
272
global.get $counter)
273
)
274
'''
275
276
# Convert and use the advanced module
277
try:
278
wasm_bytes = wasmtime.wat2wasm(advanced_wat)
279
280
engine = wasmtime.Engine()
281
store = wasmtime.Store(engine)
282
module = wasmtime.Module(engine, wasm_bytes)
283
instance = wasmtime.Instance(store, module, [])
284
285
exports = instance.exports(store)
286
call_op = exports["call_op"]
287
get_counter = exports["get_counter"]
288
functions_table = exports["functions"]
289
counter_global = exports["counter"]
290
291
# Test indirect function calls
292
operations = ["add", "sub", "mul", "div"]
293
for i, op_name in enumerate(operations):
294
result = call_op(store, i, 20, 4) # function_index, a, b
295
counter = get_counter(store)
296
print(f"{op_name}(20, 4) = {result}, counter = {counter}")
297
298
# Access global directly
299
final_counter = counter_global.value(store)
300
print(f"Final counter value: {final_counter.value}")
301
302
except wasmtime.WasmtimeError as e:
303
print(f"Advanced WAT compilation failed: {e}")
304
```
305
306
### Table Operations
307
308
```python
309
import wasmtime
310
311
# Create engine and store
312
engine = wasmtime.Engine()
313
store = wasmtime.Store(engine)
314
315
# Create table type for function references (0-10 elements)
316
table_limits = wasmtime.Limits(0, 10)
317
table_type = wasmtime.TableType(wasmtime.ValType.FUNCREF, table_limits)
318
319
# Create table with null initial value
320
table = wasmtime.Table(store, table_type, wasmtime.Val.funcref(None))
321
322
print(f"Created table with {table.size(store)} elements")
323
324
# Create some functions to store in the table
325
def host_func1(x: int) -> int:
326
return x * 2
327
328
def host_func2(x: int) -> int:
329
return x + 10
330
331
func_type = wasmtime.FuncType([wasmtime.ValType.I32], [wasmtime.ValType.I32])
332
func1 = wasmtime.Func(store, func_type, host_func1)
333
func2 = wasmtime.Func(store, func_type, host_func2)
334
335
# Grow table to accommodate functions
336
old_size = table.grow(store, 2, wasmtime.Val.funcref(None))
337
print(f"Table grown from {old_size} to {table.size(store)} elements")
338
339
# Set functions in table
340
table.set(store, 0, func1)
341
table.set(store, 1, func2)
342
343
print("Functions stored in table")
344
345
# Retrieve and call functions from table
346
for i in range(2):
347
func_val = table.get(store, i)
348
if func_val.value is not None:
349
func = func_val.value
350
result = func(store, 5)
351
print(f"Function at index {i}: f(5) = {result}")
352
353
# Try to access out of bounds (will raise error)
354
try:
355
table.get(store, 10)
356
except wasmtime.WasmtimeError as e:
357
print(f"Expected error for out of bounds access: {e}")
358
```
359
360
### Global Variable Management
361
362
```python
363
import wasmtime
364
365
# Create engine and store
366
engine = wasmtime.Engine()
367
store = wasmtime.Store(engine)
368
369
# Create mutable global variables
370
mutable_i32_type = wasmtime.GlobalType(wasmtime.ValType.I32, True)
371
mutable_global = wasmtime.Global(store, mutable_i32_type, wasmtime.Val.i32(42))
372
373
# Create immutable global variable
374
immutable_f64_type = wasmtime.GlobalType(wasmtime.ValType.F64, False)
375
immutable_global = wasmtime.Global(store, immutable_f64_type, wasmtime.Val.f64(3.14159))
376
377
# Read global values
378
mutable_value = mutable_global.value(store)
379
immutable_value = immutable_global.value(store)
380
381
print(f"Mutable global: {mutable_value.value} (type: {mutable_value.type})")
382
print(f"Immutable global: {immutable_value.value} (type: {immutable_value.type})")
383
384
# Modify mutable global
385
print("Incrementing mutable global...")
386
current_value = mutable_global.value(store)
387
new_value = wasmtime.Val.i32(current_value.value + 1)
388
mutable_global.set_value(store, new_value)
389
390
updated_value = mutable_global.value(store)
391
print(f"Updated mutable global: {updated_value.value}")
392
393
# Try to modify immutable global (will raise error)
394
try:
395
immutable_global.set_value(store, wasmtime.Val.f64(2.71828))
396
except wasmtime.WasmtimeError as e:
397
print(f"Expected error for immutable global: {e}")
398
399
# Check global types
400
mutable_type = mutable_global.type(store)
401
immutable_type = immutable_global.type(store)
402
403
print(f"Mutable global type: {mutable_type.content}, mutable: {mutable_type.mutability}")
404
print(f"Immutable global type: {immutable_type.content}, mutable: {immutable_type.mutability}")
405
```
406
407
### Utility Functions for Development
408
409
```python
410
import wasmtime
411
import time
412
import json
413
from typing import Dict, Any, List
414
415
class WasmtimeDebugUtils:
416
"""Collection of utility functions for WebAssembly development and debugging"""
417
418
@staticmethod
419
def module_info(module: wasmtime.Module) -> Dict[str, Any]:
420
"""Extract comprehensive information about a WebAssembly module"""
421
info = {
422
"imports": [],
423
"exports": [],
424
"custom_sections": {}
425
}
426
427
# Analyze imports
428
for imp in module.imports:
429
info["imports"].append({
430
"module": imp.module,
431
"name": imp.name,
432
"type": str(imp.type),
433
"type_class": type(imp.type).__name__
434
})
435
436
# Analyze exports
437
for exp in module.exports:
438
info["exports"].append({
439
"name": exp.name,
440
"type": str(exp.type),
441
"type_class": type(exp.type).__name__
442
})
443
444
# Check for common custom sections
445
common_sections = ["name", "producers", "target_features", "linking"]
446
for section_name in common_sections:
447
sections = module.custom_sections(section_name)
448
if sections:
449
info["custom_sections"][section_name] = f"{len(sections)} section(s)"
450
451
return info
452
453
@staticmethod
454
def benchmark_function(func: wasmtime.Func, store: wasmtime.Store,
455
args: List[Any], iterations: int = 1000) -> Dict[str, float]:
456
"""Benchmark a WebAssembly function"""
457
print(f"Benchmarking function with {iterations} iterations...")
458
459
# Warmup
460
for _ in range(10):
461
func(store, *args)
462
463
# Actual benchmark
464
start_time = time.perf_counter()
465
for _ in range(iterations):
466
result = func(store, *args)
467
end_time = time.perf_counter()
468
469
total_time = end_time - start_time
470
avg_time = total_time / iterations
471
472
return {
473
"total_time_seconds": total_time,
474
"average_time_microseconds": avg_time * 1_000_000,
475
"calls_per_second": iterations / total_time,
476
"iterations": iterations,
477
"last_result": result
478
}
479
480
@staticmethod
481
def create_test_wat(function_name: str, operation: str) -> str:
482
"""Generate test WAT code for common operations"""
483
templates = {
484
"add": f'''
485
(module
486
(func (export "{function_name}") (param i32 i32) (result i32)
487
local.get 0
488
local.get 1
489
i32.add))
490
''',
491
492
"factorial": f'''
493
(module
494
(func (export "{function_name}") (param i32) (result i32)
495
(local i32)
496
i32.const 1
497
local.set 1
498
(loop
499
local.get 0
500
i32.const 1
501
i32.le_s
502
if
503
local.get 1
504
return
505
end
506
local.get 1
507
local.get 0
508
i32.mul
509
local.set 1
510
local.get 0
511
i32.const 1
512
i32.sub
513
local.set 0
514
br 0)))
515
''',
516
517
"memory_test": f'''
518
(module
519
(memory (export "memory") 1)
520
(func (export "{function_name}") (param i32 i32)
521
local.get 0
522
local.get 1
523
i32.store))
524
'''
525
}
526
527
return templates.get(operation, templates["add"])
528
529
@staticmethod
530
def validate_and_analyze_wat(wat_code: str) -> Dict[str, Any]:
531
"""Validate WAT code and provide analysis"""
532
try:
533
# Convert WAT to WASM
534
wasm_bytes = wasmtime.wat2wasm(wat_code)
535
536
# Create module for analysis
537
engine = wasmtime.Engine()
538
module = wasmtime.Module(engine, wasm_bytes)
539
540
analysis = {
541
"valid": True,
542
"wasm_size": len(wasm_bytes),
543
"module_info": WasmtimeDebugUtils.module_info(module),
544
"error": None
545
}
546
547
except wasmtime.WasmtimeError as e:
548
analysis = {
549
"valid": False,
550
"wasm_size": 0,
551
"module_info": None,
552
"error": str(e)
553
}
554
555
return analysis
556
557
# Example usage of utility functions
558
if __name__ == "__main__":
559
utils = WasmtimeDebugUtils()
560
561
# Test WAT validation
562
test_wat = utils.create_test_wat("test_add", "add")
563
analysis = utils.validate_and_analyze_wat(test_wat)
564
565
print("WAT Analysis:")
566
print(json.dumps(analysis, indent=2))
567
568
if analysis["valid"]:
569
# Create and benchmark the function
570
engine = wasmtime.Engine()
571
store = wasmtime.Store(engine)
572
wasm_bytes = wasmtime.wat2wasm(test_wat)
573
module = wasmtime.Module(engine, wasm_bytes)
574
instance = wasmtime.Instance(store, module, [])
575
576
add_func = instance.exports(store)["test_add"]
577
benchmark = utils.benchmark_function(add_func, store, [100, 200], 10000)
578
579
print("\nBenchmark Results:")
580
print(json.dumps(benchmark, indent=2))
581
582
# Test factorial function
583
factorial_wat = utils.create_test_wat("factorial", "factorial")
584
factorial_analysis = utils.validate_and_analyze_wat(factorial_wat)
585
586
if factorial_analysis["valid"]:
587
engine = wasmtime.Engine()
588
store = wasmtime.Store(engine)
589
wasm_bytes = wasmtime.wat2wasm(factorial_wat)
590
module = wasmtime.Module(engine, wasm_bytes)
591
instance = wasmtime.Instance(store, module, [])
592
593
factorial_func = instance.exports(store)["factorial"]
594
595
# Test factorial computation
596
for n in range(1, 8):
597
result = factorial_func(store, n)
598
print(f"{n}! = {result}")
599
```