forked from Mirrors/wasm3
Merge branch 'main' of https://github.com/wasm3/wasm3 into main
commit
7a1848cbf6
@ -1,3 +0,0 @@
|
||||
dist/
|
||||
pywasm3.egg-info/
|
||||
.pytest*
|
@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Volodymyr Shymanskyy
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
@ -1,3 +0,0 @@
|
||||
graft m3
|
||||
include README.md
|
||||
include LICENSE
|
@ -1,67 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import wasm3
|
||||
import base64, time, timeit
|
||||
|
||||
"""
|
||||
Input module:
|
||||
(module
|
||||
(type (;0;) (func (param i64) (result i64)))
|
||||
(func (;0;) (type 0) (param i64) (result i64)
|
||||
local.get 0
|
||||
i64.const 2
|
||||
i64.lt_u
|
||||
if ;; label = @1
|
||||
local.get 0
|
||||
return
|
||||
end
|
||||
local.get 0
|
||||
i64.const 2
|
||||
i64.sub
|
||||
call 0
|
||||
local.get 0
|
||||
i64.const 1
|
||||
i64.sub
|
||||
call 0
|
||||
i64.add
|
||||
return)
|
||||
(export "fib" (func 0)))
|
||||
"""
|
||||
|
||||
# WebAssembly binary
|
||||
WASM = base64.b64decode("""
|
||||
AGFzbQEAAAABBgFgAX4BfgMCAQAHBwEDZmliAAAKHwEdACAAQgJUBEAgAA8LIABCAn0QACAAQgF9
|
||||
EAB8Dws=
|
||||
""")
|
||||
|
||||
(N, RES, CYCLES) = (24, 46368, 1000)
|
||||
|
||||
# Note: this is cold-start
|
||||
def run_wasm():
|
||||
env = wasm3.Environment()
|
||||
rt = env.new_runtime(4096)
|
||||
mod = env.parse_module(WASM)
|
||||
rt.load(mod)
|
||||
wasm_fib = rt.find_function("fib")
|
||||
assert wasm_fib(N) == RES
|
||||
|
||||
def fib(n: int) -> int:
|
||||
if n < 2:
|
||||
return n
|
||||
return fib(n-1) + fib(n-2)
|
||||
|
||||
def run_py():
|
||||
assert fib(N) == RES
|
||||
|
||||
t1 = timeit.timeit(run_wasm, number=CYCLES)
|
||||
print(f"Wasm3: {t1:.4f} seconds")
|
||||
print("Cooling down... ", end="", flush=True)
|
||||
time.sleep(10)
|
||||
print("ok")
|
||||
t2 = timeit.timeit(run_py, number=CYCLES)
|
||||
if t2 > t1:
|
||||
ratio = f"{(t2/t1):.1f}x slower"
|
||||
else:
|
||||
retio = f"{(t1/t2):.1f}x faster"
|
||||
print(f"Python: {t2:.4f} seconds, {ratio}")
|
||||
|
@ -1,31 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import wasm3
|
||||
import os, time
|
||||
|
||||
scriptpath = os.path.dirname(os.path.realpath(__file__))
|
||||
wasm_fn = os.path.join(scriptpath, "./wasm/coremark-minimal.wasm")
|
||||
|
||||
print("Initializing Wasm3 engine...")
|
||||
|
||||
def clock_ms():
|
||||
return int(round(time.time() * 1000))
|
||||
|
||||
env = wasm3.Environment()
|
||||
rt = env.new_runtime(4096)
|
||||
|
||||
with open(wasm_fn, "rb") as f:
|
||||
mod = env.parse_module(f.read())
|
||||
rt.load(mod)
|
||||
mod.link_function("env", "clock_ms", "I()", clock_ms)
|
||||
|
||||
wasm_run = rt.find_function("run")
|
||||
|
||||
print("Running CoreMark 1.0...")
|
||||
res = wasm_run()
|
||||
|
||||
if res > 1:
|
||||
print(f"Result: {res:.3f}")
|
||||
else:
|
||||
print("Error")
|
||||
|
@ -1,38 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import wasm3
|
||||
import os, time
|
||||
|
||||
scriptpath = os.path.dirname(os.path.realpath(__file__))
|
||||
wasm_fn = os.path.join(scriptpath, "./wasm/coremark-metered.wasm")
|
||||
|
||||
print("Initializing Wasm3 engine...")
|
||||
|
||||
def clock_ms():
|
||||
return int(round(time.time() * 1000))
|
||||
|
||||
env = wasm3.Environment()
|
||||
rt = env.new_runtime(4096)
|
||||
|
||||
with open(wasm_fn, "rb") as f:
|
||||
mod = env.parse_module(f.read())
|
||||
rt.load(mod)
|
||||
mod.link_function("env", "clock_ms", "I()", clock_ms)
|
||||
|
||||
# Gas metering will only apply to metered (pre-instrumented) modules
|
||||
mod.gasLimit = 500_000_000
|
||||
|
||||
wasm_run = rt.find_function("run")
|
||||
|
||||
print("Running CoreMark 1.0...")
|
||||
try:
|
||||
res = wasm_run()
|
||||
|
||||
if res > 1:
|
||||
print(f"Result: {res:.3f}")
|
||||
else:
|
||||
print("Error")
|
||||
finally:
|
||||
if mod.gasUsed:
|
||||
print(f"Gas used: {mod.gasUsed}")
|
||||
|
@ -1,115 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import wasm3
|
||||
import base64, struct
|
||||
import asyncio
|
||||
|
||||
"""
|
||||
This is a straightforward translation of JavaScript example from:
|
||||
https://kripken.github.io/blog/wasm/2019/07/16/asyncify.html
|
||||
|
||||
Input module:
|
||||
(module
|
||||
(import "env" "before" (func $before))
|
||||
(import "env" "sleep" (func $sleep (param i32)))
|
||||
(import "env" "after" (func $after))
|
||||
(export "memory" (memory 0))
|
||||
(export "main" (func $main))
|
||||
(func $main
|
||||
(call $before)
|
||||
(call $sleep (i32.const 2000))
|
||||
(call $after)
|
||||
)
|
||||
(memory 1 1)
|
||||
)
|
||||
|
||||
Asyncify command:
|
||||
wasm-opt async.wasm --asyncify -O3 -o asyncified.wasm
|
||||
"""
|
||||
|
||||
# WebAssembly binary
|
||||
WASM = base64.b64decode("""
|
||||
AGFzbQEAAAABDANgAABgAX8AYAABfwImAwNlbnYGYmVmb3JlAAADZW52BXNsZWVwAAEDZW52BWFm
|
||||
dGVyAAADBgUAAQABAgUEAQEBAQYLAn8BQQALfwFBAAsHhAEHBm1lbW9yeQIABG1haW4AAxVhc3lu
|
||||
Y2lmeV9zdGFydF91bndpbmQABBRhc3luY2lmeV9zdG9wX3Vud2luZAAFFWFzeW5jaWZ5X3N0YXJ0
|
||||
X3Jld2luZAAGFGFzeW5jaWZ5X3N0b3BfcmV3aW5kAAUSYXN5bmNpZnlfZ2V0X3N0YXRlAAcK3gEF
|
||||
jAEBAX8CfyMAQQJGBEAjASMBKAIAQXxqNgIAIwEoAgAoAgAhAAsgAEVBASMAGwRAEABBACMAQQFG
|
||||
DQEaCyAAQQFGQQEjABsEQEHQDxABQQEjAEEBRg0BGgsgAEECRkEBIwAbBEAQAkECIwBBAUYNARoL
|
||||
DwshACMBKAIAIAA2AgAjASMBKAIAQQRqNgIACxkAQQEkACAAJAEjASgCACMBKAIESwRAAAsLFQBB
|
||||
ACQAIwEoAgAjASgCBEsEQAALCxkAQQIkACAAJAEjASgCACMBKAIESwRAAAsLBAAjAAs=
|
||||
""")
|
||||
|
||||
# Init asyncio
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
def set_timeout(ms):
|
||||
def decorator(func):
|
||||
def wrapper(*args, **kwargs):
|
||||
return func(*args, **kwargs)
|
||||
loop.call_later(ms/1000, func)
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
|
||||
# Prepare Wasm3 engine
|
||||
|
||||
env = wasm3.Environment()
|
||||
rt = env.new_runtime(1024)
|
||||
mod = env.parse_module(WASM)
|
||||
rt.load(mod)
|
||||
mem = rt.get_memory(0)
|
||||
|
||||
# ------------------------------------------------
|
||||
def env_before():
|
||||
print("before!")
|
||||
|
||||
@set_timeout(1000)
|
||||
def callback():
|
||||
print("(an event that happens during the sleep)")
|
||||
|
||||
# ------------------------------------------------
|
||||
def env_sleep(ms):
|
||||
global sleeping
|
||||
if not sleeping:
|
||||
print(f"sleep...")
|
||||
DATA_ADDR = 16
|
||||
mem[DATA_ADDR:DATA_ADDR+8] = struct.pack("<II", DATA_ADDR+8, 1024)
|
||||
asyncify_start_unwind(DATA_ADDR)
|
||||
sleeping = True
|
||||
|
||||
@set_timeout(ms)
|
||||
def callback():
|
||||
print("timeout ended, starting to rewind the stack")
|
||||
asyncify_start_rewind(DATA_ADDR)
|
||||
main()
|
||||
else:
|
||||
print("...resume")
|
||||
asyncify_stop_rewind()
|
||||
sleeping = False
|
||||
|
||||
# ------------------------------------------------
|
||||
def env_after():
|
||||
print("after!")
|
||||
loop.stop()
|
||||
|
||||
mod.link_function("env", "before", "v()", env_before)
|
||||
mod.link_function("env", "sleep", "v(i)", env_sleep)
|
||||
mod.link_function("env", "after", "v()", env_after)
|
||||
|
||||
sleeping = False
|
||||
|
||||
main = rt.find_function("main")
|
||||
asyncify_start_unwind = rt.find_function("asyncify_start_unwind")
|
||||
asyncify_stop_unwind = rt.find_function("asyncify_stop_unwind")
|
||||
asyncify_start_rewind = rt.find_function("asyncify_start_rewind")
|
||||
asyncify_stop_rewind = rt.find_function("asyncify_stop_rewind")
|
||||
|
||||
main()
|
||||
print("stack unwound")
|
||||
asyncify_stop_unwind()
|
||||
|
||||
try:
|
||||
loop.run_forever()
|
||||
finally:
|
||||
loop.close()
|
@ -1,97 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os, struct, time
|
||||
import multiprocessing as mp
|
||||
import wasm3
|
||||
import numpy
|
||||
|
||||
os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "true"
|
||||
|
||||
sample_rate = 22050 # or 44100
|
||||
|
||||
def player(q):
|
||||
import pygame
|
||||
pygame.mixer.pre_init(frequency=sample_rate, size=-16, channels=2)
|
||||
pygame.init()
|
||||
|
||||
channel = pygame.mixer.Channel(0)
|
||||
try:
|
||||
while True:
|
||||
chunk = pygame.mixer.Sound(buffer=q.get())
|
||||
|
||||
indicator = '|' if channel.get_queue() else '.'
|
||||
print(indicator, end='', flush=True)
|
||||
|
||||
while channel.get_queue() is not None:
|
||||
time.sleep(0.01)
|
||||
|
||||
channel.queue(chunk)
|
||||
except:
|
||||
pass
|
||||
finally:
|
||||
pygame.quit()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
print("Hondarribia - intro song for WebAssembly Summit 2020 by Peter Salomonsen")
|
||||
print("Source: https://petersalomonsen.com/webassemblymusic/livecodev2/?gist=5b795090ead4f192e7f5ee5dcdd17392")
|
||||
print("Synthesized: https://soundcloud.com/psalomo/hondarribia")
|
||||
|
||||
q = mp.Queue()
|
||||
p = mp.Process(target=player, args=(q,))
|
||||
p.start()
|
||||
|
||||
scriptpath = os.path.dirname(os.path.realpath(__file__))
|
||||
wasm_fn = os.path.join(scriptpath, f"./wasm/hondarribia-{sample_rate}.wasm")
|
||||
|
||||
# Prepare Wasm3 engine
|
||||
|
||||
env = wasm3.Environment()
|
||||
rt = env.new_runtime(1024)
|
||||
with open(wasm_fn, "rb") as f:
|
||||
mod = env.parse_module(f.read())
|
||||
rt.load(mod)
|
||||
|
||||
print("Pre-buffering...")
|
||||
buff = b''
|
||||
buff_sz = 1024
|
||||
|
||||
def fd_write(fd, wasi_iovs, iows_len, nwritten):
|
||||
global buff, buff_sz
|
||||
mem = rt.get_memory(0)
|
||||
|
||||
# get data
|
||||
(off, size) = struct.unpack("<II", mem[wasi_iovs:wasi_iovs+8])
|
||||
data = mem[off:off+size]
|
||||
|
||||
# decode
|
||||
arr = numpy.frombuffer(data, dtype=numpy.float32)
|
||||
data = (arr * 32768).astype(numpy.int16).tobytes()
|
||||
|
||||
# buffer
|
||||
buff += data
|
||||
if len(buff) > buff_sz*1024:
|
||||
#print('+', end='', flush=True)
|
||||
q.put(buff)
|
||||
buff = b''
|
||||
buff_sz = 64
|
||||
|
||||
return size
|
||||
|
||||
for modname in ["wasi_unstable", "wasi_snapshot_preview1"]:
|
||||
mod.link_function(modname, "fd_write", "i(i*i*)", fd_write)
|
||||
|
||||
wasm_start = rt.find_function("_start")
|
||||
try:
|
||||
wasm_start()
|
||||
q.put(buff)
|
||||
except:
|
||||
pass
|
||||
finally:
|
||||
q.put(None)
|
||||
p.join()
|
||||
|
||||
print()
|
||||
print("Finished")
|
||||
|
@ -1,78 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import wasm3
|
||||
import os, time, random, math, base64
|
||||
import pygame
|
||||
|
||||
print("WebAssembly demo file provided by Ben Smith (binji)")
|
||||
print("Sources: https://github.com/binji/raw-wasm")
|
||||
|
||||
scriptpath = os.path.dirname(os.path.realpath(__file__))
|
||||
wasm_fn = os.path.join(scriptpath, "./wasm/chip8.wasm")
|
||||
|
||||
# Prepare Wasm3 engine
|
||||
|
||||
env = wasm3.Environment()
|
||||
rt = env.new_runtime(1024)
|
||||
with open(wasm_fn, "rb") as f:
|
||||
mod = env.parse_module(f.read())
|
||||
rt.load(mod)
|
||||
mod.link_function("Math", "random", "f()", random.random)
|
||||
|
||||
wasm_run = rt.find_function("run")
|
||||
mem = rt.get_memory(0)
|
||||
|
||||
# Load CHIP-8 ROM
|
||||
|
||||
ROM = base64.b64decode("""
|
||||
YwfB/6Js8R7wZUAAEgKEAMUfokz1HvBlyANIABImhkCGAkYAEgKjbIBg8FWEY6Js8R6AQPBVo2yC
|
||||
EIEygR6BHoEegiaCJoIm0SESAgMGDBgwYMCBBw4cOHDgwYMPHjx48OHDhx8+fPjx48eP////////
|
||||
////x/////////+D/////////wI/////////BB/4Z88TP/yED/mnjnN/+GgP+aeWcP/4GBP4ZzZw
|
||||
//AEIfmnAnN/4AJA+CE6cz/AAoH4YTsTP8BDAn//////gP4EP/////+A/wg5ydDD/8A/kHnJ05//
|
||||
wA/g+cnTn//gB+F5zLDH//ADEnnMs+P/+AMM+E5wh//8AwD4TnCH//wBAP///////gEA////////
|
||||
AQH5zmEIR/8AA/nMYQnD/4AD+Eyzmcv/gAf4CbOYQ/8Hh/koE5nH/wOH+SnTmEP/AQf56dOYSf8B
|
||||
B////////wEH////////AQf//////wA=
|
||||
""")
|
||||
|
||||
mem[0x200:0x200+len(ROM)] = ROM
|
||||
|
||||
# Map memory region to an RGBA image
|
||||
|
||||
img_base = 0x1000
|
||||
img_size = (64, 32)
|
||||
(img_w, img_h) = img_size
|
||||
region = mem[img_base : img_base + (img_w * img_h * 4)]
|
||||
img = pygame.image.frombuffer(region, img_size, "RGBA")
|
||||
|
||||
# Prepare PyGame
|
||||
|
||||
scr_size = (img_w*8, img_h*8)
|
||||
pygame.init()
|
||||
surface = pygame.display.set_mode(scr_size)
|
||||
pygame.display.set_caption("Wasm3 CHIP-8")
|
||||
white = (255, 255, 255)
|
||||
|
||||
clock = pygame.time.Clock()
|
||||
|
||||
while True:
|
||||
# Process input
|
||||
for event in pygame.event.get():
|
||||
if (event.type == pygame.QUIT or
|
||||
(event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE)):
|
||||
pygame.quit()
|
||||
quit()
|
||||
|
||||
# TODO: input support
|
||||
#mem[10] = 0
|
||||
|
||||
# Render next frame
|
||||
wasm_run(500)
|
||||
|
||||
# Image output
|
||||
img_scaled = pygame.transform.scale(img, scr_size)
|
||||
surface.fill(white)
|
||||
surface.blit(img_scaled, (0, 0))
|
||||
pygame.display.flip()
|
||||
|
||||
# Stabilize FPS
|
||||
clock.tick(60)
|
@ -1,75 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import wasm3
|
||||
import os, time, random
|
||||
import pygame
|
||||
|
||||
print("WebAssembly demo file provided by Ben Smith (binji)")
|
||||
print("Sources: https://github.com/binji/raw-wasm")
|
||||
|
||||
scriptpath = os.path.dirname(os.path.realpath(__file__))
|
||||
wasm_fn = os.path.join(scriptpath, "./wasm/dino.wasm")
|
||||
|
||||
# Prepare Wasm3 engine
|
||||
|
||||
env = wasm3.Environment()
|
||||
rt = env.new_runtime(1024)
|
||||
with open(wasm_fn, "rb") as f:
|
||||
mod = env.parse_module(f.read())
|
||||
rt.load(mod)
|
||||
mod.link_function("Math", "random", "f()", lambda: random.random())
|
||||
|
||||
wasm_run = rt.find_function("run")
|
||||
mem = rt.get_memory(0)
|
||||
|
||||
# Map memory region to an RGBA image
|
||||
|
||||
img_base = 0x5000
|
||||
img_size = (300, 75)
|
||||
(img_w, img_h) = img_size
|
||||
region = mem[img_base : img_base + (img_w * img_h * 4)]
|
||||
img = pygame.image.frombuffer(region, img_size, "RGBA")
|
||||
|
||||
# Prepare PyGame
|
||||
|
||||
scr_size = (img_w*4, img_h*4)
|
||||
pygame.init()
|
||||
surface = pygame.display.set_mode(scr_size)
|
||||
pygame.display.set_caption("Wasm3 Dino")
|
||||
white = (255, 255, 255)
|
||||
|
||||
k_jump = False
|
||||
k_duck = False
|
||||
|
||||
clock = pygame.time.Clock()
|
||||
|
||||
while True:
|
||||
# Process input
|
||||
for event in pygame.event.get():
|
||||
if (event.type == pygame.QUIT or
|
||||
(event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE)):
|
||||
pygame.quit()
|
||||
quit()
|
||||
elif event.type == pygame.KEYDOWN or event.type == pygame.KEYUP:
|
||||
if event.key == pygame.K_UP:
|
||||
k_jump = (event.type == pygame.KEYDOWN)
|
||||
elif event.key == pygame.K_DOWN:
|
||||
k_duck = (event.type == pygame.KEYDOWN)
|
||||
|
||||
mem[0] = 0
|
||||
if k_jump:
|
||||
mem[0] |= 0x1 # Jump flag
|
||||
if k_duck:
|
||||
mem[0] |= 0x2 # Duck flag
|
||||
|
||||
# Render next frame
|
||||
wasm_run()
|
||||
|
||||
# Image output
|
||||
img_scaled = pygame.transform.scale(img, scr_size)
|
||||
surface.fill(white)
|
||||
surface.blit(img_scaled, (0, 0))
|
||||
pygame.display.flip()
|
||||
|
||||
# Stabilize FPS
|
||||
clock.tick(60)
|
@ -1,61 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import wasm3
|
||||
import os, time, random, math
|
||||
import pygame
|
||||
|
||||
print("WebAssembly demo file provided by Ben Smith (binji)")
|
||||
print("Sources: https://github.com/binji/raw-wasm")
|
||||
|
||||
scriptpath = os.path.dirname(os.path.realpath(__file__))
|
||||
wasm_fn = os.path.join(scriptpath, "./wasm/fire.wasm")
|
||||
|
||||
# Prepare Wasm3 engine
|
||||
|
||||
env = wasm3.Environment()
|
||||
rt = env.new_runtime(1024)
|
||||
with open(wasm_fn, "rb") as f:
|
||||
mod = env.parse_module(f.read())
|
||||
rt.load(mod)
|
||||
mod.link_function("", "rand", "F()", random.random)
|
||||
|
||||
wasm_run = rt.find_function("run")
|
||||
mem = rt.get_memory(0)
|
||||
|
||||
# Map memory region to an RGBA image
|
||||
|
||||
img_base = 53760
|
||||
img_size = (320, 168)
|
||||
(img_w, img_h) = img_size
|
||||
region = mem[img_base : img_base + (img_w * img_h * 4)]
|
||||
img = pygame.image.frombuffer(region, img_size, "RGBA")
|
||||
|
||||
# Prepare PyGame
|
||||
|
||||
scr_size = (img_w*2, img_h*2)
|
||||
pygame.init()
|
||||
surface = pygame.display.set_mode(scr_size)
|
||||
pygame.display.set_caption("Wasm3 Doomfire")
|
||||
background = (255, 255, 255)
|
||||
|
||||
clock = pygame.time.Clock()
|
||||
|
||||
while True:
|
||||
# Process input
|
||||
for event in pygame.event.get():
|
||||
if (event.type == pygame.QUIT or
|
||||
(event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE)):
|
||||
pygame.quit()
|
||||
quit()
|
||||
|
||||
# Render next frame
|
||||
wasm_run()
|
||||
|
||||
# Image output
|
||||
img_scaled = pygame.transform.scale(img, scr_size)
|
||||
surface.fill(background)
|
||||
surface.blit(img_scaled, (0, 0))
|
||||
pygame.display.flip()
|
||||
|
||||
# Stabilize FPS
|
||||
clock.tick(60)
|
@ -1,86 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import wasm3
|
||||
import os, time, random, math
|
||||
import pygame
|
||||
|
||||
print("WebAssembly demo file provided by Ben Smith (binji)")
|
||||
print("Sources: https://github.com/binji/raw-wasm")
|
||||
|
||||
scriptpath = os.path.dirname(os.path.realpath(__file__))
|
||||
wasm_fn = os.path.join(scriptpath, "./wasm/maze.wasm")
|
||||
|
||||
def env_t(start):
|
||||
pass
|
||||
|
||||
# Prepare Wasm3 engine
|
||||
|
||||
env = wasm3.Environment()
|
||||
rt = env.new_runtime(1024)
|
||||
with open(wasm_fn, "rb") as f:
|
||||
mod = env.parse_module(f.read())
|
||||
rt.load(mod)
|
||||
mod.link_function("Math", "sin", "f(f)", math.sin)
|
||||
mod.link_function("Math", "random", "f()", random.random)
|
||||
mod.link_function("env", "t", "v(i)", env_t)
|
||||
|
||||
wasm_run = rt.find_function("run")
|
||||
mem = rt.get_memory(0)
|
||||
|
||||
# Map memory region to an RGBA image
|
||||
|
||||
img_base = 0x3000
|
||||
img_size = (320, 240)
|
||||
(img_w, img_h) = img_size
|
||||
region = mem[img_base : img_base + (img_w * img_h * 4)]
|
||||
img = pygame.image.frombuffer(region, img_size, "RGBA")
|
||||
|
||||
# Prepare PyGame
|
||||
|
||||
scr_size = (img_w*2, img_h*2)
|
||||
pygame.init()
|
||||
surface = pygame.display.set_mode(scr_size)
|
||||
pygame.display.set_caption("Wasm3 Maze")
|
||||
white = (255, 255, 255)
|
||||
|
||||
k_up = False
|
||||
k_down = False
|
||||
k_left = False
|
||||
k_right = False
|
||||
|
||||
clock = pygame.time.Clock()
|
||||
|
||||
while True:
|
||||
# Process input
|
||||
for event in pygame.event.get():
|
||||
if (event.type == pygame.QUIT or
|
||||
(event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE)):
|
||||
pygame.quit()
|
||||
quit()
|
||||
elif event.type == pygame.KEYDOWN or event.type == pygame.KEYUP:
|
||||
is_pressed = (event.type == pygame.KEYDOWN)
|
||||
if event.key == pygame.K_UP:
|
||||
k_up = is_pressed
|
||||
elif event.key == pygame.K_DOWN:
|
||||
k_down = is_pressed
|
||||
elif event.key == pygame.K_LEFT:
|
||||
k_left = is_pressed
|
||||
elif event.key == pygame.K_RIGHT:
|
||||
k_right = is_pressed
|
||||
|
||||
mem[0] = k_left
|
||||
mem[1] = k_right
|
||||
mem[2] = k_up
|
||||
mem[3] = k_down
|
||||
|
||||
# Render next frame
|
||||
wasm_run()
|
||||
|
||||
# Image output
|
||||
img_scaled = pygame.transform.scale(img, scr_size)
|
||||
surface.fill(white)
|
||||
surface.blit(img_scaled, (0, 0))
|
||||
pygame.display.flip()
|
||||
|
||||
# Stabilize FPS
|
||||
clock.tick(60)
|
@ -1,63 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import wasm3
|
||||
import os, time, random, math
|
||||
import pygame
|
||||
|
||||
print("WebAssembly demo file provided by Ben Smith (binji)")
|
||||
print("Sources: https://github.com/binji/raw-wasm")
|
||||
|
||||
scriptpath = os.path.dirname(os.path.realpath(__file__))
|
||||
wasm_fn = os.path.join(scriptpath, "./wasm/metaball.wasm")
|
||||
|
||||
# Prepare Wasm3 engine
|
||||
|
||||
env = wasm3.Environment()
|
||||
rt = env.new_runtime(1024)
|
||||
with open(wasm_fn, "rb") as f:
|
||||
mod = env.parse_module(f.read())
|
||||
rt.load(mod)
|
||||
mod.link_function("", "rand", "f()", random.random)
|
||||
wasm_blobs = rt.find_function("blobs")
|
||||
wasm_blobs(5)
|
||||
|
||||
wasm_run = rt.find_function("run")
|
||||
mem = rt.get_memory(0)
|
||||
|
||||
# Map memory region to an RGBA image
|
||||
|
||||
img_base = 1024
|
||||
img_size = (320, 200)
|
||||
(img_w, img_h) = img_size
|
||||
region = mem[img_base : img_base + (img_w * img_h * 4)]
|
||||
img = pygame.image.frombuffer(region, img_size, "RGBA")
|
||||
|
||||
# Prepare PyGame
|
||||
|
||||
scr_size = (img_w*2, img_h*2)
|
||||
pygame.init()
|
||||
surface = pygame.display.set_mode(scr_size)
|
||||
pygame.display.set_caption("Wasm3 Metaball")
|
||||
background = (0xd4, 0x19, 0x5d)
|
||||
|
||||
clock = pygame.time.Clock()
|
||||
|
||||
while True:
|
||||
# Process input
|
||||
for event in pygame.event.get():
|
||||
if (event.type == pygame.QUIT or
|
||||
(event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE)):
|
||||
pygame.quit()
|
||||
quit()
|
||||
|
||||
# Render next frame
|
||||
wasm_run()
|
||||
|
||||
# Image output
|
||||
img_scaled = pygame.transform.scale(img, scr_size)
|
||||
surface.fill(background)
|
||||
surface.blit(img_scaled, (0, 0))
|
||||
pygame.display.flip()
|
||||
|
||||
# Stabilize FPS
|
||||
clock.tick(30)
|
@ -1,64 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import wasm3
|
||||
import os, time, random, math
|
||||
import pygame
|
||||
|
||||
print("WebAssembly demo file provided by Ben Smith (binji)")
|
||||
print("Sources: https://github.com/binji/raw-wasm")
|
||||
|
||||
scriptpath = os.path.dirname(os.path.realpath(__file__))
|
||||
wasm_fn = os.path.join(scriptpath, "./wasm/ray.wasm")
|
||||
|
||||
# Prepare Wasm3 engine
|
||||
|
||||
env = wasm3.Environment()
|
||||
rt = env.new_runtime(1024)
|
||||
with open(wasm_fn, "rb") as f:
|
||||
mod = env.parse_module(f.read())
|
||||
rt.load(mod)
|
||||
mod.link_function("Math", "sin", "f(f)", math.sin)
|
||||
|
||||
wasm_run = rt.find_function("run")
|
||||
mem = rt.get_memory(0)
|
||||
|
||||
# Map memory region to an RGBA image
|
||||
|
||||
img_base = 1024
|
||||
img_size = (320, 200)
|
||||
(img_w, img_h) = img_size
|
||||
region = mem[img_base : img_base + (img_w * img_h * 4)]
|
||||
img = pygame.image.frombuffer(region, img_size, "RGBA")
|
||||
|
||||
# Prepare PyGame
|
||||
|
||||
scr_size = (img_w*2, img_h*2)
|
||||
pygame.init()
|
||||
surface = pygame.display.set_mode(scr_size)
|
||||
pygame.display.set_caption("Wasm3 Raytrace")
|
||||
background = (255, 255, 255)
|
||||
|
||||
clock = pygame.time.Clock()
|
||||
|
||||
t = 0
|
||||
|
||||
while True:
|
||||
# Process input
|
||||
for event in pygame.event.get():
|
||||
if (event.type == pygame.QUIT or
|
||||
(event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE)):
|
||||
pygame.quit()
|
||||
quit()
|
||||
|
||||
# Render next frame
|
||||
wasm_run(t)
|
||||
t += 50
|
||||
|
||||
# Image output
|
||||
img_scaled = pygame.transform.scale(img, scr_size)
|
||||
surface.fill(background)
|
||||
surface.blit(img_scaled, (0, 0))
|
||||
pygame.display.flip()
|
||||
|
||||
# Stabilize FPS
|
||||
clock.tick(30)
|
@ -1,74 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import wasm3
|
||||
import os, time, random, math
|
||||
import pygame
|
||||
|
||||
print("WebAssembly demo file provided by Ben Smith (binji)")
|
||||
print("Sources: https://github.com/binji/raw-wasm")
|
||||
|
||||
scriptpath = os.path.dirname(os.path.realpath(__file__))
|
||||
wasm_fn = os.path.join(scriptpath, "./wasm/snake.wasm")
|
||||
|
||||
# Prepare Wasm3 engine
|
||||
|
||||
env = wasm3.Environment()
|
||||
rt = env.new_runtime(1024)
|
||||
with open(wasm_fn, "rb") as f:
|
||||
mod = env.parse_module(f.read())
|
||||
rt.load(mod)
|
||||
mod.link_function("Math", "sin", "f(f)", math.sin)
|
||||
mod.link_function("Math", "random", "f()", random.random)
|
||||
|
||||
wasm_run = rt.find_function("run")
|
||||
mem = rt.get_memory(0)
|
||||
|
||||
# Map memory region to an RGBA image
|
||||
|
||||
img_base = 0x15000
|
||||
img_size = (240, 320)
|
||||
(img_w, img_h) = img_size
|
||||
region = mem[img_base : img_base + (img_w * img_h * 4)]
|
||||
img = pygame.image.frombuffer(region, img_size, "RGBA")
|
||||
|
||||
# Prepare PyGame
|
||||
|
||||
scr_size = (img_w*2, img_h*2)
|
||||
pygame.init()
|
||||
surface = pygame.display.set_mode(scr_size)
|
||||
pygame.display.set_caption("Wasm3 Snake")
|
||||
white = (255, 255, 255)
|
||||
|
||||
k_left = False
|
||||
k_right = False
|
||||
|
||||
clock = pygame.time.Clock()
|
||||
|
||||
while True:
|
||||
# Process input
|
||||
for event in pygame.event.get():
|
||||
if (event.type == pygame.QUIT or
|
||||
(event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE)):
|
||||
pygame.quit()
|
||||
quit()
|
||||
elif event.type == pygame.KEYDOWN or event.type == pygame.KEYUP:
|
||||
is_pressed = (event.type == pygame.KEYDOWN)
|
||||
if event.key == pygame.K_LEFT:
|
||||
k_left = is_pressed
|
||||
elif event.key == pygame.K_RIGHT:
|
||||
k_right = is_pressed
|
||||
|
||||
mem[0x2c0] = k_left
|
||||
mem[0x2c1] = k_right
|
||||
|
||||
# Render next frame
|
||||
wasm_run()
|
||||
|
||||
# Image output
|
||||
img_scaled = pygame.transform.scale(img, scr_size)
|
||||
surface.fill(white)
|
||||
surface.blit(img_scaled, (0, 0))
|
||||
pygame.display.flip()
|
||||
|
||||
# Stabilize FPS
|
||||
clock.tick(60)
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1 +0,0 @@
|
||||
../../source
|
@ -1,584 +0,0 @@
|
||||
#include "Python.h"
|
||||
|
||||
#include "wasm3.h"
|
||||
#include "m3_api_defs.h"
|
||||
|
||||
#define MAX_ARGS 32
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
IM3Environment e;
|
||||
} m3_environment;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
m3_environment *env;
|
||||
IM3Runtime r;
|
||||
} m3_runtime;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
m3_environment *env;
|
||||
IM3Module m;
|
||||
//bool is_gas_metered;
|
||||
int64_t total_gas;
|
||||
int64_t current_gas;
|
||||
} m3_module;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
IM3Function f;
|
||||
IM3Runtime r;
|
||||
} m3_function;
|
||||
|
||||
static PyObject *M3_Environment_Type;
|
||||
static PyObject *M3_Runtime_Type;
|
||||
static PyObject *M3_Module_Type;
|
||||
static PyObject *M3_Function_Type;
|
||||
|
||||
static m3_environment*
|
||||
newEnvironment(PyObject *arg)
|
||||
{
|
||||
m3_environment *self = PyObject_GC_New(m3_environment, (PyTypeObject*)M3_Environment_Type);
|
||||
if (!self) return NULL;
|
||||
self->e = m3_NewEnvironment();
|
||||
return self;
|
||||
}
|
||||
|
||||
static void
|
||||
delEnvironment(m3_environment *self)
|
||||
{
|
||||
m3_FreeEnvironment(self->e);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
formatError(PyObject *exception, IM3Runtime runtime, M3Result err)
|
||||
{
|
||||
M3ErrorInfo info;
|
||||
memset(&info, 0, sizeof(info));
|
||||
m3_GetErrorInfo (runtime, &info);
|
||||
if (strlen(info.message)) {
|
||||
PyErr_Format(exception, "%s (%s)", err, info.message);
|
||||
} else {
|
||||
PyErr_SetString(exception, err);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
put_arg_on_stack(u64 *s, M3ValueType type, PyObject *arg)
|
||||
{
|
||||
switch (type) {
|
||||
case c_m3Type_i32: *(i32*)(s) = PyLong_AsLong(arg); break;
|
||||
case c_m3Type_i64: *(i64*)(s) = PyLong_AsLongLong(arg); break;
|
||||
case c_m3Type_f32: *(f32*)(s) = PyFloat_AsDouble(arg); break;
|
||||
case c_m3Type_f64: *(f64*)(s) = PyFloat_AsDouble(arg); break;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
get_arg_from_stack(u64 *s, M3ValueType type)
|
||||
{
|
||||
switch (type) {
|
||||
case c_m3Type_i32: return PyLong_FromLong( *(i32*)s); break;
|
||||
case c_m3Type_i64: return PyLong_FromLongLong( *(i64*)s); break;
|
||||
case c_m3Type_f32: return PyFloat_FromDouble( *(f32*)s); break;
|
||||
case c_m3Type_f64: return PyFloat_FromDouble( *(f64*)s); break;
|
||||
default:
|
||||
return PyErr_Format(PyExc_TypeError, "unknown type %d", (int)type);
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
M3_Environment_new_runtime(m3_environment *env, PyObject *stack_size_bytes)
|
||||
{
|
||||
size_t n = PyLong_AsSize_t(stack_size_bytes);
|
||||
m3_runtime *self = PyObject_GC_New(m3_runtime, (PyTypeObject*)M3_Runtime_Type);
|
||||
if (!self) return NULL;
|
||||
Py_INCREF(env);
|
||||
self->env = env;
|
||||
self->r = m3_NewRuntime(env->e, n, NULL);
|
||||
return self;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
M3_Environment_parse_module(m3_environment *env, PyObject *bytes)
|
||||
{
|
||||
Py_ssize_t size;
|
||||
char *data;
|
||||
PyBytes_AsStringAndSize(bytes, &data, &size);
|
||||
IM3Module m;
|
||||
M3Result err = m3_ParseModule(env->e, &m, data, size);
|
||||
if (err) {
|
||||
PyErr_SetString(PyExc_RuntimeError, err);
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(bytes);
|
||||
|
||||
m3_module *self = PyObject_GC_New(m3_module, (PyTypeObject*)M3_Module_Type);
|
||||
if (!self) return NULL;
|
||||
Py_INCREF(env);
|
||||
self->env = env;
|
||||
self->m = m;
|
||||
self->total_gas = self->current_gas = 0;
|
||||
return self;
|
||||
}
|
||||
|
||||
static PyMethodDef M3_Environment_methods[] = {
|
||||
{"new_runtime", (PyCFunction)M3_Environment_new_runtime, METH_O,
|
||||
PyDoc_STR("new_runtime(stack_size_bytes) -> Runtime")},
|
||||
{"parse_module", (PyCFunction)M3_Environment_parse_module, METH_O,
|
||||
PyDoc_STR("new_runtime(bytes) -> Module")},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static PyType_Slot M3_Environment_Type_slots[] = {
|
||||
{Py_tp_doc, "The wasm3.Environment type"},
|
||||
{Py_tp_finalize, delEnvironment},
|
||||
{Py_tp_new, newEnvironment},
|
||||
{Py_tp_methods, M3_Environment_methods},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
M3_Runtime_load(m3_runtime *runtime, PyObject *arg)
|
||||
{
|
||||
m3_module *module = (m3_module *)arg;
|
||||
M3Result err = m3_LoadModule(runtime->r, module->m);
|
||||
if (err) {
|
||||
return formatError(PyExc_RuntimeError, runtime->r, err);
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
M3_Runtime_find_function(m3_runtime *runtime, PyObject *name)
|
||||
{
|
||||
IM3Function func = NULL;
|
||||
M3Result err = m3_FindFunction(&func, runtime->r, PyUnicode_AsUTF8(name));
|
||||
if (err) {
|
||||
return formatError(PyExc_RuntimeError, runtime->r, err);
|
||||
}
|
||||
m3_function *self = PyObject_GC_New(m3_function, (PyTypeObject*)M3_Function_Type);
|
||||
if (!self) return NULL;
|
||||
self->f = func;
|
||||
self->r = runtime->r;
|
||||
return self;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
M3_Runtime_get_memory(m3_runtime *runtime, PyObject *index)
|
||||
{
|
||||
Py_buffer* pybuff;
|
||||
uint32_t size = 0;
|
||||
uint8_t *mem = m3_GetMemory(runtime->r, &size, PyLong_AsLong(index));
|
||||
if (!mem)
|
||||
Py_RETURN_NONE;
|
||||
|
||||
pybuff = (Py_buffer*) PyMem_Malloc(sizeof(Py_buffer));
|
||||
PyBuffer_FillInfo(pybuff, (PyObject *)runtime, mem, size, 0, PyBUF_WRITABLE);
|
||||
return PyMemoryView_FromBuffer(pybuff);
|
||||
}
|
||||
|
||||
static PyMethodDef M3_Runtime_methods[] = {
|
||||
{"load", (PyCFunction)M3_Runtime_load, METH_O,
|
||||
PyDoc_STR("load(module) -> None")},
|
||||
{"find_function", (PyCFunction)M3_Runtime_find_function, METH_O,
|
||||
PyDoc_STR("find_function(name) -> Function")},
|
||||
{"get_memory", (PyCFunction)M3_Runtime_get_memory, METH_O,
|
||||
PyDoc_STR("get_memory(index) -> memoryview")},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static PyType_Slot M3_Runtime_Type_slots[] = {
|
||||
{Py_tp_doc, "The wasm3.Runtime type"},
|
||||
// {Py_tp_finalize, delRuntime},
|
||||
// {Py_tp_new, newRuntime},
|
||||
{Py_tp_methods, M3_Runtime_methods},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
Module_name(m3_module *self, void * closure)
|
||||
{
|
||||
return PyUnicode_FromString(m3_GetModuleName(self->m));
|
||||
}
|
||||
|
||||
static int
|
||||
Module_setGasLimit(m3_module *self, PyObject *value, void * closure)
|
||||
{
|
||||
self->total_gas = PyFloat_AsDouble(value)*10000.0;
|
||||
self->current_gas = self->total_gas;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
Module_getGasLimit(m3_module *self, void * closure)
|
||||
{
|
||||
return PyFloat_FromDouble((double)(self->total_gas)/10000.0);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
Module_getGasUsed(m3_module *self, void * closure)
|
||||
{
|
||||
return PyFloat_FromDouble((double)(self->total_gas - self->current_gas)/10000.0);
|
||||
}
|
||||
|
||||
m3ApiRawFunction(metering_usegas)
|
||||
{
|
||||
m3ApiGetArg (int32_t, gas)
|
||||
|
||||
m3_module *mod = (m3_module *)(_ctx->userdata);
|
||||
|
||||
mod->current_gas -= gas;
|
||||
|
||||
if (UNLIKELY(mod->current_gas < 0)) {
|
||||
m3ApiTrap("[trap] Out of gas");
|
||||
}
|
||||
m3ApiSuccess();
|
||||
}
|
||||
|
||||
static const char* trapException = "function raised exception";
|
||||
|
||||
m3ApiRawFunction(CallImport)
|
||||
{
|
||||
PyObject *pFunc = (PyObject *)(_ctx->userdata);
|
||||
IM3Function f = _ctx->function;
|
||||
int nArgs = m3_GetArgCount(f);
|
||||
int nRets = m3_GetRetCount(f);
|
||||
PyObject *pArgs = PyTuple_New(nArgs);
|
||||
if (!pArgs) {
|
||||
m3ApiTrap("python call: args not allocated");
|
||||
}
|
||||
|
||||
for (Py_ssize_t i = 0; i < nArgs; ++i) {
|
||||
PyObject *arg = get_arg_from_stack(&_sp[i], m3_GetArgType(f, i));
|
||||
PyTuple_SET_ITEM(pArgs, i, arg);
|
||||
}
|
||||
|
||||
PyObject * pRets = PyObject_CallObject(pFunc, pArgs);
|
||||
if (!pRets) m3ApiTrap(trapException);
|
||||
|
||||
if (PyTuple_Check(pRets)) {
|
||||
if (PyTuple_GET_SIZE(pRets) != nRets) {
|
||||
m3ApiTrap("python call: return tuple length mismatch");
|
||||
}
|
||||
for (Py_ssize_t i = 0; i < nRets; ++i) {
|
||||
PyObject *ret = PyTuple_GET_ITEM(pRets, i);
|
||||
if (!ret) m3ApiTrap("python call: return type invalid");
|
||||
put_arg_on_stack(&_sp[i], m3_GetRetType(f, i), ret);
|
||||
}
|
||||
} else {
|
||||
if (nRets == 0) {
|
||||
if (pRets != Py_None) {
|
||||
//m3ApiTrap("python call: return value ignored");
|
||||
}
|
||||
} else if (nRets == 1) {
|
||||
if (pRets == Py_None) {
|
||||
m3ApiTrap("python call: should return a value");
|
||||
}
|
||||
put_arg_on_stack(&_sp[0], m3_GetRetType(f, 0), pRets);
|
||||
} else {
|
||||
m3ApiTrap("python call: should return a tuple");
|
||||
}
|
||||
}
|
||||
m3ApiSuccess();
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
M3_Module_link_function(m3_module *self, PyObject *args)
|
||||
{
|
||||
if (PyTuple_Size(args) != 4) {
|
||||
PyErr_SetString(PyExc_TypeError, "link_function takes 4 arguments");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *mod_name = PyTuple_GET_ITEM(args, 0);
|
||||
PyObject *func_name = PyTuple_GET_ITEM(args, 1);
|
||||
PyObject *func_sig = PyTuple_GET_ITEM(args, 2);
|
||||
PyObject *pFunc = PyTuple_GET_ITEM(args, 3);
|
||||
if (!PyCallable_Check(pFunc)) {
|
||||
PyErr_SetString(PyExc_TypeError, "function should be a callable object");
|
||||
return NULL;
|
||||
}
|
||||
M3Result err = m3_LinkRawFunctionEx (self->m, PyUnicode_AsUTF8(mod_name), PyUnicode_AsUTF8(func_name),
|
||||
PyUnicode_AsUTF8(func_sig), CallImport, pFunc);
|
||||
if (err && err != m3Err_functionLookupFailed) {
|
||||
return formatError(PyExc_RuntimeError, m3_GetModuleRuntime(self->m), err);
|
||||
}
|
||||
|
||||
err = m3_LinkRawFunctionEx (self->m, "metering", "usegas", "v(i)", &metering_usegas, self);
|
||||
/*if (!err) {
|
||||
self->is_gas_metered = true;
|
||||
}*/
|
||||
if (err && err != m3Err_functionLookupFailed) {
|
||||
return formatError(PyExc_RuntimeError, m3_GetModuleRuntime(self->m), err);
|
||||
}
|
||||
|
||||
Py_INCREF(pFunc);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyGetSetDef M3_Module_properties[] = {
|
||||
{"name", (getter) Module_name, NULL, "module name", NULL},
|
||||
{"gasLimit", (getter) Module_getGasLimit, (setter) Module_setGasLimit, "gas limit for metered modules", NULL},
|
||||
{"gasUsed", (getter) Module_getGasUsed, NULL, "gas used", NULL},
|
||||
{0},
|
||||
};
|
||||
|
||||
static PyMethodDef M3_Module_methods[] = {
|
||||
{"link_function", (PyCFunction)M3_Module_link_function, METH_VARARGS,
|
||||
PyDoc_STR("link_function(module, name, signature, function)")},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static PyType_Slot M3_Module_Type_slots[] = {
|
||||
{Py_tp_doc, "The wasm3.Module type"},
|
||||
// {Py_tp_finalize, delModule},
|
||||
// {Py_tp_new, newModule},
|
||||
{Py_tp_methods, M3_Module_methods},
|
||||
{Py_tp_getset, M3_Module_properties},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
get_result_from_stack(m3_function *func)
|
||||
{
|
||||
int nRets = m3_GetRetCount(func->f);
|
||||
if (nRets <= 0) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
if (nRets > 1) {
|
||||
PyErr_SetString(PyExc_NotImplementedError, "multi-value not supported yet");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (nRets > MAX_ARGS) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "too many rets");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uint64_t valbuff[MAX_ARGS];
|
||||
static const void* valptrs[MAX_ARGS];
|
||||
memset(valbuff, 0, sizeof(valbuff));
|
||||
memset(valptrs, 0, sizeof(valptrs));
|
||||
|
||||
for (int i = 0; i < nRets; i++) {
|
||||
valptrs[i] = &valbuff[i];
|
||||
}
|
||||
M3Result err = m3_GetResults (func->f, nRets, valptrs);
|
||||
if (err) {
|
||||
return formatError(PyExc_RuntimeError, func->r, err);
|
||||
}
|
||||
|
||||
return get_arg_from_stack(valptrs[0], m3_GetRetType(func->f, 0));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
M3_Function_call_argv(m3_function *func, PyObject *args)
|
||||
{
|
||||
Py_ssize_t size = PyTuple_GET_SIZE(args);
|
||||
const char* argv[MAX_ARGS];
|
||||
for(Py_ssize_t i = 0; i< size;++i) {
|
||||
argv[i] = PyUnicode_AsUTF8(PyTuple_GET_ITEM(args, i));
|
||||
}
|
||||
M3Result err = m3_CallArgv(func->f, size, argv);
|
||||
if (err == trapException) {
|
||||
return NULL;
|
||||
} else if (err) {
|
||||
return formatError(PyExc_RuntimeError, func->r, err);
|
||||
}
|
||||
|
||||
return get_result_from_stack(func);
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
M3_Function_call(m3_function *self, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
u32 i;
|
||||
IM3Function f = self->f;
|
||||
|
||||
int nArgs = m3_GetArgCount(f);
|
||||
|
||||
if (nArgs > MAX_ARGS) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "too many args");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uint64_t valbuff[MAX_ARGS];
|
||||
static const void* valptrs[MAX_ARGS];
|
||||
memset(valbuff, 0, sizeof(args));
|
||||
memset(valptrs, 0, sizeof(valptrs));
|
||||
|
||||
for (int i = 0; i < nArgs; i++) {
|
||||
u64* s = &valbuff[i];
|
||||
valptrs[i] = s;
|
||||
put_arg_on_stack(s, m3_GetArgType(f, i), PyTuple_GET_ITEM(args, i));
|
||||
}
|
||||
|
||||
M3Result err = m3_Call (f, nArgs, valptrs);
|
||||
if (err == trapException) {
|
||||
return NULL;
|
||||
} else if (err) {
|
||||
return formatError(PyExc_RuntimeError, self->r, err);
|
||||
}
|
||||
|
||||
return get_result_from_stack(self);
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
Function_name(m3_function *self, void * closure)
|
||||
{
|
||||
return PyUnicode_FromString(m3_GetFunctionName(self->f));
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
Function_num_args(m3_function *self, void * closure)
|
||||
{
|
||||
return PyLong_FromLong(m3_GetArgCount(self->f));
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
Function_num_rets(m3_function *self, void * closure)
|
||||
{
|
||||
return PyLong_FromLong(m3_GetRetCount(self->f));
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
Function_arg_types(m3_function *self, void * closure)
|
||||
{
|
||||
Py_ssize_t nArgs = m3_GetArgCount(self->f);
|
||||
PyObject *ret = PyTuple_New(nArgs);
|
||||
if (ret) {
|
||||
Py_ssize_t i;
|
||||
for (i = 0; i < nArgs; ++i) {
|
||||
PyTuple_SET_ITEM(ret, i, PyLong_FromLong(m3_GetArgType(self->f, i)));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
Function_ret_types(m3_function *self, void * closure)
|
||||
{
|
||||
Py_ssize_t nRets = m3_GetRetCount(self->f);
|
||||
PyObject *ret = PyTuple_New(nRets);
|
||||
if (ret) {
|
||||
Py_ssize_t i;
|
||||
for (i = 0; i < nRets; ++i) {
|
||||
PyTuple_SET_ITEM(ret, i, PyLong_FromLong(m3_GetRetType(self->f, i)));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static PyGetSetDef M3_Function_properties[] = {
|
||||
{"name", (getter) Function_name, NULL, "function name", NULL },
|
||||
{"num_args", (getter) Function_num_args, NULL, "number of args", NULL },
|
||||
{"num_rets", (getter) Function_num_rets, NULL, "number of rets", NULL },
|
||||
{"arg_types", (getter) Function_arg_types, NULL, "types of args", NULL },
|
||||
{"ret_types", (getter) Function_ret_types, NULL, "types of rets", NULL },
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
static PyMethodDef M3_Function_methods[] = {
|
||||
{"call_argv", (PyCFunction)M3_Function_call_argv, METH_VARARGS,
|
||||
PyDoc_STR("call_argv(args...) -> result")},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
static PyType_Slot M3_Function_Type_slots[] = {
|
||||
{Py_tp_doc, "The wasm3.Function type"},
|
||||
// {Py_tp_finalize, delFunction},
|
||||
// {Py_tp_new, newFunction},
|
||||
{Py_tp_call, M3_Function_call},
|
||||
{Py_tp_methods, M3_Function_methods},
|
||||
{Py_tp_getset, M3_Function_properties},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
static PyType_Spec M3_Environment_Type_spec = {
|
||||
"wasm3.Environment",
|
||||
sizeof(m3_environment),
|
||||
0,
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
|
||||
M3_Environment_Type_slots
|
||||
};
|
||||
|
||||
static PyType_Spec M3_Runtime_Type_spec = {
|
||||
"wasm3.Runtime",
|
||||
sizeof(m3_runtime),
|
||||
0,
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
|
||||
M3_Runtime_Type_slots
|
||||
};
|
||||
|
||||
static PyType_Spec M3_Module_Type_spec = {
|
||||
"wasm3.Module",
|
||||
sizeof(m3_module),
|
||||
0,
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
|
||||
M3_Module_Type_slots
|
||||
};
|
||||
|
||||
static PyType_Spec M3_Function_Type_spec = {
|
||||
"wasm3.Function",
|
||||
sizeof(m3_function),
|
||||
0,
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
|
||||
M3_Function_Type_slots
|
||||
};
|
||||
|
||||
static int
|
||||
m3_modexec(PyObject *m)
|
||||
{
|
||||
M3_Environment_Type = PyType_FromSpec(&M3_Environment_Type_spec);
|
||||
if (M3_Environment_Type == NULL)
|
||||
goto fail;
|
||||
M3_Runtime_Type = PyType_FromSpec(&M3_Runtime_Type_spec);
|
||||
if (M3_Runtime_Type == NULL)
|
||||
goto fail;
|
||||
M3_Module_Type = PyType_FromSpec(&M3_Module_Type_spec);
|
||||
if (M3_Module_Type == NULL)
|
||||
goto fail;
|
||||
M3_Function_Type = PyType_FromSpec(&M3_Function_Type_spec);
|
||||
if (M3_Function_Type == NULL)
|
||||
goto fail;
|
||||
PyModule_AddStringMacro(m, M3_VERSION);
|
||||
PyModule_AddObject(m, "Environment", M3_Environment_Type);
|
||||
PyModule_AddObject(m, "Runtime", M3_Runtime_Type);
|
||||
PyModule_AddObject(m, "Module", M3_Module_Type);
|
||||
PyModule_AddObject(m, "Function", M3_Function_Type);
|
||||
return 0;
|
||||
fail:
|
||||
Py_XDECREF(m);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static PyModuleDef_Slot m3_slots[] = {
|
||||
{Py_mod_exec, m3_modexec},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(m3_doc,
|
||||
"wasm3 python bindings");
|
||||
|
||||
static struct PyModuleDef m3module = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"wasm3",
|
||||
m3_doc,
|
||||
0,
|
||||
0, // methods
|
||||
m3_slots,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC
|
||||
PyInit_wasm3(void)
|
||||
{
|
||||
return PyModuleDef_Init(&m3module);
|
||||
}
|
||||
|
@ -1,37 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from setuptools import setup
|
||||
from distutils.core import Extension
|
||||
from glob import glob
|
||||
|
||||
SOURCES = glob('m3/*.c') + ['m3module.c']
|
||||
|
||||
setup(
|
||||
name = "pywasm3",
|
||||
version = "0.4.9",
|
||||
description = "The fastest WebAssembly interpreter",
|
||||
platforms = "any",
|
||||
url = "https://github.com/wasm3/wasm3",
|
||||
license = "MIT",
|
||||
author = "Volodymyr Shymanskyy",
|
||||
author_email = "vshymanskyi@gmail.com",
|
||||
|
||||
long_description = open("README.md").read(),
|
||||
long_description_content_type = "text/markdown",
|
||||
|
||||
ext_modules=[
|
||||
Extension('wasm3', sources=SOURCES, include_dirs=['m3'],
|
||||
extra_compile_args=['-g0', '-O3', '-march=native',
|
||||
'-fomit-frame-pointer', '-fno-stack-check', '-fno-stack-protector',
|
||||
'-DDEBUG', '-DNASSERTS'])
|
||||
],
|
||||
|
||||
classifiers = [
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
"Development Status :: 4 - Beta",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Operating System :: POSIX :: Linux",
|
||||
"Operating System :: Microsoft :: Windows",
|
||||
"Operating System :: MacOS :: MacOS X"
|
||||
]
|
||||
)
|
@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Build using:
|
||||
* emcc dyn_callback.c -Os -s WASM=1 -s SIDE_MODULE=1 -o dyn_callback.wasm
|
||||
*/
|
||||
|
||||
typedef int (*fptr_type)(int x, int y);
|
||||
|
||||
extern void pass_fptr(fptr_type fptr);
|
||||
|
||||
static int callback_add(int x, int y)
|
||||
{
|
||||
return x+y;
|
||||
}
|
||||
|
||||
static int callback_mul(int x, int y)
|
||||
{
|
||||
return x*y;
|
||||
}
|
||||
|
||||
void run_test()
|
||||
{
|
||||
pass_fptr(callback_add);
|
||||
pass_fptr(callback_mul);
|
||||
}
|
@ -1,214 +0,0 @@
|
||||
import wasm3 as m3
|
||||
import pytest
|
||||
|
||||
import tempfile, subprocess
|
||||
|
||||
def wat2wasm(wat):
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
fn_in = d + "/input.wat"
|
||||
fn_out = d + "/output.wasm"
|
||||
with open(fn_in, "wb") as f:
|
||||
f.write(wat.encode('utf8'))
|
||||
subprocess.run(["wat2wasm", "--enable-all", "-o", fn_out, fn_in], check=True)
|
||||
with open(fn_out, "rb") as f:
|
||||
return f.read()
|
||||
|
||||
FIB64_WASM = wat2wasm("""
|
||||
(module
|
||||
(func $fib2 (param $n i64) (param $a i64) (param $b i64) (result i64)
|
||||
(if (result i64)
|
||||
(i64.eqz (get_local $n))
|
||||
(then (get_local $a))
|
||||
(else (return_call $fib2 (i64.sub (get_local $n)
|
||||
(i64.const 1))
|
||||
(get_local $b)
|
||||
(i64.add (get_local $a)
|
||||
(get_local $b))))))
|
||||
|
||||
(func $fib (export "fib") (param i64) (result i64)
|
||||
(return_call $fib2 (get_local 0)
|
||||
(i64.const 0) ;; seed value $a
|
||||
(i64.const 1))) ;; seed value $b
|
||||
)
|
||||
""")
|
||||
|
||||
CALLBACK_WASM = wat2wasm("""
|
||||
(module
|
||||
(type (;0;) (func (param i32 i32) (result i32)))
|
||||
(func $i (import "env" "callback") (type 0))
|
||||
(func (export "run_callback") (type 0)
|
||||
local.get 0
|
||||
local.get 1
|
||||
call $i)
|
||||
)
|
||||
""")
|
||||
|
||||
DYN_CALLBACK_WASM = wat2wasm("""
|
||||
(module
|
||||
(type $t0 (func (param i32 i32) (result i32)))
|
||||
(type $t1 (func))
|
||||
(type $t2 (func (param i32)))
|
||||
(type $t3 (func (param i32 i32 i32) (result i32)))
|
||||
(import "env" "pass_fptr" (func $env.pass_fptr (type $t2)))
|
||||
(import "env" "__table_base" (global $env.__table_base i32))
|
||||
(func $run_test (export "run_test") (type $t1)
|
||||
global.get $env.__table_base
|
||||
call $env.pass_fptr
|
||||
global.get $env.__table_base
|
||||
i32.const 1
|
||||
i32.add
|
||||
call $env.pass_fptr)
|
||||
(func $f2 (type $t0) (param $p0 i32) (param $p1 i32) (result i32)
|
||||
local.get $p0
|
||||
local.get $p1
|
||||
i32.add)
|
||||
(func $f3 (type $t0) (param $p0 i32) (param $p1 i32) (result i32)
|
||||
local.get $p0
|
||||
local.get $p1
|
||||
i32.mul)
|
||||
(func $test (export "call_pass_fptr") (type $t2) (param $p0 i32)
|
||||
local.get $p0
|
||||
call $env.pass_fptr
|
||||
)
|
||||
(func $dynCall_iii (export "dynCall_iii") (type $t3) (param $p0 i32) (param $p1 i32) (param $p2 i32) (result i32)
|
||||
local.get $p1
|
||||
local.get $p2
|
||||
local.get $p0
|
||||
call_indirect $table (type $t0))
|
||||
(table $table (export "table") 2 funcref)
|
||||
(elem (global.get $env.__table_base) func $f2 $f3))
|
||||
""")
|
||||
|
||||
|
||||
ADD_WASM = wat2wasm("""
|
||||
(module
|
||||
(func (export "add") (param i64 i64) (result i64)
|
||||
local.get 0
|
||||
local.get 1
|
||||
i64.add
|
||||
return)
|
||||
)
|
||||
""")
|
||||
|
||||
|
||||
def test_classes():
|
||||
assert isinstance(m3.Environment, type)
|
||||
assert isinstance(m3.Runtime, type)
|
||||
assert isinstance(m3.Module, type)
|
||||
assert isinstance(m3.Function, type)
|
||||
|
||||
def test_callback():
|
||||
env = m3.Environment()
|
||||
rt = env.new_runtime(1024)
|
||||
mod = env.parse_module(CALLBACK_WASM)
|
||||
rt.load(mod)
|
||||
mem = rt.get_memory(0)
|
||||
|
||||
def func(x, y):
|
||||
assert x == 123
|
||||
assert y == 456
|
||||
return x*y
|
||||
mod.link_function("env", "callback", "i(ii)", func)
|
||||
run_callback = rt.find_function("run_callback")
|
||||
assert run_callback(123, 456) == 123*456
|
||||
|
||||
def test_callback_member():
|
||||
class WasmRunner:
|
||||
def __init__(self, wasm):
|
||||
self.env = m3.Environment()
|
||||
self.rt = self.env.new_runtime(1024)
|
||||
self.mod = self.env.parse_module(wasm)
|
||||
self.rt.load(self.mod)
|
||||
self.mem = self.rt.get_memory(0)
|
||||
self.mod.link_function("env", "callback", "i(ii)", self.func)
|
||||
self.run_callback = self.rt.find_function("run_callback")
|
||||
|
||||
def func(self, x, y):
|
||||
assert x == 987
|
||||
assert y == 654
|
||||
return x+y
|
||||
|
||||
inst = WasmRunner(CALLBACK_WASM)
|
||||
assert inst.run_callback(987, 654) == 987+654
|
||||
|
||||
def test_dynamic_callback():
|
||||
env = m3.Environment()
|
||||
rt = env.new_runtime(1024)
|
||||
mod = env.parse_module(DYN_CALLBACK_WASM)
|
||||
rt.load(mod)
|
||||
dynCall_iii = rt.find_function("dynCall_iii")
|
||||
|
||||
def pass_fptr(fptr):
|
||||
if fptr == 0:
|
||||
assert dynCall_iii(fptr, 12, 34) == 46
|
||||
elif fptr == 1:
|
||||
# TODO: call by table index directly here
|
||||
assert dynCall_iii(fptr, 12, 34) == 408
|
||||
else:
|
||||
raise Exception("Strange function ptr")
|
||||
|
||||
mod.link_function("env", "pass_fptr", "v(i)", pass_fptr)
|
||||
|
||||
# Indirect calls
|
||||
assert dynCall_iii(0, 12, 34) == 46
|
||||
assert dynCall_iii(1, 12, 34) == 408
|
||||
|
||||
# Recursive exported function call (single calls)
|
||||
call_pass_fptr = rt.find_function("call_pass_fptr")
|
||||
base = 0
|
||||
call_pass_fptr(base+0)
|
||||
call_pass_fptr(base+1)
|
||||
|
||||
# Recursive exported function call (multiple calls)
|
||||
rt.find_function("run_test")()
|
||||
|
||||
def test_m3(capfd):
|
||||
env = m3.Environment()
|
||||
rt = env.new_runtime(1024)
|
||||
assert isinstance(rt, m3.Runtime)
|
||||
mod = env.parse_module(FIB64_WASM)
|
||||
assert isinstance(mod, m3.Module)
|
||||
assert mod.name == '.unnamed'
|
||||
rt.load(mod)
|
||||
assert rt.get_memory(0) is None # XXX
|
||||
# rt.print_info()
|
||||
# assert capfd.readouterr().out == """
|
||||
# -- m3 runtime -------------------------------------------------
|
||||
# stack-size: 1024
|
||||
#
|
||||
# module [0] name: '.unnamed'; funcs: 1
|
||||
# ----------------------------------------------------------------
|
||||
# """
|
||||
with pytest.raises(RuntimeError):
|
||||
rt.find_function('not_existing')
|
||||
|
||||
func = rt.find_function('fib')
|
||||
assert isinstance(func, m3.Function)
|
||||
assert func.call_argv('5') == 5
|
||||
assert func.call_argv('10') == 55
|
||||
assert func.name == 'fib'
|
||||
assert func.num_args == 1
|
||||
assert func.num_rets == 1
|
||||
assert func.arg_types == (2,)
|
||||
assert func.ret_types == (2,)
|
||||
assert func(0) == 0
|
||||
assert func(1) == 1
|
||||
rt.load(env.parse_module(ADD_WASM))
|
||||
add = rt.find_function('add')
|
||||
assert add(2, 3) == 5
|
||||
|
||||
|
||||
def call_function(wasm, func, *args):
|
||||
env = m3.Environment()
|
||||
rt = env.new_runtime(4096)
|
||||
mod = env.parse_module(wasm)
|
||||
rt.load(mod)
|
||||
f = rt.find_function(func)
|
||||
return f.call_argv(*args)
|
||||
|
||||
def test_fib64():
|
||||
assert call_function(FIB64_WASM, 'fib', '5') == 5
|
||||
assert call_function(FIB64_WASM, 'fib', '10') == 55
|
||||
# TODO: Fails on 3.6, 3.7 ?
|
||||
#assert call_function(FIB64_WASM, 'fib', '90') == 2880067194370816120
|
||||
|
Loading…
Reference in new issue