import io import os import subprocess import sys from tempfile import NamedTemporaryFile from pywasm import binary from pywasm import Runtime from py2wasm.utils import process def wat2wasm(code_wat): path = os.environ.get('WAT2WASM', 'wat2wasm') with NamedTemporaryFile('w+t') as input_fp: input_fp.write(code_wat) input_fp.flush() with NamedTemporaryFile('w+b') as output_fp: subprocess.run( [ path, input_fp.name, '-o', output_fp.name, ], check=True, ) output_fp.seek(0) return output_fp.read() class SuiteResult: def __init__(self): self.log_int32_list = [] self.returned_value = None def callback_log_int32(self, store, value): del store # auto passed by pywasm self.log_int32_list.append(value) def make_imports(self): return { 'console': { 'logInt32': self.callback_log_int32, } } class Suite: def __init__(self, code_py, test_name): self.code_py = code_py self.test_name = test_name def run_code(self, *args): """ Compiles the given python code into wasm and then runs it Returned is an object with the results set """ code_wat = process(self.code_py, self.test_name) dashes = '-' * 16 sys.stderr.write(f'{dashes} Assembly {dashes}\n') line_list = code_wat.split('\n') line_no_width = len(str(len(line_list))) for line_no, line_txt in enumerate(line_list): sys.stderr.write('{} {}\n'.format( str(line_no + 1).zfill(line_no_width), line_txt, )) code_wasm = wat2wasm(code_wat) module = binary.Module.from_reader(io.BytesIO(code_wasm)) result = SuiteResult() runtime = Runtime(module, result.make_imports(), {}) sys.stderr.write(f'{dashes} Memory (pre run) {dashes}\n') _dump_memory(runtime.store.mems[0].data) result.returned_value = runtime.exec('testEntry', args) sys.stderr.write(f'{dashes} Memory (post run) {dashes}\n') _dump_memory(runtime.store.mems[0].data) return result def _dump_memory(mem): line_width = 16 prev_line = None skip = False for idx in range(0, len(mem), line_width): line = '' for idx2 in range(0, line_width): line += f'{mem[idx + idx2]:02X}' if idx2 % 2 == 1: line += ' ' if prev_line == line: if not skip: sys.stderr.write('**\n') skip = True else: sys.stderr.write(f'{idx:08x} {line}\n') prev_line = line