Skip to content

Commit 2044bc8

Browse files
committed
Initial commit.
This code has been extracted from yowasp-yosys. The part of it that handles caching has been changed to keep the cached binaries for every WebAssembly module digest around. This does waste some space, but can save a lot of time e.g. when bisecting.
0 parents  commit 2044bc8

File tree

5 files changed

+131
-0
lines changed

5 files changed

+131
-0
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
__pycache__/
2+
/*.egg-info
3+
/.eggs
4+
/build
5+
/dist

LICENSE.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
ISC License
2+
3+
Copyright (C) Catherine <whitequark@whitequark.org>
4+
5+
Permission to use, copy, modify, and/or distribute this software for any
6+
purpose with or without fee is hereby granted, provided that the above
7+
copyright notice and this permission notice appear in all copies.
8+
9+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
YoWASP runtime
2+
==============
3+
4+
This package is an internal support package for the [YoWASP project][yowasp]. It handles interfacing with the [WebAssembly][] runtime and the supported operating systems. Do not depend on this package in your own code.
5+
6+
[webassembly]: https://webassembly.org/
7+
[yowasp]: https://yowasp.github.io/
8+
9+
License
10+
-------
11+
12+
This package is covered by the [ISC license](LICENSE.txt).

pyproject.toml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
[build-system]
2+
requires = ["setuptools~=67.0"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "yowasp-runtime"
7+
version = "1.0"
8+
description = "Common runtime for YoWASP packages"
9+
readme = "README.md"
10+
authors = [{name = "Catherine", email = "whitequark@whitequark.org"}]
11+
license = {file = "LICENSE.txt"}
12+
classifiers = [
13+
"License :: OSI Approved :: ISC License (ISCL)"
14+
]
15+
16+
dependencies = [
17+
"importlib_resources; python_version<'3.9'",
18+
"appdirs~=1.4",
19+
"wasmtime>=1.0,<2"
20+
]
21+
22+
[project.urls]
23+
"Homepage" = "https://yowasp.org/"
24+
"Source Code" = "https://github.com/YoWASP/runtime"
25+
"Bug Tracker" = "https://github.com/YoWASP/runtime/issues"

yowasp_runtime/__init__.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import os
2+
import sys
3+
import wasmtime
4+
import pathlib
5+
import hashlib
6+
import appdirs
7+
try:
8+
from importlib import resources as importlib_resources
9+
importlib_resources.files
10+
except (ImportError, AttributeError):
11+
import importlib_resources
12+
13+
14+
def run_wasm(__package__, wasm_filename, *, resources, argv):
15+
# load the WebAssembly application
16+
module_binary = importlib_resources.read_binary(__package__, wasm_filename)
17+
module_digest = hashlib.sha1(module_binary).hexdigest()
18+
19+
wasi_cfg = wasmtime.WasiConfig()
20+
21+
# inherit standard I/O handles
22+
wasi_cfg.inherit_stdin()
23+
wasi_cfg.inherit_stdout()
24+
wasi_cfg.inherit_stderr()
25+
26+
# use provided argv
27+
wasi_cfg.argv = argv
28+
29+
# preopens for package resources
30+
for resource in resources:
31+
wasi_cfg.preopen_dir(str(importlib_resources.files(__package__) / resource),
32+
"/" + resource)
33+
34+
# preopens for absolute paths
35+
if os.name == "nt":
36+
for letter in "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ":
37+
wasi_cfg.preopen_dir(letter + ":\\", letter + ":")
38+
else:
39+
wasi_cfg.preopen_dir("/", "/")
40+
41+
# preopens for relative paths
42+
wasi_cfg.preopen_dir(".", ".")
43+
for level in range(len(pathlib.Path().cwd().parts)):
44+
wasi_cfg.preopen_dir(str(pathlib.Path("").joinpath(*[".."] * level)),
45+
"/".join([".."] * level))
46+
47+
# compute path to cache
48+
default_cache_path = appdirs.user_cache_dir("YoWASP", appauthor=False)
49+
cache_path = pathlib.Path(os.getenv("YOWASP_CACHE_DIR", default_cache_path))
50+
cache_filename = (cache_path / __package__ / wasm_filename / module_digest)
51+
52+
# compile WebAssembly to machine code, or load cached
53+
engine = wasmtime.Engine()
54+
if cache_filename.exists():
55+
module = wasmtime.Module.deserialize_file(engine, str(cache_filename))
56+
else:
57+
print("Preparing to run {}. This might take a while...".format(argv[0]), file=sys.stderr)
58+
module = wasmtime.Module(engine, module_binary)
59+
cache_filename.parent.mkdir(parents=True, exist_ok=True)
60+
with cache_filename.open("wb") as cache_file:
61+
cache_file.write(module.serialize())
62+
63+
# run compiled code
64+
linker = wasmtime.Linker(engine)
65+
linker.define_wasi()
66+
store = wasmtime.Store(engine)
67+
store.set_wasi(wasi_cfg)
68+
app = linker.instantiate(store, module)
69+
linker.define_instance(store, "app", app)
70+
try:
71+
app.exports(store)["_start"](store)
72+
return 0
73+
except wasmtime.ExitTrap as trap:
74+
return trap.code

0 commit comments

Comments
 (0)