mohanson / pywasm Goto Github PK
View Code? Open in Web Editor NEWA WebAssembly interpreter written in pure Python
License: MIT License
A WebAssembly interpreter written in pure Python
License: MIT License
大佬,这个报错是怎么回事,第一次接触wasm,不太懂
----> 1 pywasm.load('Wasm.wasm')
d:\python\lib\site-packages\pywasm\__init__.py in load(name, imps, opts)
97 with open(name, 'rb') as f:
98 module = binary.Module.from_reader(f)
---> 99 return Runtime(module, imps, opts)
100
101
d:\python\lib\site-packages\pywasm\__init__.py in __init__(self, module, imps, opts)
26 for e in module.import_list:
27 if e.module not in imps or e.name not in imps[e.module]:
---> 28 raise Exception(f'pywasm: missing import {e.module}.{e.name}')
29 if isinstance(e.desc, binary.TypeIndex):
30 a = execution.HostFunc(module.type_list[e.desc], imps[e.module][e.name])
Exception: pywasm: missing import env.time
加载的wasm文件 ☛ https://spa14.scrape.center/Wasm.wasm
$ pip install pywasm==1.0.0
Collecting pywasm==1.0.0
Downloading pywasm-1.0.0-py3-none-any.whl (27 kB)
Collecting numpy
Using cached numpy-1.19.4-cp38-cp38-macosx_10_9_x86_64.whl (15.3 MB)
Installing collected packages: numpy, pywasm
Successfully installed numpy-1.19.4 pywasm-1.0.0
$ pip install pywasm==1.0.4
Collecting pywasm==1.0.4
Using cached pywasm-1.0.4.tar.gz (28 kB)
ERROR: Command errored out with exit status 1:
command: /Users/pprescod/code/open_source/wasm_api/.venv/bin/python3 -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/private/var/folders/0y/kdzktrn95clfn6_8cjfyqvx80000gp/T/pip-install-byir0hq3/pywasm/setup.py'"'"'; __file__='"'"'/private/var/folders/0y/kdzktrn95clfn6_8cjfyqvx80000gp/T/pip-install-byir0hq3/pywasm/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base /private/var/folders/0y/kdzktrn95clfn6_8cjfyqvx80000gp/T/pip-pip-egg-info-zfgq73nm
cwd: /private/var/folders/0y/kdzktrn95clfn6_8cjfyqvx80000gp/T/pip-install-byir0hq3/pywasm/
Complete output (5 lines):
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/private/var/folders/0y/kdzktrn95clfn6_8cjfyqvx80000gp/T/pip-install-byir0hq3/pywasm/setup.py", line 7, in <module>
with open(os.path.join(root, 'requirements.txt')) as f:
FileNotFoundError: [Errno 2] No such file or directory: '/private/var/folders/0y/kdzktrn95clfn6_8cjfyqvx80000gp/T/pip-install-byir0hq3/pywasm/requirements.txt'
----------------------------------------
ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.
WARNING: You are using pip version 20.2.1; however, version 20.3.3 is available.
You should consider upgrading via the '/Users/pprescod/code/open_source/wasm_api/.venv/bin/python3 -m pip install --upgrade pip' command.
I was confused with the structure of memoryInstance, why the type of data is bytearray? How about dict with bytearray in it? Doesn't this structure better match the addressing approach of memory?
Are there any docs (perhaps at least auto-generated docs) describing what pywasm.Memory, pywasm.Limits, etc. are?
docs: https://github.com/CraneStation/wasmtime/blob/master/docs/WASI-api.md
The WASI is still not stable. But it's not a big work, so, add this?
I call a runtime instance several times, but each time I need to reattach env functions (because apparently, the old ones refer to outdated data). On first try
runtime.imps = newimps
does not seem to work. Is this possible? I'd prefer to do this without having to reload the entire runtime (which would necessitate loading the .wasm binary from the filessystem again etc.)
# ./test.py
import pywasm
# pywasm.on_debug()
runtime = pywasm.load('./examples/fib.wasm')
r = runtime.exec('fib', [10])
print(r) # 55
> python3 ./test.py
For performance, does not automatically pop out data when call / invoke ends, which is different from the spec, because in most case, we push the result from call / invoke into stack again.
I am going to remove this performance optimization to be exactly the same as the spec describes.
As I understand it, when a Limit is reached, an assertion triggers an exception, the execution halts and if one wants the results, the called function will have to be restarted again, with higher limits.
Would there be a way to implement suspension and resumption when this happens, so the runtime state isn't discarded, much like Stackless Python can: https://stackless.readthedocs.io/en/latest/library/stackless/pickling.html ?
One use case would be something along my https://rlc-chess.com project:
A P2P wireless environment is simulated. Nodes can send messages to other nodes within some radius. Each has a unique id and gets a special packet with the id of another node. The objective is for as many nodes as possible to deliver the packets to the right node. Participants can submit .wasm programs that are instantiated for each node and that try to route the packets correctly.
https://www.youtube.com/watch?v=Y8MvSAZ-YMk
I could do the same as with the chess competition and limit the number of instructions each node can use to process each packet it receives. But it would also be interesting for each node to divide up the time itself. If the interpreter can continue the execution at the exact same instruction and state where it left off, this could be done.
This is something the Life VM also supports: perlin-network/life#52
Not sure how hard this would be to implement.
It might look like this
class Node:
def __init__(self):
self.runtime = pywasm.load(...)
self.result = None
nodes = [Node() for i in range(20)]
while True:
for node in nodes:
node.runtime.machine.opts.cycle_limit = 1000
# I guess instead of raising an assertion, a "soft" return would be required
if node.result.state == pywasm.RESOURCE_EXCEPTION:
node.result = node.runtime.resume()
else:
node.result = node.runtime.exec("process", [], suspend_on_resource_exception=True)
This would go through each node and run it for 1000 steps each, forever. The WebAssembly code itself could contain arbitrarily complex code/loops, since the scheduling is handled this way on the outside.
The Life WebAssembly VM supports setting instruction step ("gas") and memory allocation limits. Would this be possible to implement in pywasm too?
Use cases:
Line 80 in 8cb7872
I'd suggest these be called "minimum" and "maximum" rather than "n" and "m".
This is just something I noted
Running a script that spends most of its time in pywasm's exec:
$ time python main.py
real 2m0,034s
user 2m0,305s
sys 0m0,644s
And with optimizations enabled:
$ time python -O main.py
real 0m0,449s
user 0m0,908s
sys 0m0,481s
According to this -O eliminates assert statements. Not sure how much this impacts security.
Edit: ok, it seems that the code is not executed correctly, I'll have a look
I get this:
File "main.py", line 193, in play
runtime = pywasm.load(runtime, {
File "/home/one/.pyenv/versions/3.8.2/lib/python3.8/site-packages/pywasm/__init__.py", line 98, in load
module = binary.Module.from_reader(f)
File "/home/one/.pyenv/versions/3.8.2/lib/python3.8/site-packages/pywasm/binary.py", line 1084, in from_reader
type_section = TypeSection.from_reader(section_reader)
File "/home/one/.pyenv/versions/3.8.2/lib/python3.8/site-packages/pywasm/binary.py", line 445, in from_reader
o.data = [FunctionType.from_reader(r) for _ in range(n)]
File "/home/one/.pyenv/versions/3.8.2/lib/python3.8/site-packages/pywasm/binary.py", line 445, in <listcomp>
o.data = [FunctionType.from_reader(r) for _ in range(n)]
File "/home/one/.pyenv/versions/3.8.2/lib/python3.8/site-packages/pywasm/binary.py", line 70, in from_reader
o.args = ResultType.from_reader(r)
File "/home/one/.pyenv/versions/3.8.2/lib/python3.8/site-packages/pywasm/binary.py", line 51, in from_reader
o.data = [ValueType.from_reader(r) for i in range(n)]
File "/home/one/.pyenv/versions/3.8.2/lib/python3.8/site-packages/pywasm/binary.py", line 51, in <listcomp>
o.data = [ValueType.from_reader(r) for i in range(n)]
File "/home/one/.pyenv/versions/3.8.2/lib/python3.8/site-packages/pywasm/binary.py", line 33, in from_reader
return ValueType(ord(r.read(1)))
Exception ord() expected a character, but string of length 0 found
Ah, looking through the pywasm code it seems that the asserts have side effects, that are necessary for it to be executed correctly.
I was playing around with wasmer and saw this implmentation I like portable stuff so i tried it.
but for some reason it doesnt behave quite the same as wasmer. I get different images.
wasmer setup
#this uses python-wasmer
from wasmer import FunctionType,Buffer,Memory,MemoryType, engine, Store, Module, Instance, Function,Value,Type
from pathlib import Path
store = Store()
module=Module(store, open('pikchrNoImp.wasm', 'rb').read())
for i in module.imports:
print(i.name)
instance = Instance(module)#, import_object)
memory = instance.exports.memory
def write_c_string(instance,bstring:bytearray):
ptr=instance.exports.stackAlloc(len(bstring)+1)
mem=instance.exports.memory.int8_view()
ptrcnt=ptr
for c in bstring:
mem[ptrcnt]=c
ptrcnt+=1
return ptr
def get_c_string(instance,ptr):
mem = bytearray(instance.exports.memory.buffer)
result_str = mem[ptr:].partition(b"\x00")[0] #get c string
return str(result_str, 'UTF-8')
in1=write_c_string(instance,b"""
arrow right 200% "Markdown" "Source"
box rad 10px "Markdown" "Formatter" "(markdown.c)" fit
arrow right 200% "HTML+SVG" "Output"
arrow <-> down 70% from last box.s
box same "Pikchr" "Formatter" "(pikchr.c)" fit
""")
result = instance.exports.pikchr(in1,0,0,0,0)
print(get_c_string(instance,result))
Path("wasmTest.svg").write_text(get_c_string(instance,result))
pywasm setup
#This uses python-wasmer
import pywasm
from pathlib import Path
option = pywasm.Option()
runtime = pywasm.load('PikchrNoImp.wasm')
def write_c_string(runtime,bstring:bytearray):
ptr=runtime.exec("stackAlloc",[(len(bstring)+1)])
mem=runtime.machine.store.mems[0].data
ptrcnt=ptr
for c in bstring:
mem[ptrcnt]=c
ptrcnt+=1
mem[ptrcnt]=0
return ptr
def get_c_string(runtime,ptr):
mem = runtime.machine.store.mems[0].data
result_str = mem[ptr:].partition(b"\x00")[0] #get c string
return str(result_str, 'UTF-8')
print(get_c_string(runtime,5268992))
in1=write_c_string(runtime,b"""
arrow right 200% "Markdown" "Source"
box rad 10px "Markdown" "Formatter" "(markdown.c)" fit
arrow right 200% "HTML+SVG" "Output"
arrow <-> down 70% from last box.s
box same "Pikchr" "Formatter" "(pikchr.c)" fit
""")
#print(dir(runtime.machine.store.mems.index()))
print(in1)
print(get_c_string(runtime,in1))
r = runtime.exec('pikchr', [in1,0,0,0,0])
print(r)
print(get_c_string(runtime,r))
Path("wasmTest.svg").write_text(get_c_string(runtime,r))
I have no idea why they would have different results? maybe math issue?
In the previous period, the development of pywasm stopped, but it is now full of vitality! Yes! Yes!
To meet the pywasm 1.0, the following work is to be done
In Python, I have a list of integers in the range 0-255, so in the uint8 range.
I want to supply them to the WebAssembly runtime before it starts execution, so the called function will be able to access it when it runs. Can I do this with pywasm?
It might look like this:
import pywasm
numbers = [1,2,3,4,5]#,...
memory = pywasm.Memory(numbers, dtype=pywasm.uint8)
runtime = pywasm.load('./examples/addlist.wasm', memories=[memory])
r = runtime.exec('addlist', [])
print(r) # 1+2+3+4+5+... = x
Finishing up #38
Can you clarify whether pywasm supports a pattern like this?
memory = pywasm.Memory(pywasm.binary.MemoryType(pywasm.binary.Limit(min=1, max=10)))
runtime = pywasm.load('test/malloc.wasm', {'env': {'memory': memory}})
How does one express a memory limit for a WASM runtime?
I am trying to analyse polybench suite (written in C)
Since none of your test files contain any #include, wanted to know what to do in case of such cases.
Used emscripten to comile to .c files to .wasm
On trying to load the file in pyawm using pywasm.load("filename")
Getting the following error:
Exception Traceback (most recent call last)
in
----> 1 vm = pywasm.load('polybench-c-4.1/2mm.wasm')
/usr/local/lib/python3.7/site-packages/pywasm/init.py in load(name, imps)
69 with open(name, 'rb') as f:
70 module = structure.Module.from_reader(f)
---> 71 return VirtualMachine(module, imps)
72
73
/usr/local/lib/python3.7/site-packages/pywasm/init.py in init(self, module, imps)
15 for e in self.module.imports:
16 if e.module not in imps or e.name not in imps[e.module]:
---> 17 raise Exception(f'pywasm: global import {e.module}.{e.name} not found')
18 if e.kind == convention.extern_func:
19 a = execution.HostFunc(self.module.types[e.desc], imps[e.module][e.name])
Exception: pywasm: global import env.calloc not found
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.