MVP #1
14
stubs/pywasm/__init__.pyi
Normal file
14
stubs/pywasm/__init__.pyi
Normal file
@ -0,0 +1,14 @@
|
||||
from typing import Any, Dict, List, Optional, Union
|
||||
|
||||
from . import binary
|
||||
from . import option
|
||||
from . import execution
|
||||
|
||||
class Runtime:
|
||||
store: execution.Store
|
||||
|
||||
def __init__(self, module: binary.Module, imps: Optional[Dict[str, Any]] = None, opts: Optional[option.Option] = None):
|
||||
...
|
||||
|
||||
def exec(self, name: str, args: List[Union[int, float]]) -> Any:
|
||||
...
|
||||
6
stubs/pywasm/binary.pyi
Normal file
6
stubs/pywasm/binary.pyi
Normal file
@ -0,0 +1,6 @@
|
||||
from typing import BinaryIO
|
||||
|
||||
class Module:
|
||||
@classmethod
|
||||
def from_reader(cls, reader: BinaryIO) -> 'Module':
|
||||
...
|
||||
10
stubs/pywasm/execution.pyi
Normal file
10
stubs/pywasm/execution.pyi
Normal file
@ -0,0 +1,10 @@
|
||||
from typing import List
|
||||
|
||||
class Result:
|
||||
...
|
||||
|
||||
class MemoryInstance:
|
||||
data: bytearray
|
||||
|
||||
class Store:
|
||||
memory_list: List[MemoryInstance]
|
||||
2
stubs/pywasm/option.pyi
Normal file
2
stubs/pywasm/option.pyi
Normal file
@ -0,0 +1,2 @@
|
||||
class Option:
|
||||
...
|
||||
@ -1,20 +1,21 @@
|
||||
"""
|
||||
Runners to help run WebAssembly code on various interpreters
|
||||
"""
|
||||
from typing import Any, TextIO
|
||||
from typing import Any, Iterable, TextIO
|
||||
|
||||
import io
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
import pywasm.binary
|
||||
import wasm3
|
||||
|
||||
from phasm.compiler import phasm_compile
|
||||
from phasm.parser import phasm_parse
|
||||
from phasm import ourlang
|
||||
from phasm import wasm
|
||||
|
||||
import wasm3
|
||||
|
||||
def wat2wasm(code_wat: str) -> bytes:
|
||||
"""
|
||||
Converts the given WebAssembly Assembly code into WebAssembly Binary
|
||||
@ -101,6 +102,18 @@ class RunnerBase:
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def interpreter_write_memory(self, offset: int, data: Iterable[int]) -> None:
|
||||
"""
|
||||
Writes into the interpreters memory
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def interpreter_read_memory(self, offset: int, length: int) -> bytes:
|
||||
"""
|
||||
Reads from the interpreters memory
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def interpreter_dump_memory(self, textio: TextIO) -> None:
|
||||
"""
|
||||
Dumps the interpreters memory for debugging
|
||||
@ -113,6 +126,37 @@ class RunnerBase:
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
class RunnerPywasm(RunnerBase):
|
||||
"""
|
||||
Implements a runner for pywasm
|
||||
|
||||
See https://pypi.org/project/pywasm/
|
||||
"""
|
||||
module: pywasm.binary.Module
|
||||
runtime: pywasm.Runtime
|
||||
|
||||
def interpreter_setup(self) -> None:
|
||||
# Nothing to set up
|
||||
pass
|
||||
|
||||
def interpreter_load(self) -> None:
|
||||
bytesio = io.BytesIO(self.wasm_bin)
|
||||
self.module = pywasm.binary.Module.from_reader(bytesio)
|
||||
self.runtime = pywasm.Runtime(self.module, {}, None)
|
||||
|
||||
def interpreter_write_memory(self, offset: int, data: Iterable[int]) -> None:
|
||||
for idx, byt in enumerate(data):
|
||||
self.runtime.store.memory_list[0].data[offset + idx] = byt
|
||||
|
||||
def interpreter_read_memory(self, offset: int, length: int) -> bytes:
|
||||
return self.runtime.store.memory_list[0].data[offset:length]
|
||||
|
||||
def interpreter_dump_memory(self, textio: TextIO) -> None:
|
||||
_dump_memory(textio, self.runtime.store.memory_list[0].data)
|
||||
|
||||
def call(self, function: str, *args: Any) -> Any:
|
||||
return self.runtime.exec(function, [*args])
|
||||
|
||||
class RunnerPywasm3(RunnerBase):
|
||||
"""
|
||||
Implements a runner for pywasm3
|
||||
@ -131,6 +175,16 @@ class RunnerPywasm3(RunnerBase):
|
||||
self.mod = self.env.parse_module(self.wasm_bin)
|
||||
self.rtime.load(self.mod)
|
||||
|
||||
def interpreter_write_memory(self, offset: int, data: Iterable[int]) -> None:
|
||||
memory = self.rtime.get_memory(0)
|
||||
|
||||
for idx, byt in enumerate(data):
|
||||
memory[offset + idx] = byt # type: ignore
|
||||
|
||||
def interpreter_read_memory(self, offset: int, length: int) -> bytes:
|
||||
memory = self.rtime.get_memory(0)
|
||||
return memory[offset:length].tobytes()
|
||||
|
||||
def interpreter_dump_memory(self, textio: TextIO) -> None:
|
||||
_dump_memory(textio, self.rtime.get_memory(0))
|
||||
|
||||
|
||||
@ -31,11 +31,9 @@ def testEntry() -> u8:
|
||||
"""
|
||||
|
||||
runner = setup_interpreter(code_py)
|
||||
memory = runner.rtime.get_memory(0)
|
||||
|
||||
# Garbage in the memory so we can test for it
|
||||
for idx in range(128):
|
||||
memory[idx] = idx
|
||||
runner.interpreter_write_memory(0, range(128))
|
||||
|
||||
sys.stderr.write(f'{DASHES} Memory (pre run) {DASHES}\n')
|
||||
runner.interpreter_dump_memory(sys.stderr)
|
||||
@ -45,15 +43,13 @@ def testEntry() -> u8:
|
||||
sys.stderr.write(f'{DASHES} Memory (post run) {DASHES}\n')
|
||||
runner.interpreter_dump_memory(sys.stderr)
|
||||
|
||||
memory = memory.tobytes()
|
||||
|
||||
assert (
|
||||
b'\xC0\xA1\x00\x00'
|
||||
b'\x00\x00\x00\x00'
|
||||
b'\x00\x00\x00\x00'
|
||||
b'\x10\x00\x00\x00'
|
||||
b'\x10\x11\x12\x13' # Untouched because unused
|
||||
) == memory[0:20]
|
||||
) == runner.interpreter_read_memory(0, 20)
|
||||
|
||||
@pytest.mark.integration_test
|
||||
def test___alloc___no_init():
|
||||
@ -68,7 +64,7 @@ def testEntry() -> u8:
|
||||
sys.stderr.write(f'{DASHES} Memory (pre run) {DASHES}\n')
|
||||
runner.interpreter_dump_memory(sys.stderr)
|
||||
|
||||
with pytest.raises(RuntimeError, match='unreachable executed'):
|
||||
with pytest.raises(Exception, match='unreachable'):
|
||||
runner.call('stdlib.alloc.__alloc__', 32)
|
||||
|
||||
@pytest.mark.integration_test
|
||||
@ -80,7 +76,6 @@ def testEntry() -> u8:
|
||||
"""
|
||||
|
||||
runner = setup_interpreter(code_py)
|
||||
memory = runner.rtime.get_memory(0)
|
||||
|
||||
sys.stderr.write(f'{DASHES} Memory (pre run) {DASHES}\n')
|
||||
runner.interpreter_dump_memory(sys.stderr)
|
||||
@ -93,7 +88,14 @@ def testEntry() -> u8:
|
||||
sys.stderr.write(f'{DASHES} Memory (post run) {DASHES}\n')
|
||||
runner.interpreter_dump_memory(sys.stderr)
|
||||
|
||||
assert b'\xC0\xA1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' == memory[0:12]
|
||||
assert (
|
||||
b'\xC0\xA1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7C\x00\x00\x00'
|
||||
b'\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
b'\x00\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||
b'\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00'
|
||||
) == runner.interpreter_read_memory(0, 0x60)
|
||||
|
||||
assert 0x14 == offset0
|
||||
assert 0x38 == offset1
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user