Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add bindings for Module.{serialize,deserialize} #43

Merged
merged 1 commit into from
Jul 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions tests/test_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,11 @@ def test_exports(self):
assert(isinstance(ty, TableType))
self.assertEqual(ty.limits, Limits(1, None))
self.assertEqual(ty.element, ValType.funcref())

def test_serialize(self):
store = Store()
module = Module(store.engine, '(module)')
encoded = module.serialize()
module = Module.deserialize(store.engine, encoded)
assert(len(module.imports) == 0)
assert(len(module.exports) == 0)
56 changes: 53 additions & 3 deletions wasmtime/_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,44 @@ def __init__(self, engine: Engine, wasm: typing.Union[str, bytes]):
self._ptr = ptr
self.engine = engine

@classmethod
def _from_ptr(cls, ptr: "pointer[ffi.wasm_module_t]", engine: Engine) -> "Module":
ty: "Module" = cls.__new__(cls)
if not isinstance(ptr, POINTER(ffi.wasm_module_t)):
raise TypeError("wrong pointer type")
ty._ptr = ptr
ty.engine = engine
return ty

@classmethod
def deserialize(cls, engine: Engine, encoded: typing.Union[bytes, bytearray]) -> 'Module':
"""
Deserializes bytes previously created by `Module.serialize`.

This constructor for `Module` will deserialize bytes previously created
by a serialized module. This will only succeed if the bytes were
previously created by the same version of `wasmtime` as well as the
same configuration within `Engine`.
"""

if not isinstance(engine, Engine):
raise TypeError("expected an Engine")
if not isinstance(encoded, (bytes, bytearray)):
raise TypeError("expected bytes")

# TODO: can the copy be avoided here? I can't for the life of me
# figure this out.
c_ty = c_uint8 * len(encoded)
binary = ffi.wasm_byte_vec_t(len(encoded), c_ty.from_buffer_copy(encoded))
ptr = POINTER(ffi.wasm_module_t)()
error = ffi.wasmtime_module_deserialize(engine._ptr, byref(binary), byref(ptr))
if error:
raise WasmtimeError._from_ptr(error)
ret: "Module" = cls.__new__(cls)
ret._ptr = ptr
ret.engine = engine
return ret

@classmethod
def validate(cls, store: Store, wasm: typing.Union[bytes, bytearray]) -> None:
"""
Expand Down Expand Up @@ -91,9 +129,21 @@ def exports(self) -> typing.List[ExportType]:
ret.append(ExportType._from_ptr(exports.vec.data[i], exports))
return ret

def __del__(self) -> None:
if hasattr(self, '_ptr'):
ffi.wasm_module_delete(self._ptr)
def serialize(self) -> bytearray:
"""
Serializes this module to a binary representation.

This method will serialize this module to an in-memory byte array which
can be cached and later passed to `Module.deserialize` to recreate this
module.
"""
raw = ffi.wasm_byte_vec_t()
err = ffi.wasmtime_module_serialize(self._ptr, byref(raw))
if err:
raise WasmtimeError._from_ptr(err)
ret = ffi.to_bytes(raw)
ffi.wasm_byte_vec_delete(byref(raw))
return ret


class ImportTypeList:
Expand Down