working go wasm bridge

pull/2/head
vedhavyas 2019-08-07 12:47:59 +02:00
parent d528eeada8
commit 5a771cc80d
No known key found for this signature in database
GPG Key ID: 317BF0923E3EB7E5
5 changed files with 133 additions and 29 deletions

87
bridge.go 100644
View File

@ -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)
}

View File

@ -22,11 +22,16 @@ extern void valueNew(void *context, int32_t a);
extern void valueLength(void *context, int32_t a); extern void valueLength(void *context, int32_t a);
extern void valuePrepareString(void *context, int32_t a); extern void valuePrepareString(void *context, int32_t a);
extern void valueLoadString(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 "C"
import ( import (
"crypto/rand"
"encoding/binary"
"fmt" "fmt"
"log" "log"
"time"
"unsafe" "unsafe"
"github.com/wasmerio/go-ext-wasm/wasmer" "github.com/wasmerio/go-ext-wasm/wasmer"
@ -39,17 +44,21 @@ func debug(ctx unsafe.Pointer, a int32) {
//export wexit //export wexit
func wexit(ctx unsafe.Pointer, a int32) { 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 //export wwrite
func wwrite(ctx unsafe.Pointer, a int32) { func wwrite(ctx unsafe.Pointer, a int32) {
fmt.Println("wasm write") fmt.Println("wasm write", a)
} }
//export nanotime //export nanotime
func nanotime(ctx unsafe.Pointer, a int32) { func nanotime(ctx unsafe.Pointer, a int32) {
fmt.Println("nano time") n := time.Now().UnixNano()
Bridge.setInt64(a+8, n)
} }
//export walltime //export walltime
@ -69,7 +78,11 @@ func clearScheduledCallback(ctx unsafe.Pointer, a int32) {
//export getRandomData //export getRandomData
func getRandomData(ctx unsafe.Pointer, a int32) { 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 //export stringVal
@ -79,7 +92,8 @@ func stringVal(ctx unsafe.Pointer, a int32) {
//export valueGet //export valueGet
func valueGet(ctx unsafe.Pointer, a int32) { func valueGet(ctx unsafe.Pointer, a int32) {
fmt.Println("valueGet") str := Bridge.loadString(a + 16)
fmt.Println("valueGet", str)
} }
//export valueSet //export valueSet
@ -127,9 +141,19 @@ func valueLoadString(ctx unsafe.Pointer, a int32) {
fmt.Println("valueLoadString") fmt.Println("valueLoadString")
} }
// Imports returns wasm go specific imports //export scheduleTimeoutEvent
func Imports() (*wasmer.Imports, error) { func scheduleTimeoutEvent(ctx unsafe.Pointer, a int32) {
imps := wasmer.NewImports().Namespace("go") 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 { var is = []struct {
name string name string
imp interface{} imp interface{}
@ -143,6 +167,8 @@ func Imports() (*wasmer.Imports, error) {
{"runtime.scheduleCallback", scheduleCallback, C.scheduleCallback}, {"runtime.scheduleCallback", scheduleCallback, C.scheduleCallback},
{"runtime.clearScheduledCallback", clearScheduledCallback, C.clearScheduledCallback}, {"runtime.clearScheduledCallback", clearScheduledCallback, C.clearScheduledCallback},
{"runtime.getRandomData", getRandomData, C.getRandomData}, {"runtime.getRandomData", getRandomData, C.getRandomData},
{"runtime.scheduleTimeoutEvent", scheduleTimeoutEvent, C.scheduleTimeoutEvent},
{"runtime.clearTimeoutEvent", clearTimeoutEvent, C.clearTimeoutEvent},
{"syscall/js.stringVal", stringVal, C.stringVal}, {"syscall/js.stringVal", stringVal, C.stringVal},
{"syscall/js.valueGet", valueGet, C.valueGet}, {"syscall/js.valueGet", valueGet, C.valueGet},
{"syscall/js.valueSet", valueSet, C.valueSet}, {"syscall/js.valueSet", valueSet, C.valueSet},
@ -160,9 +186,9 @@ func Imports() (*wasmer.Imports, error) {
for _, imp := range is { for _, imp := range is {
imps, err = imps.Append(imp.name, imp.imp, imp.cgo) imps, err = imps.Append(imp.name, imp.imp, imp.cgo)
if err != nil { if err != nil {
return nil, err return err
} }
} }
return imps, nil return nil
} }

View File

@ -1,32 +1,18 @@
package main package main
import "C"
import ( import (
"fmt"
"log" "log"
wasmgo "github.com/vedhavyas/wasm" wasmgo "github.com/vedhavyas/wasm"
wasm "github.com/wasmerio/go-ext-wasm/wasmer"
) )
func main() { func main() {
// Reads the WebAssembly module as bytes. err := wasmgo.Bridge.InitWASM("./simple/prog/main.wasm", nil)
bytes, err := wasm.ReadBytes("./simple/prog/main.wasm")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
imports, err := wasmgo.Imports() if err := wasmgo.Bridge.Run(); err != nil {
if err != nil {
log.Fatal(err) 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)
} }

View File

@ -7,12 +7,17 @@ import (
"syscall/js" "syscall/js"
) )
func printWasm(v []js.Value) { func printWasm(this js.Value, v []js.Value) interface{} {
fmt.Println("Hello from WASM", v) fmt.Println("Hello from WASM", v)
return nil
} }
func main() { 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...") fmt.Println("Done...")
<-make(chan struct{}) <-c
} }

Binary file not shown.