wasmer.wasmer
Wasmer Python API
A complete and mature WebAssembly runtime for Python based on Wasmer.
Features:
- Easy to use: The
wasmer
API mimics the standard WebAssembly API, - Fast:
wasmer
executes the WebAssembly modules as fast as possible, close to native speed, - Safe: All calls to WebAssembly will be fast, but more importantly, completely safe and sandboxed.
Example
The very basic example is the following:
from wasmer import Store, Module, Instance
# Create a store, which holds the engine, the compiler etc.
store = Store()
# Let's assume we don't have WebAssembly bytes at hand. We will
# write WebAssembly manually.
module = Module(
store,
"""
(module
(type (func (param i32 i32) (result i32)))
(func (type 0)
local.get 0
local.get 1
i32.add)
(export "sum" (func 0)))
"""
)
# Instantiates the module.
instance = Instance(module)
# Now, let's execute the `sum` function.
assert instance.exports.sum(1, 2) == 3
That's it. Now explore the API! Some pointers for the adventurers:
- The basic elements are
Module
andInstance
, - Exports of an instance are represented by the
Exports
object, - Maybe your module needs to import
Function
,Memory
,Global
orTable
? Well, there is the Pythondict
for that! - It is possible to read and write
Memory
data with the Python buffer protocol withBuffer
.
Have fun!
Translate WebAssembly text source to WebAssembly binary format.
Example
from wasmer import wat2wasm
assert wat2wasm('(module)') == b'\x00asm\x01\x00\x00\x00'
Disassemble WebAssembly binary to WebAssembly text format.
Example
from wasmer import wasm2wat
assert wasm2wat(b'\x00asm\x01\x00\x00\x00') == '(module)'
Represents all the exports of an instance. It is built by
Instance.exports
.
Exports can be of kind Function
, Global
, Table
, or Memory
.
The Exports
class implement the Iterator
Protocol. Please see
the ExportsIterator
class.
Example
from wasmer import Store, Module, Instance, Exports, Function, Global, Table, Memory
module = Module(
Store(),
"""
(module
(func (export "func") (param i32 i64))
(global (export "glob") i32 (i32.const 7))
(table (export "tab") 0 funcref)
(memory (export "mem") 1))
"""
)
instance = Instance(module)
exports = instance.exports
assert isinstance(exports, Exports)
assert isinstance(exports.func, Function)
assert isinstance(exports.glob, Global)
assert isinstance(exports.tab, Table)
assert isinstance(exports.mem, Memory)
Iterator over all the exports of an Instance
.
Example
from wasmer import Store, Module, Instance, Exports, Function, Global, Table, Memory
module = Module(
Store(),
"""
(module
(func (export "func") (param i32 i64))
(global (export "glob") i32 (i32.const 7))
(table (export "tab") 0 funcref)
(memory (export "mem") 1))
"""
)
instance = Instance(module)
assert [name for (name, export) in instance.exports] == ["func", "glob", "tab", "mem"]
Represents a WebAssembly function instance.
A function instance is the runtime representation of a
function. It effectively is a closure of the original function
(defined in either the host or the WebAssembly module) over the
runtime Instance
of its originating Module
.
The module instance is used to resolve references to other definitions during executing of the function.
Specification: https://webassembly.github.io/spec/core/exec/runtime.html#function-instances
Note that the function can be invoked/called by the host only when
it is an exported function (see Exports
to see an example).
Example
To build a Function
, we need its type. It can either be inferred
from Python thanks to annotations, or be given with a
FunctionType
value.
With Python annotations
First, let's see with Python annotations:
from wasmer import Store, Function, Type
def sum(x: int, y: int) -> int:
return x + y
store = Store()
function = Function(store, sum)
function_type = function.type
assert function_type.params == [Type.I32, Type.I32]
assert function_type.results == [Type.I32]
Here is the mapping table:
Annotations | WebAssembly type |
---|---|
int , 'i32' , 'I32' |
Type.I32 |
'i64' , 'I64' |
Type.I64 |
float , 'f32' , 'F32' |
Type.F32 |
'f64' , 'F64' |
Type.F64 |
None |
none (only in return position) |
It is possible for a host function to return a tuple of the types above (except None
), like:
from wasmer import Store, Function, Type
def swap(x: 'i32', y: 'i64') -> ('i64', 'i32'):
return (y, x)
store = Store()
function = Function(store, swap)
function_type = function.type
assert function_type.params == [Type.I32, Type.I64]
assert function_type.results == [Type.I64, Type.I32]
With FunctionType
Second, the same code but without annotations and a FunctionType
:
from wasmer import Store, Function, FunctionType, Type
def sum(x, y):
return x + y
store = Store()
function = Function(store, sum, FunctionType([Type.I32, Type.I32], [Type.I32]))
Returns the type of the function as a FunctionType
object.
Example
from wasmer import Store, Module, Instance, FunctionType, Type
module = Module(
Store(),
"""
(module
(type (func (param i32 i32) (result i32)))
(func (type 0)
local.get 0
local.get 1
i32.add)
(export "sum" (func 0)))
"""
)
instance = Instance(module)
sum = instance.exports.sum
sum_type = sum.type
assert isinstance(sum_type, FunctionType)
assert sum_type.params == [Type.I32, Type.I32]
assert sum_type.results == [Type.I32]
Represents a WebAssembly global instance.
A global instance is the runtime representation of a global variable. It consists of an individual value and a flag indicating whether it is mutable.
Specification: https://webassembly.github.io/spec/core/exec/runtime.html#global-instances
Example
from wasmer import Store, Global, Value, Type
store = Store()
# Let's create an immutable global.
global_ = Global(store, Value.i32(42))
global_type = global_.type
assert global_.value == 42
assert global_type.type == Type.I32
assert global_type.mutable == False
# Let's create an mutable global.
global_ = Global(store, Value.i32(42), mutable=True)
assert global_.mutable == True
Returns the type of the global as a value of kind GlobalType
.
Example
from wasmer import Store, Global, Value, Type
store = Store()
global_ = Global(store, Value.i32(42), mutable=False)
global_type = global_.type
assert global_type.type == Type.I32
assert global_type.mutable == False
Get or set a custom value to the global instance.
Example
from wasmer import Store, Global, Value
store = Store()
global_ = Global(store, Value.i32(42), mutable=True)
assert global_.value == 42
global_.value = 153
assert global_.value == 153
Checks whether the global is mutable.
Example
from wasmer import Store, Global, Value
store = Store()
global_ = Global(store, Value.i32(42), mutable=True)
assert global_.mutable == True
A WebAssembly memory instance.
A memory instance is the runtime representation of a linear memory. It consists of a vector of bytes and an optional maximum size.
The length of the vector always is a multiple of the WebAssembly page size, which is defined to be the constant 65536 – abbreviated 64Ki. Like in a memory type, the maximum size in a memory instance is given in units of this page size.
A memory created by the host or in WebAssembly code will be accessible and mutable from both host and WebAssembly.
Specification: https://webassembly.github.io/spec/core/exec/runtime.html#memory-instances
Example
Creates a Memory
from scratch:
from wasmer import Store, Memory, MemoryType
store = Store()
memory_type = MemoryType(minimum=3)
memory = Memory(store, memory_type)
assert memory.size == 3
Gets a memory from the exports of an instance:
from wasmer import Store, Module, Instance, Memory
module = Module(Store(), open('tests/tests.wasm', 'rb').read())
instance = Instance(module)
memory = instance.exports.memory
assert isinstance(memory, Memory)
Grow memory by the specified amount of WebAssembly pages.
Example
from wasmer import Store, Memory, MemoryType
store = Store()
memory_type = MemoryType(minimum=3)
memory = Memory(store, memory_type)
assert memory.size == 3
memory.grow(2)
assert memory.size == 5
Creates a read-and-write view over the memory data where
elements are of kind uint8
. See the Uint8Array
view to
learn more.
Examples
from wasmer import Store, Memory, MemoryType, Uint8Array
store = Store()
memory_type = MemoryType(minimum=3)
memory = Memory(store, memory_type)
assert isinstance(memory.uint8_view(offset=42), Uint8Array)
Creates a read-and-write over the memory data where elements
are of kind int8
. See the Int8Array
view to learn more,
and the Memory.uint8_view
method to see an example.
Creates a read-and-write over the memory data where elements
are of kind uint16
. See the Uint16Array
view to learn
more, and the Memory.uint8_view
method to see an example.
Creates a read-and-write over the memory data where elements
are of kind int16
. See the Int16Array
view to learn more,
and the Memory.uint8_view
method to see an example.
Creates a read-and-write over the memory data where elements
are of kind uint32
. See the Uint32Array
view to learn
more, and the Memory.uint8_view
method to see an example.
Creates a read-and-write over the memory data where elements
are of kind int32
. See the Int32Array
view to learn more,
and the Memory.uint8_view
method to see an example.
Creates a read-and-write over the memory data where elements
are of kind uint64
. See the Uint64Array
view to learn
more, and the Memory.uint8_view
method to see an example.
Creates a read-and-write over the memory data where elements
are of kind int64
. See the Int64Array
view to learn more,
and the Memory.uint8_view
method to see an example.
Creates a read-and-write over the memory data where elements
are of kind float32
. See the Float32Array
view to learn more,
and the Memory.uint8_view
method to see an example.
Creates a read-and-write over the memory data where elements
are of kind float64
. See the Float64Array
view to learn more,
and the Memory.uint8_view
method to see an example.
Gets the memory type, of kind MemoryType
.
Example
from wasmer import Store, Memory, Module, Instance
module = Module(Store(), open('tests/tests.wasm', 'rb').read())
instance = Instance(module)
memory = instance.exports.memory
memory_type = memory.type
assert memory_type.minimum == 17
assert memory_type.maximum == None
assert memory_type.shared == False
Returns the size (in bytes) of the Memory
.
Example
from wasmer import Store, Memory, MemoryType
store = Store()
memory_type = MemoryType(minimum=3)
memory = Memory(store, memory_type)
assert memory.data_size == 196608
A WebAssembly table instance.
The Table
class is an array-like structure representing a
WebAssembly table, which stores function references.
A table created by the host or in WebAssembly code will be accessible and mutable from both host and WebAssembly.
Specification: https://webassembly.github.io/spec/core/exec/runtime.html#table-instances
Gets the table type, as an object of kind TableType
.
Example
from wasmer import Store, Module, Instance, Table, Type
module = Module(Store(), '(module (table (export "table") 2 funcref))')
instance = Instance(module)
table = instance.exports.table
table_type = table.type
assert table_type.type == Type.FUNC_REF
assert table_type.minimum == 2
assert table_type.maximum == None
Gets the table size (in elements).
Example
from wasmer import Store, Module, Instance, Table
module = Module(Store(), '(module (table (export "table") 2 funcref))')
instance = Instance(module)
table = instance.exports.table
assert table.size == 2
An ImportObject
represents all of the import data used when
instantiating a WebAssembly module.
Important
This object is deprecated in favor of dictionaries in Python. You can now type:
from wasmer import Store, Function
def sum(x: int, y: int) -> int:
return x + y
store = Store()
import_object = {}
import_object["math"] = {
"sum": Function(store, sum)
}
Example
Importing a function, math.sum
, and call it through the exported
add_one
function:
from wasmer import Store, Module, Instance, ImportObject, Function
def sum(x: int, y: int) -> int:
return x + y
store = Store()
module = Module(
store,
"""
(module
(import "math" "sum" (func $sum (param i32 i32) (result i32)))
(func (export "add_one") (param i32) (result i32)
local.get 0
i32.const 1
call $sum))
"""
)
import_object = ImportObject()
import_object.register(
"math",
{
"sum": Function(store, sum)
}
)
instance = Instance(module, import_object)
assert instance.exports.add_one(1) == 2
Importing a memory:
from wasmer import Store, Module, Instance, Memory, MemoryType, ImportObject
store = Store()
module = Module(
store,
"""
(module
(import "env" "memory" (memory $memory 1))
(func (export "increment")
i32.const 0
i32.const 0
i32.load ;; load 0
i32.const 1
i32.add ;; add 1
i32.store ;; store at 0
))
"""
)
memory = Memory(store, MemoryType(minimum=1))
view = memory.uint8_view(offset=0)
import_object = ImportObject()
import_object.register(
"env",
{
"memory": memory
}
)
instance = Instance(module, import_object)
assert view[0] == 0
instance.exports.increment()
assert view[0] == 1
instance.exports.increment()
assert view[0] == 2
Importing a global:
from wasmer import Store, Module, Instance, ImportObject, Global, Value
store = Store()
module = Module(
store,
"""
(module
(import "env" "global" (global $global (mut i32)))
(func (export "read_g") (result i32)
global.get $global)
(func (export "write_g") (param i32)
local.get 0
global.set $global))
"""
)
global_ = Global(store, Value.i32(7), mutable=True)
import_object = ImportObject()
import_object.register(
"env",
{
"global": global_
}
)
instance = Instance(module, import_object)
assert instance.exports.read_g() == 7
global_.value = 153
assert instance.exports.read_g() == 153
instance.exports.write_g(11)
assert global_.value == 11
etc.
Checks whether the import object contains a specific namespace.
Example
from wasmer import ImportObject
import_object = ImportObject()
assert import_object.contains_namespace("foo") == False
Gets a Python dictionary from an ImportObject
.
Registers a set of Function
, Memory
, Global
or Table
to a particular namespace.
Example
from wasmer import Store, ImportObject, Function, Memory, MemoryType
store = Store()
def sum(x: int, y: int) -> int:
return x + y
import_object = ImportObject()
import_object.register(
"env",
{
"sum": Function(store, sum),
"memory": Memory(store, MemoryType(minimum=1))
}
)
A WebAssembly instance is a stateful, executable instance of a
WebAssembly Module
.
Instance objects contain all the exported WebAssembly functions, memories, tables and globals that allow interacting with WebAssembly.
Specification: https://webassembly.github.io/spec/core/exec/runtime.html#module-instances
Example
Example without an import object. The following creates a module
with a sum
exported function that sum two integers.
from wasmer import Store, Module, Instance
module = Module(
Store(),
"""
(module
(type (func (param i32 i32) (result i32)))
(func (type 0)
local.get 0
local.get 1
i32.add)
(export "sum" (func 0)))
"""
)
instance = Instance(module)
assert instance.exports.sum(1, 2) == 3
Example with an import object. The following creates a module that
(i) imports a sum
function from the math
namespace, and (ii)
exports a add_one
function that adds 1 to any given integer (by
using the math.sum
function).
from wasmer import Store, Module, Instance, Function
from collections import defaultdict
# Let's define the `sum` function!
def sum(x: int, y: int) -> int:
return x + y
# Let's build a store, as usual.
store = Store()
# Let's compile the WebAssembly module.
module = Module(
store,
"""
(module
(import "math" "sum" (func $sum (param i32 i32) (result i32)))
(func (export "add_one") (param i32) (result i32)
local.get 0
i32.const 1
call $sum))
"""
)
# Now, let's create an import object, and register the `sum`
# function.
import_object = defaultdict(dict)
import_object["math"]["sum"] = Function(store, sum)
# Here we go, let's instantiate the module with the import object!
instance = Instance(module, import_object)
# Let's test it!
assert instance.exports.add_one(41) == 42
Represents a read-and-write buffer over data of a memory.
It is built by the Memory.buffer
getter.
It implements the Python buffer protocol, so it
is possible to read and write bytes with bytes
,
bytearray
or memoryview
.
Example
from wasmer import Memory, MemoryType, Store
store = Store()
memory = Memory(store, MemoryType(minimum=128))
# Let's write data with a `Int8Array` view for example.
int8 = memory.int8_view()
int8[0] = 1
int8[1] = 2
int8[2] = 3
int8[3] = 0x57
int8[4] = 0x61
int8[5] = 0x73
int8[6] = 0x6d
int8[7] = 0x65
int8[8] = 0x72
# Let's read data with a `Buffer` for example.
byte_array = bytearray(memory.buffer)
assert byte_array[0:3] == b'\x01\x02\x03'
assert byte_array[3:9].decode() == 'Wasmer'
Represents a read-and-write view over the data of a memory.
It is built by the Memory.uint8_view
and siblings getters.
It implements the Python mapping protocol, so it is possible to read and write bytes with a standard Python API.
Example
This is an example for the Uint8Array
view, but it is
the same for its siblings!
from wasmer import Store, Module, Instance, Uint8Array
module = Module(Store(), open('tests/tests.wasm', 'rb').read())
instance = Instance(module)
exports = instance.exports
pointer = exports.string()
memory = exports.memory.uint8_view(offset=pointer)
nth = 0
string = ''
while (0 != memory[nth]):
string += chr(memory[nth])
nth += 1
assert string == 'Hello, World!'
Gets the number of bytes per element.
Represents a read-and-write view over the data of a memory.
It is built by the Memory.uint8_view
and siblings getters.
It implements the Python mapping protocol, so it is possible to read and write bytes with a standard Python API.
Example
This is an example for the Uint8Array
view, but it is
the same for its siblings!
from wasmer import Store, Module, Instance, Uint8Array
module = Module(Store(), open('tests/tests.wasm', 'rb').read())
instance = Instance(module)
exports = instance.exports
pointer = exports.string()
memory = exports.memory.uint8_view(offset=pointer)
nth = 0
string = ''
while (0 != memory[nth]):
string += chr(memory[nth])
nth += 1
assert string == 'Hello, World!'
Gets the number of bytes per element.
Represents a read-and-write view over the data of a memory.
It is built by the Memory.uint8_view
and siblings getters.
It implements the Python mapping protocol, so it is possible to read and write bytes with a standard Python API.
Example
This is an example for the Uint8Array
view, but it is
the same for its siblings!
from wasmer import Store, Module, Instance, Uint8Array
module = Module(Store(), open('tests/tests.wasm', 'rb').read())
instance = Instance(module)
exports = instance.exports
pointer = exports.string()
memory = exports.memory.uint8_view(offset=pointer)
nth = 0
string = ''
while (0 != memory[nth]):
string += chr(memory[nth])
nth += 1
assert string == 'Hello, World!'
Gets the number of bytes per element.
Represents a read-and-write view over the data of a memory.
It is built by the Memory.uint8_view
and siblings getters.
It implements the Python mapping protocol, so it is possible to read and write bytes with a standard Python API.
Example
This is an example for the Uint8Array
view, but it is
the same for its siblings!
from wasmer import Store, Module, Instance, Uint8Array
module = Module(Store(), open('tests/tests.wasm', 'rb').read())
instance = Instance(module)
exports = instance.exports
pointer = exports.string()
memory = exports.memory.uint8_view(offset=pointer)
nth = 0
string = ''
while (0 != memory[nth]):
string += chr(memory[nth])
nth += 1
assert string == 'Hello, World!'
Gets the number of bytes per element.
Represents a read-and-write view over the data of a memory.
It is built by the Memory.uint8_view
and siblings getters.
It implements the Python mapping protocol, so it is possible to read and write bytes with a standard Python API.
Example
This is an example for the Uint8Array
view, but it is
the same for its siblings!
from wasmer import Store, Module, Instance, Uint8Array
module = Module(Store(), open('tests/tests.wasm', 'rb').read())
instance = Instance(module)
exports = instance.exports
pointer = exports.string()
memory = exports.memory.uint8_view(offset=pointer)
nth = 0
string = ''
while (0 != memory[nth]):
string += chr(memory[nth])
nth += 1
assert string == 'Hello, World!'
Gets the number of bytes per element.
Represents a read-and-write view over the data of a memory.
It is built by the Memory.uint8_view
and siblings getters.
It implements the Python mapping protocol, so it is possible to read and write bytes with a standard Python API.
Example
This is an example for the Uint8Array
view, but it is
the same for its siblings!
from wasmer import Store, Module, Instance, Uint8Array
module = Module(Store(), open('tests/tests.wasm', 'rb').read())
instance = Instance(module)
exports = instance.exports
pointer = exports.string()
memory = exports.memory.uint8_view(offset=pointer)
nth = 0
string = ''
while (0 != memory[nth]):
string += chr(memory[nth])
nth += 1
assert string == 'Hello, World!'
Gets the number of bytes per element.
Represents a read-and-write view over the data of a memory.
It is built by the Memory.uint8_view
and siblings getters.
It implements the Python mapping protocol, so it is possible to read and write bytes with a standard Python API.
Example
This is an example for the Uint8Array
view, but it is
the same for its siblings!
from wasmer import Store, Module, Instance, Uint8Array
module = Module(Store(), open('tests/tests.wasm', 'rb').read())
instance = Instance(module)
exports = instance.exports
pointer = exports.string()
memory = exports.memory.uint8_view(offset=pointer)
nth = 0
string = ''
while (0 != memory[nth]):
string += chr(memory[nth])
nth += 1
assert string == 'Hello, World!'
Gets the number of bytes per element.
Represents a read-and-write view over the data of a memory.
It is built by the Memory.uint8_view
and siblings getters.
It implements the Python mapping protocol, so it is possible to read and write bytes with a standard Python API.
Example
This is an example for the Uint8Array
view, but it is
the same for its siblings!
from wasmer import Store, Module, Instance, Uint8Array
module = Module(Store(), open('tests/tests.wasm', 'rb').read())
instance = Instance(module)
exports = instance.exports
pointer = exports.string()
memory = exports.memory.uint8_view(offset=pointer)
nth = 0
string = ''
while (0 != memory[nth]):
string += chr(memory[nth])
nth += 1
assert string == 'Hello, World!'
Gets the number of bytes per element.
Represents a read-and-write view over the data of a memory.
It is built by the Memory.uint8_view
and siblings getters.
It implements the Python mapping protocol, so it is possible to read and write bytes with a standard Python API.
Example
This is an example for the Uint8Array
view, but it is
the same for its siblings!
from wasmer import Store, Module, Instance, Uint8Array
module = Module(Store(), open('tests/tests.wasm', 'rb').read())
instance = Instance(module)
exports = instance.exports
pointer = exports.string()
memory = exports.memory.uint8_view(offset=pointer)
nth = 0
string = ''
while (0 != memory[nth]):
string += chr(memory[nth])
nth += 1
assert string == 'Hello, World!'
Gets the number of bytes per element.
Represents a read-and-write view over the data of a memory.
It is built by the Memory.uint8_view
and siblings getters.
It implements the Python mapping protocol, so it is possible to read and write bytes with a standard Python API.
Example
This is an example for the Uint8Array
view, but it is
the same for its siblings!
from wasmer import Store, Module, Instance, Uint8Array
module = Module(Store(), open('tests/tests.wasm', 'rb').read())
instance = Instance(module)
exports = instance.exports
pointer = exports.string()
memory = exports.memory.uint8_view(offset=pointer)
nth = 0
string = ''
while (0 != memory[nth]):
string += chr(memory[nth])
nth += 1
assert string == 'Hello, World!'
Gets the number of bytes per element.
A WebAssembly module contains stateless WebAssembly code that has already been compiled and can be instantiated multiple times.
Creates a new WebAssembly Module given the configuration in the store.
If the provided bytes are not WebAssembly-like (start with
b"\0asm"
), this function will try to to convert the bytes
assuming they correspond to the WebAssembly text format.
Security
Before the code is compiled, it will be validated using the store features.
Example
from wasmer import Store, Module
store = Store()
# Let's compile WebAssembly from bytes.
module = Module(store, open('tests/tests.wasm', 'rb').read())
# Let's compile WebAssembly from WAT.
module = Module(store, '(module)')
Validates a new WebAssembly Module given the configuration
in the Store
.
This validation is normally pretty fast and checks the enabled
WebAssembly features in the Store
engine to assure deterministic
validation of the Module
.
Example
from wasmer import Store, Module
assert Module.validate(Store(), wasm_bytes)
Get the custom sections of the module given a name
.
Important
Following the WebAssembly specification, one name can have multiple custom sections. That's why a list of bytes is returned rather than bytes.
Consequently, the empty list represents the absence of a custom section for the given name.
Examples
from wasmer import Store, Module
module = Module(Store(), open('tests/custom_sections.wasm', 'rb').read())
assert module.custom_sections('easter_egg') == [b'Wasmer']
assert module.custom_sections('hello') == [b'World!']
assert module.custom_sections('foo') == []
Serializes a module into a binary representation that the
Engine
can later process via Module.deserialize
.
Examples
from wasmer import Store, Module
store = Store()
module = Module(Store(), '(module)')
serialized_module = module.serialize()
assert type(serialized_module) == bytes
Deserializes a serialized module binary into a Module
.
Note: the module has to be serialized before with the
serialize
method.
Safety
This function is inherently unsafe as the provided bytes:
- Are going to be deserialized directly into Rust objects.
- Contains the function assembly bodies and, if intercepted, a malicious actor could inject code into executable memory.
And as such, the deserialize
method is unsafe.
Example
from wasmer import Store, Module
store = Store()
module = Module(
store,
"""
(module
(func (export "function") (param i32 i64)))
"""
)
serialized_module = module.serialize()
del module
module = Module.deserialize(store, serialized_module)
del serialized_module
assert isinstance(module, Module)
Returns a list of ExportType
objects, which represents all
the exports of this module.
The order of the exports is guaranteed to be the same as in the WebAssembly bytecode.
Example
See the ExportType
class to learn more.
Returns a list of ImportType
objects, which represents all
the imports of this module.
The order of the imports is guaranteed to be the same as in the WebAssembly bytecode.
Example
See the ImportType
class to learn more.
Get or set the current name of the module.
This name is normally set in the WebAssembly bytecode by some compilers, but can be also overwritten.
Not all modules have a name.
Example
from wasmer import Store, Module
store = Store()
# Module with an existing name.
assert Module(store, '(module $moduleName)').name == 'moduleName'
# Module with no name.
assert Module(store, '(module)').name == None
# Change the module's name.
module = Module(store, '(module $moduleName)')
module.name = 'hello'
assert module.name == 'hello'
The store represents all global state that can be manipulated by WebAssembly programs. It consists of the runtime representation of all instances of functions, tables, memories, and globals that have been allocated during the lifetime of the abstract machine.
The Store
holds the engine (that is —amongst many things— used
to compile the WebAssembly bytes into a valid module artifact), in
addition to the Tunables
(that are used to create the memories,
tables and globals). The engine comes from the wasmer.engine
module.
Specification: https://webassembly.github.io/spec/core/exec/runtime.html#store
Read the documentation of the engine
submodule to learn more.
Examples
Use the Universal engine with no compiler (headless mode):
from wasmer import engine, Store
store = Store(engine.Universal())
Use the Universal engine with the LLVM compiler:
from wasmer import engine, Store
from wasmer_compiler_llvm import Compiler
store = Store(engine.Universal(Compiler))
If the store is built without an engine, the Universal engine will be
used, with the first compiler found in this order:
compiler_compiler_cranelift
, compiler_compiler_llvm
,
compiler_compiler_singlepass
, otherwise it will run in headless
mode.
Represents the type of a module's export (not to be confused with
an export of an instance). It is usually built from the
Module.exports
getter.
Examples
from wasmer import Store, Module, ExportType, FunctionType, GlobalType, TableType, MemoryType, Type
module = Module(
Store(),
"""
(module
(func (export "function") (param i32 i64))
(global (export "global") i32 (i32.const 7))
(table (export "table") 0 funcref)
(memory (export "memory") 1))
"""
)
exports = module.exports
assert isinstance(exports[0], ExportType)
assert exports[0].name == "function"
assert isinstance(exports[0].type, FunctionType)
assert exports[0].type.params == [Type.I32, Type.I64]
assert exports[0].type.results == []
assert exports[1].name == "global"
assert isinstance(exports[1].type, GlobalType)
assert exports[1].type.type == Type.I32
assert exports[1].type.mutable == False
assert exports[2].name == "table"
assert isinstance(exports[2].type, TableType)
assert exports[2].type.type == Type.FUNC_REF
assert exports[2].type.minimum == 0
assert exports[2].type.maximum == None
assert exports[3].name == "memory"
assert isinstance(exports[3].type, MemoryType)
assert exports[3].type.minimum == 1
assert exports[3].type.maximum == None
assert exports[3].type.shared == False
The type of the export. Possible values are: FunctionType
,
GlobalType
, TableType
and MemoryType
.
The name of the export.
Represents the signature of a function that is either implemented in WebAssembly module or exposed to WebAssembly by the host.
WebAssembly functions can have 0 or more parameters and results.
Example
from wasmer import FunctionType, Type
# Type: (i32, i32) -> i32
function_type = FunctionType(
params=[Type.I32, Type.I32],
results=[Type.I32]
)
Parameters, i.e. inputs, of the function.
Results, i.e. outputs, of the function.
A descriptor for a WebAssembly global.
Example
from wasmer import GlobalType, Type
# Describes a global of kind `i32` which is immutable.
global_type = GlobalType(Type.I32, mutable=False)
The type of the value stored in the global.
A flag indicating whether the value may change at runtime.
Represents the type of a module's import. It is usually built from
the Module.imports
getter.
Example
from wasmer import Store, Module, ImportType, FunctionType, GlobalType, TableType, MemoryType, Type
module = Module(
Store(),
"""
(module
(import "ns" "function" (func))
(import "ns" "global" (global f32))
(import "ns" "table" (table 1 2 anyfunc))
(import "ns" "memory" (memory 3 4)))
"""
)
imports = module.imports
assert isinstance(imports[0], ImportType)
assert imports[0].module == "ns"
assert imports[0].name == "function"
assert isinstance(imports[0].type, FunctionType)
assert imports[0].type.params == []
assert imports[0].type.results == []
assert imports[1].module == "ns"
assert imports[1].name == "global"
assert isinstance(imports[1].type, GlobalType)
assert imports[1].type.type == Type.F32
assert imports[1].type.mutable == False
assert imports[2].module == "ns"
assert imports[2].name == "table"
assert isinstance(imports[2].type, TableType)
assert imports[2].type.type == Type.FUNC_REF
assert imports[2].type.minimum == 1
assert imports[2].type.maximum == 2
assert imports[3].module == "ns"
assert imports[3].name == "memory"
assert isinstance(imports[3].type, MemoryType)
assert imports[3].type.minimum == 3
assert imports[3].type.maximum == 4
assert imports[3].type.shared == False
The type of the import. Possible values are: FunctionType
,
GlobalType
, TableType
and MemoryType
.
The namespace name (also known as module name).
The name of the import.
A descriptor for a WebAssembly memory type.
Memories are described in units of pages (64Kb) and represent contiguous chunks of addressable memory.
Example
from wasmer import MemoryType
memory_type = MemoryType(
minimum=1,
shared=True
)
The maximum number of pages in the memory. It is optional.
The minimum number of pages in the memory.
A descriptor for a table in a WebAssembly module.
Tables are contiguous chunks of a specific element, typically a
funcref
or externref
. The most common use for tables is a
function table through which call_indirect
can invoke other
functions.
Example
from wasmer import TableType, Type
table_type = TableType(Type.I32, minimum=7, maximum=42)
The minimum number of elements in the table.
The type of data stored in elements of the table.
The maximum number of elements in the table.
Represents a WebAssembly value of a specific type.
Most of the time, the types for WebAssembly values will be
inferred. When it's not possible, the Value
class is necessary.
Example
from wasmer import Value
value = Value.i32(42)
An enumeration.
Inherited Members
- enum.Enum
- name
- value
- builtins.int
- conjugate
- bit_length
- bit_count
- to_bytes
- from_bytes
- as_integer_ratio
- real
- imag
- numerator
- denominator
Wasmer Engines.
Engines are mainly responsible for two things:
- Transform the compilation code (from any Wasmer compiler) to create an artifact,
- Load an atifact so it can be used by the user (normally, pushing the code into executable memory and so on).
It currently has two implementations:
- Universal with
engine.Universal
, - Dylib with
engine.Dylib
.
Both engines receive an optional compiler. If absent, engines will run in headless mode, i.e. they won't be able to compile (create) an artifact), they will only be able to run (load) an artifact.
Compilers are distributed as individual Python packages:
wasmer_compiler_cranelift
to use the Cranelift compiler,wasmer_compiler_llvm
to use the LLVM compiler,wasmer_compiler_singlepass
to use the Singlepass compiler.
Example
Create a Universal engine with no compiler (headless mode):
from wasmer import engine
engine = engine.Universal()
Create a Universal engine with the LLVM compiler:
from wasmer import engine
from wasmer_compiler_llvm import Compiler
engine = engine.Universal(Compiler)
Engines are stored inside the wasmer.Store
.
Wasmer's compilation targets.
Wasmer has several compilers used by the engines (wasmer.engine
)
when a WebAssembly module needs to be compiled. The Wasmer's
architecture allows to compile for any targets. It allows to
cross-compile a WebAssembly module, i.e. to compile from another
architecture than the host's.
This module provides the Target
class that allows to define a
target for the compiler. A Target
is defined by a Triple
and
CpuFeatures
(optional).
Example
from wasmer import engine, target, Store, Module
from wasmer_compiler_cranelift import Compiler
# Build a triple from a string.
triple = target.Triple('x86_64-linux-musl')
# Build the CPU features (optional).
cpu_features = target.CpuFeatures()
cpu_features.add('sse2')
# Build the target.
target = target.Target(triple, cpu_features)
# There we go. When creating the engine, pass the compiler _and_
# the target.
engine = engine.Dylib(Compiler, target)
# And finally, build the store with the engine.
store = Store(engine)
# Now, let's compile the module for the defined target.
module = Module(
store,
"""
(module
(type $sum_t (func (param i32 i32) (result i32)))
(func $sum_f (type $sum_t) (param $x i32) (param $y i32) (result i32)
local.get $x
local.get $y
i32.add)
(export "sum" (func $sum_f)))
"""
)
# What's next? Serialize the module, and execute it on the
# targeted host.
Wasmer's WASI implementation.
From the user perspective, WASI is a bunch of imports. To generate
the appropriated imports, you can use StateBuilder
to build an
Environment
. This environment holds the WASI memory, and can be
used to generate a valid wasmer.ImportObject
. This last one can
be passed to wasmer.Instance
to instantiate a wasmer.Module
that needs WASI support.
Example
from wasmer import wasi, Store, Module, Instance
store = Store()
module = Module(store, open('tests/wasi.wasm', 'rb').read())
# Get the WASI version.
wasi_version = wasi.get_version(module, strict=True)
# Build a WASI environment for the imports.
wasi_env = wasi.StateBuilder('test-program').argument('--foo').finalize()
# Generate an `ImportObject` from the WASI environment.
import_object = wasi_env.generate_import_object(store, wasi_version)
# Now we are ready to instantiate the module.
instance = Instance(module, import_object)
# Here we go, let's start the program.
instance.exports._start()