Skip to content

Commit

Permalink
Merge #30
Browse files Browse the repository at this point in the history
30: feat(import) Support instance context data r=Hywan a=Hywan

Fix #28.

Example:

```go
//export logMessageWithContextData
func logMessageWithContextData(context unsafe.Pointer, pointer int32, length int32) {
	var instanceContext = wasm.IntoInstanceContext(context)
	var memory = instanceContext.Memory().Data()
	var logMessage = (*logMessageContext)(instanceContext.Data())

	logMessage.message = string(memory[pointer : pointer+length])
}

type logMessageContext struct {
	message string
}

func testImportInstanceContextData(t *testing.T) {
	imports, err := wasm.NewImports().Append("log_message", logMessageWithContextData, C.logMessageWithContextData)
	assert.NoError(t, err)

	instance, err := wasm.NewInstanceWithImports(getImportedFunctionBytes("log.wasm"), imports)
	assert.NoError(t, err)

	defer instance.Close()

	contextData := logMessageContext{message: "first"}
	instance.SetContextData(unsafe.Pointer(&contextData))

	doSomething := instance.Exports["do_something"]

	result, err := doSomething()

	assert.NoError(t, err)
	assert.Equal(t, wasm.TypeVoid, result.GetType())
	assert.Equal(t, "hello", contextData.message)
}
```

1. When defining the instance, we see `SetContextData` that assigns a data to the instance context.
2. In the imported function, on the instance context, we see the `Data` method call that retrieves the instance context data (here, cast as a `logMessageContext` structure).

Co-authored-by: Ivan Enderlin <[email protected]>
  • Loading branch information
bors[bot] and Hywan committed Jun 5, 2019
2 parents b5a33c0 + a172bac commit 8fe4352
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 5 deletions.
2 changes: 1 addition & 1 deletion justfile
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ test:
#export DYLD_PRINT_LIBRARIES=y
cd wasmer/test/
# Run the tests.
go test -test.v $(find . -type f \( -name "*_test.go" \! -name "example_*.go" \! -name "benchmark*.go" \) ) imports.go
GODEBUG=cgocheck=2 go test -test.v $(find . -type f \( -name "*_test.go" \! -name "example_*.go" \! -name "benchmark*.go" \) ) imports.go
# Run the short examples.
go test -test.v example_test.go
# Run the long examples.
Expand Down
8 changes: 8 additions & 0 deletions wasmer/bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,14 @@ func cWasmerInstanceContextMemory(instanceContext *cWasmerInstanceContextT) *cWa
return (*cWasmerMemoryT)(C.wasmer_instance_context_memory((*C.wasmer_instance_context_t)(instanceContext), 0))
}

func cWasmerInstanceContextDataSet(instance *cWasmerInstanceT, dataPointer unsafe.Pointer) {
C.wasmer_instance_context_data_set((*C.wasmer_instance_t)(instance), dataPointer)
}

func cWasmerInstanceContextDataGet(instanceContext *cWasmerInstanceContextT) unsafe.Pointer {
return unsafe.Pointer(C.wasmer_instance_context_data_get((*C.wasmer_instance_t)(instanceContext)))
}

func cGoString(string *cChar) string {
return C.GoString((*C.char)(string))
}
Expand Down
6 changes: 6 additions & 0 deletions wasmer/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,9 @@ func IntoInstanceContext(instanceContext unsafe.Pointer) InstanceContext {
func (instanceContext *InstanceContext) Memory() *Memory {
return &instanceContext.memory
}

// Data returns the instance context data as an `unsafe.Pointer`. It's
// up to the user to cast it appropriately as a pointer to a data.
func (instanceContext *InstanceContext) Data() unsafe.Pointer {
return cWasmerInstanceContextDataGet(instanceContext.context)
}
10 changes: 10 additions & 0 deletions wasmer/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,16 @@ func NewInstanceWithImports(bytes []byte, imports *Imports) (Instance, error) {
return Instance{instance: instance, imports: imports, Exports: exports, Memory: memory}, nil
}

// SetContextData assigns a data that can be used by all imported
// functions. Indeed, each imported function receives as its first
// argument an instance context (see `InstanceContext`). An instance
// context can hold a pointer to any kind of data. It is important to
// understand that this data is shared by all imported function, it's
// global to the instance.
func (instance *Instance) SetContextData(data unsafe.Pointer) {
cWasmerInstanceContextDataSet(instance.instance, data)
}

// Close closes/frees an `Instance`.
func (instance *Instance) Close() {
if instance.imports != nil {
Expand Down
4 changes: 4 additions & 0 deletions wasmer/test/import_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,7 @@ func TestImportBadOutput(t *testing.T) {
func TestImportInstanceContext(t *testing.T) {
testImportInstanceContext(t)
}

func TestImportInstanceContextData(t *testing.T) {
testImportInstanceContextData(t)
}
44 changes: 40 additions & 4 deletions wasmer/test/imports.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ package wasmertest

// #include <stdlib.h>
//
// extern int32_t sum(void *ctx, int32_t x, int32_t y);
// extern int32_t sum(void *context, int32_t x, int32_t y);
// extern int32_t missingContext();
// extern int32_t badInstanceContext(int32_t x);
// extern int32_t badInput(void *ctx, char x);
// extern char badOutput(void *ctx);
// extern void logMessage(void *ctx, int32_t pointer, int32_t length);
// extern int32_t badInput(void *context, char x);
// extern char badOutput(void *context);
// extern void logMessage(void *context, int32_t pointer, int32_t length);
// extern void logMessageWithContextData(void *context, int32_t pointer, int32_t length);
import "C"
import (
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -117,4 +118,39 @@ func testImportInstanceContext(t *testing.T) {
assert.Equal(t, wasm.TypeVoid, result.GetType())
assert.NoError(t, err)
assert.Equal(t, "hello", loggedMessage)
loggedMessage = ""
}

//export logMessageWithContextData
func logMessageWithContextData(context unsafe.Pointer, pointer int32, length int32) {
var instanceContext = wasm.IntoInstanceContext(context)
var memory = instanceContext.Memory().Data()
var logMessage = (*logMessageContext)(instanceContext.Data())

logMessage.message = string(memory[pointer : pointer+length])
}

type logMessageContext struct {
message string
}

func testImportInstanceContextData(t *testing.T) {
imports, err := wasm.NewImports().Append("log_message", logMessageWithContextData, C.logMessageWithContextData)
assert.NoError(t, err)

instance, err := wasm.NewInstanceWithImports(getImportedFunctionBytes("log.wasm"), imports)
assert.NoError(t, err)

defer instance.Close()

contextData := logMessageContext{message: "first"}
instance.SetContextData(unsafe.Pointer(&contextData))

doSomething := instance.Exports["do_something"]

result, err := doSomething()

assert.NoError(t, err)
assert.Equal(t, wasm.TypeVoid, result.GetType())
assert.Equal(t, "hello", contextData.message)
}

0 comments on commit 8fe4352

Please sign in to comment.