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

feat(module) Support module serialization and deserialization #34

Merged
merged 5 commits into from
Jun 5, 2019
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
23 changes: 23 additions & 0 deletions wasmer/bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type cWasmerInstanceT C.wasmer_instance_t
type cWasmerMemoryT C.wasmer_memory_t
type cWasmerModuleT C.wasmer_module_t
type cWasmerResultT C.wasmer_result_t
type cWasmerSerializedModuleT C.wasmer_serialized_module_t
type cWasmerValueT C.wasmer_value_t
type cWasmerValueTag C.wasmer_value_tag

Expand Down Expand Up @@ -167,6 +168,28 @@ func cWasmerModuleInstantiate(module *cWasmerModuleT, instance **cWasmerInstance
return cWasmerResultT(C.wasmer_module_instantiate((*C.wasmer_module_t)(module), (**C.wasmer_instance_t)(unsafe.Pointer(instance)), (*C.wasmer_import_t)(imports), (C.int)(importsLength)))
}

func cWasmerModuleSerialize(serializedModule **cWasmerSerializedModuleT, module *cWasmerModuleT) cWasmerResultT {
return cWasmerResultT(C.wasmer_module_serialize((**C.wasmer_serialized_module_t)(unsafe.Pointer(serializedModule)), (*C.wasmer_module_t)(module)))
}

func cWasmerModuleDeserialize(module **cWasmerModuleT, serializedModule *cWasmerSerializedModuleT) cWasmerResultT {
return cWasmerResultT(C.wasmer_module_deserialize((**C.wasmer_module_t)(unsafe.Pointer(module)), (*C.wasmer_serialized_module_t)(serializedModule)))
}

func cWasmerSerializedModuleBytes(serializedModule *cWasmerSerializedModuleT) []byte {
var byteArray = C.wasmer_serialized_module_bytes((*C.wasmer_serialized_module_t)(serializedModule))

return C.GoBytes(unsafe.Pointer(byteArray.bytes), (C.int)(byteArray.bytes_len))
}

func cWasmerSerializedModuleFromBytes(serializedModule **cWasmerSerializedModuleT, serializedModuleBytes *cUint8T, serializedModuleBytesLength cInt) cWasmerResultT {
return cWasmerResultT(C.wasmer_serialized_module_from_bytes((**C.wasmer_serialized_module_t)(unsafe.Pointer(serializedModule)), (*C.uint8_t)(serializedModuleBytes), (C.uint)(serializedModuleBytesLength)))
}

func cWasmerSerializedModuleDestroy(serializedModule *cWasmerSerializedModuleT) {
C.wasmer_serialized_module_destroy((*C.wasmer_serialized_module_t)(serializedModule))
}

func cGoString(string *cChar) string {
return C.GoString((*C.char)(string))
}
Expand Down
35 changes: 35 additions & 0 deletions wasmer/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,41 @@ func ExampleModule_Instantiate() {
// 3
}

func ExampleModule_Serialize() {
// Compiles the bytes into a WebAssembly module.
module1, _ := wasm.Compile(GetBytes())
defer module1.Close()

// Serializes the module into a sequence of bytes.
serialization, _ := module1.Serialize()

// Do something with `serialization`.
// Then later…

// Deserializes the module.
module2, _ := wasm.DeserializeModule(serialization)
defer module2.Close()
// And enjoy!

// Instantiates the WebAssembly module.
instance, _ := module2.Instantiate()
defer instance.Close()

// Gets an exported function.
sum, functionExists := instance.Exports["sum"]

fmt.Println(functionExists)

// Calls the `sum` exported function with Go values.
result, _ := sum(1, 2)

fmt.Println(result)

// Output:
// true
// 3
}

func ExampleInstance_basic() {
// Instantiates a WebAssembly instance from bytes.
instance, err := wasm.NewInstance(GetBytes())
Expand Down
46 changes: 46 additions & 0 deletions wasmer/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,52 @@ func (module *Module) InstantiateWithImports(imports *Imports) (Instance, error)
)
}

// Serialize serializes the current module into a sequence of
// bytes. Those bytes can be deserialized into a module with
// `DeserializeModule`.
func (module *Module) Serialize() ([]byte, error) {
var serializedModule *cWasmerSerializedModuleT
var serializeResult = cWasmerModuleSerialize(&serializedModule, module.module)
defer cWasmerSerializedModuleDestroy(serializedModule)

if serializeResult != cWasmerOk {
return nil, NewModuleError("Failed to serialize the module.")
}

return cWasmerSerializedModuleBytes(serializedModule), nil
}

// DeserializeModule deserializes a sequence of bytes into a
// module. Ideally, those bytes must come from `Module.Serialize`.
func DeserializeModule(serializedModuleBytes []byte) (Module, error) {
var emptyModule = Module{module: nil}

if len(serializedModuleBytes) < 1 {
return emptyModule, NewModuleError("Serialized module bytes are empty.")
}

var serializedModule *cWasmerSerializedModuleT
var deserializeBytesResult = cWasmerSerializedModuleFromBytes(
&serializedModule,
(*cUint8T)(unsafe.Pointer(&serializedModuleBytes[0])),
cInt(len(serializedModuleBytes)),
)
defer cWasmerSerializedModuleDestroy(serializedModule)

if deserializeBytesResult != cWasmerOk {
return emptyModule, NewModuleError("Failed to reconstitute the serialized module from the given bytes.")
}

var module *cWasmerModuleT
var deserializeResult = cWasmerModuleDeserialize(&module, serializedModule)

if deserializeResult != cWasmerOk {
return emptyModule, NewModuleError("Failed to deserialize the module.")
}

return Module{module}, nil
}

// Close closes/frees a `Module`.
func (module *Module) Close() {
if module.module != nil {
Expand Down
37 changes: 37 additions & 0 deletions wasmer/test/module_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,40 @@ func TestModuleInstantiate(t *testing.T) {

assert.Equal(t, wasm.I32(3), result)
}

func TestModuleSerialize(t *testing.T) {
module1, err := wasm.Compile(GetBytes())
defer module1.Close()

assert.NoError(t, err)

bytes, err := module1.Serialize()

assert.NoError(t, err)

module2, err := wasm.DeserializeModule(bytes)
defer module2.Close()

assert.NoError(t, err)

instance, err := module2.Instantiate()
defer instance.Close()

assert.NoError(t, err)

result, _ := instance.Exports["sum"](1, 2)

assert.Equal(t, wasm.I32(3), result)
}

func TestModuleDeserializeModuleWithEmptyBytes(t *testing.T) {
_, err := wasm.DeserializeModule([]byte{})

assert.EqualError(t, err, "Serialized module bytes are empty.")
}

func TestModuleDeserializeModuleWithRandomBytes(t *testing.T) {
_, err := wasm.DeserializeModule([]byte("random"))

assert.EqualError(t, err, "Failed to deserialize the module.")
}