diff --git a/bridge.go b/bridge.go new file mode 100644 index 0000000..50377e0 --- /dev/null +++ b/bridge.go @@ -0,0 +1,87 @@ +package wasm + +import ( + "encoding/binary" + + "github.com/wasmerio/go-ext-wasm/wasmer" +) + +func init() { + Bridge = new(bridge) +} + +// Bridge connects go wasm builds +var Bridge *bridge + +type bridge struct { + instance wasmer.Instance + vmExit bool + exitCode int +} + +// GoBridge returns a new bridge. +func (b *bridge) InitWASM(file string, imports *wasmer.Imports) (err error) { + bytes, err := wasmer.ReadBytes(file) + if err != nil { + return err + } + + if imports == nil { + imports = wasmer.NewImports() + } + + err = b.addImports(imports) + if err != nil { + return err + } + + inst, err := wasmer.NewInstanceWithImports(bytes, imports) + if err != nil { + return err + } + + b.instance = inst + return nil +} + +// Run start the wasm instance. +func (b *bridge) Run() error { + defer b.instance.Close() + + run := b.instance.Exports["run"] + resume := b.instance.Exports["resume"] + _, err := run(0, 0) + if err != nil { + return err + } + + for !b.vmExit { + _, err = resume() + if err != nil { + return err + } + } + + return nil +} + +func (b *bridge) mem() []byte { + return b.instance.Memory.Data() +} + +func (b bridge) setInt64(offset int32, v int64) { + mem := b.mem() + binary.LittleEndian.PutUint64(mem[offset:], uint64(v)) +} + +func (b bridge) loadSlice(addr int32) []byte { + mem := b.mem() + array := binary.LittleEndian.Uint64(mem[addr+0:]) + length := binary.LittleEndian.Uint64(mem[addr+8:]) + return mem[array : array+length] +} + +func (b bridge) loadString(addr int32) string { + d := b.loadSlice(addr) + return string(d) +} diff --git a/imports.go b/imports.go index f807c61..8ac4560 100644 --- a/imports.go +++ b/imports.go @@ -22,11 +22,16 @@ extern void valueNew(void *context, int32_t a); extern void valueLength(void *context, int32_t a); extern void valuePrepareString(void *context, int32_t a); extern void valueLoadString(void *context, int32_t a); +extern void scheduleTimeoutEvent(void *context, int32_t a); +extern void clearTimeoutEvent(void *context, int32_t a); */ import "C" import ( + "crypto/rand" + "encoding/binary" "fmt" "log" + "time" "unsafe" "github.com/wasmerio/go-ext-wasm/wasmer" @@ -39,17 +44,21 @@ func debug(ctx unsafe.Pointer, a int32) { //export wexit func wexit(ctx unsafe.Pointer, a int32) { - fmt.Println("wasm exit") + Bridge.vmExit = true + mem := Bridge.mem() + Bridge.exitCode = int(binary.LittleEndian.Uint32(mem[a+8:])) + fmt.Println("Wasm exited with code", Bridge.exitCode) } //export wwrite func wwrite(ctx unsafe.Pointer, a int32) { - fmt.Println("wasm write") + fmt.Println("wasm write", a) } //export nanotime func nanotime(ctx unsafe.Pointer, a int32) { - fmt.Println("nano time") + n := time.Now().UnixNano() + Bridge.setInt64(a+8, n) } //export walltime @@ -69,7 +78,11 @@ func clearScheduledCallback(ctx unsafe.Pointer, a int32) { //export getRandomData func getRandomData(ctx unsafe.Pointer, a int32) { - fmt.Println("getRandomData") + s := Bridge.loadSlice(a + 8) + _, err := rand.Read(s) + if err != nil { + fmt.Println("failed: getRandomData", err) + } } //export stringVal @@ -79,7 +92,8 @@ func stringVal(ctx unsafe.Pointer, a int32) { //export valueGet func valueGet(ctx unsafe.Pointer, a int32) { - fmt.Println("valueGet") + str := Bridge.loadString(a + 16) + fmt.Println("valueGet", str) } //export valueSet @@ -127,9 +141,19 @@ func valueLoadString(ctx unsafe.Pointer, a int32) { fmt.Println("valueLoadString") } -// Imports returns wasm go specific imports -func Imports() (*wasmer.Imports, error) { - imps := wasmer.NewImports().Namespace("go") +//export scheduleTimeoutEvent +func scheduleTimeoutEvent(ctx unsafe.Pointer, a int32) { + fmt.Println("scheduleTimeoutEvent") +} + +//export clearTimeoutEvent +func clearTimeoutEvent(ctx unsafe.Pointer, a int32) { + fmt.Println("clearTimeoutEvent") +} + +// addImports adds go bridge imports in "go" namespace. +func (b *bridge) addImports(imps *wasmer.Imports) error { + imps = imps.Namespace("go") var is = []struct { name string imp interface{} @@ -143,6 +167,8 @@ func Imports() (*wasmer.Imports, error) { {"runtime.scheduleCallback", scheduleCallback, C.scheduleCallback}, {"runtime.clearScheduledCallback", clearScheduledCallback, C.clearScheduledCallback}, {"runtime.getRandomData", getRandomData, C.getRandomData}, + {"runtime.scheduleTimeoutEvent", scheduleTimeoutEvent, C.scheduleTimeoutEvent}, + {"runtime.clearTimeoutEvent", clearTimeoutEvent, C.clearTimeoutEvent}, {"syscall/js.stringVal", stringVal, C.stringVal}, {"syscall/js.valueGet", valueGet, C.valueGet}, {"syscall/js.valueSet", valueSet, C.valueSet}, @@ -160,9 +186,9 @@ func Imports() (*wasmer.Imports, error) { for _, imp := range is { imps, err = imps.Append(imp.name, imp.imp, imp.cgo) if err != nil { - return nil, err + return err } } - return imps, nil + return nil } diff --git a/simple/caller/main.go b/simple/caller/main.go index 5affb1a..9c6f10e 100644 --- a/simple/caller/main.go +++ b/simple/caller/main.go @@ -1,32 +1,18 @@ package main -import "C" import ( - "fmt" "log" wasmgo "github.com/vedhavyas/wasm" - wasm "github.com/wasmerio/go-ext-wasm/wasmer" ) func main() { - // Reads the WebAssembly module as bytes. - bytes, err := wasm.ReadBytes("./simple/prog/main.wasm") + err := wasmgo.Bridge.InitWASM("./simple/prog/main.wasm", nil) if err != nil { log.Fatal(err) } - imports, err := wasmgo.Imports() - if err != nil { + if err := wasmgo.Bridge.Run(); err != nil { log.Fatal(err) } - - // Instantiates the WebAssembly module. - instance, err := wasm.NewInstanceWithImports(bytes, imports) - if err != nil { - log.Fatal(err) - } - defer instance.Close() - - fmt.Println(instance.Exports) } diff --git a/simple/prog/main.go b/simple/prog/main.go index 800066d..90077cd 100644 --- a/simple/prog/main.go +++ b/simple/prog/main.go @@ -7,12 +7,17 @@ import ( "syscall/js" ) -func printWasm(v []js.Value) { +func printWasm(this js.Value, v []js.Value) interface{} { fmt.Println("Hello from WASM", v) + return nil } func main() { - js.Global().Set("printWasm", js.NewCallback(printWasm)) + c := make(chan struct{}, 0) + fmt.Println("WASM Go Initialized") + + // register functions + js.Global().Set("printWasm", js.FuncOf(printWasm)) fmt.Println("Done...") - <-make(chan struct{}) + <-c } diff --git a/simple/prog/main.wasm b/simple/prog/main.wasm index 3112566..805cb83 100755 Binary files a/simple/prog/main.wasm and b/simple/prog/main.wasm differ