Skip to main content

printf function for Python Web Assembly runtime

Project description

printf function for Python Web Assembly runtime

THis project is intended as a small helper package for running Web Assembly files generated by c4wa compiler in Python. However, it could be used with any Web Assembly project provided that variable arguments calling convention defined in c4wa spec is followed.

Consider the following WAT file, with comments (save it as file add.wat):

(module
  ;; function printf (imported): int, int -> void
  (import "c4wa" "printf" (func $printf (param i32) (param i32)))
  ;; memory (exported)
  (memory (export "memory") 1)
  ;; "%d + %d = %d\n" is written at address 1024
  (data (i32.const 1024) "%d + %d = %d\0A\00")
  ;; function add (exported): int, int -> void
  (func $add (export "add") (param $a i32) (param $b i32)
    ;; memory[0-7] = $a
    (i64.store (i32.const 0) (i64.extend_i32_s (get_local $a)))
    ;; memory[8-15] = $b
    (i64.store (i32.const 8) (i64.extend_i32_s (get_local $b)))
    ;; memory[16-23] = $a + $b
    (i64.store (i32.const 16) (i64.extend_i32_s (i32.add (get_local $a) (get_local $b))))
    ;; printf(1024, 0)
    (call $printf (i32.const 1024) (i32.const 0))))

It exports function add, linear memory as memory and imports function printf, which expects two i32 arguments.

To run it using wasmer, we can use the following Python script (save it as file add.py:

import sys
from wasm_import import sprintf

def main (num1 : int, num2 : int) :
    from wasmer import engine, Store, Module, Instance, Function, FunctionType, Type, ImportObject
    from wasmer_compiler_llvm import Compiler
    store = Store(engine.Native(Compiler))

    module = Module(store, open("add.wat", 'r').read())
    import_object : ImportObject = ImportObject()

    def printf(p_fmt, offset):
        mem = instance.exports.memory.uint8_view()
        res = sprintf(p_fmt, mem, offset)
        print(res, end='')

    import_object.register("c4wa", {"printf" : Function(store, printf,
                                    FunctionType(params=[Type.I32, Type.I32], results=[]))})

    instance = Instance(module, import_object)
    instance.exports.add(num1, num2)


if __name__ == "__main__" :
    if len(sys.argv) != 3 :
        print(f"USAGE: {sys.argv[0]} <num 1> <num 2>")
        exit(0)
    main(int(sys.argv[1]), int(sys.argv[2]))

Then install wasmer packages and execute:

python3 -m pip install --upgrade wasmer wasmer_compiler_llvm
python3 add.py 13 17
# 13 + 17 = 30

To use wasmtime instead, replace main function above with this:

def main (num1 : int, num2 : int) :
    from wasmtime import Store, Module, Instance, Func, FuncType, ValType
    store = Store()

    module = Module.from_file(store.engine, "add.wat")

    def printf(p_fmt, offset):
        mem = instance.exports(store)["memory"].data_ptr(store)
        res = sprintf(p_fmt, mem, offset)
        print(res, end='')

    instance = Instance(store, module, [Func(store, FuncType([ValType.i32(), ValType.i32()], []), printf)])
    instance.exports(store)["add"](store, num1, num2)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

wasm-import-0.1.1.tar.gz (10.1 kB view hashes)

Uploaded Source

Built Distribution

wasm_import-0.1.1-py3-none-any.whl (10.6 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page