diff --git a/tests/integration/runners.py b/tests/integration/runners.py index 5d26797..c1350ff 100644 --- a/tests/integration/runners.py +++ b/tests/integration/runners.py @@ -3,6 +3,7 @@ Runners to help run WebAssembly code on various interpreters """ from typing import Any, Iterable, TextIO +import ctypes import io import os import subprocess @@ -10,6 +11,7 @@ import tempfile import pywasm.binary import wasm3 +import wasmtime from phasm.compiler import phasm_compile from phasm.parser import phasm_parse @@ -191,6 +193,66 @@ class RunnerPywasm3(RunnerBase): def call(self, function: str, *args: Any) -> Any: return self.rtime.find_function(function)(*args) +class RunnerWasmtime(RunnerBase): + """ + Implements a runner for wasmtime + + See https://pypi.org/project/wasmtime/ + """ + store: wasmtime.Store + module: wasmtime.Module + instance: wasmtime.Instance + + def interpreter_setup(self) -> None: + self.store = wasmtime.Store() + + def interpreter_load(self) -> None: + self.module = wasmtime.Module(self.store.engine, self.wasm_bin) + self.instance = wasmtime.Instance(self.store, self.module, []) + + def interpreter_write_memory(self, offset: int, data: Iterable[int]) -> None: + exports = self.instance.exports(self.store) + memory = exports['memory'] + assert isinstance(memory, wasmtime.Memory) # type hint + + data_ptr = memory.data_ptr(self.store) + data_len = memory.data_len(self.store) + + idx = offset + for byt in data: + assert idx < data_len + data_ptr[idx] = ctypes.c_ubyte(byt) + idx += 1 + + def interpreter_read_memory(self, offset: int, length: int) -> bytes: + exports = self.instance.exports(self.store) + memory = exports['memory'] + assert isinstance(memory, wasmtime.Memory) # type hint + + data_ptr = memory.data_ptr(self.store) + data_len = memory.data_len(self.store) + + raw = ctypes.string_at(data_ptr, data_len) + + return raw[offset:length] + + def interpreter_dump_memory(self, textio: TextIO) -> None: + exports = self.instance.exports(self.store) + memory = exports['memory'] + assert isinstance(memory, wasmtime.Memory) # type hint + + data_ptr = memory.data_ptr(self.store) + data_len = memory.data_len(self.store) + + _dump_memory(textio, ctypes.string_at(data_ptr, data_len)) + + def call(self, function: str, *args: Any) -> Any: + exports = self.instance.exports(self.store) + func = exports[function] + assert isinstance(func, wasmtime.Func) + + return func(self.store, *args) + def _dump_memory(textio: TextIO, mem: bytes) -> None: line_width = 16 diff --git a/tests/integration/test_stdlib_alloc.py b/tests/integration/test_stdlib_alloc.py index 850c87f..7e960d7 100644 --- a/tests/integration/test_stdlib_alloc.py +++ b/tests/integration/test_stdlib_alloc.py @@ -3,10 +3,10 @@ import sys import pytest from .helpers import DASHES -from .runners import RunnerPywasm3 +from .runners import RunnerPywasm3 as Runner -def setup_interpreter(phash_code: str) -> RunnerPywasm3: - runner = RunnerPywasm3(phash_code) +def setup_interpreter(phash_code: str) -> Runner: + runner = Runner(phash_code) runner.parse() runner.compile_ast()