From 4aefd0446ff70f178aa150e13a33ee65918ac2e3 Mon Sep 17 00:00:00 2001 From: vedhavyas Date: Tue, 13 Aug 2019 17:11:23 +0200 Subject: [PATCH] update bridge --- bridge.go | 101 ++++++++++++++++++++++++++++++++++-------- imports.go | 77 +++++++++++++++++--------------- simple/caller/main.go | 5 ++- 3 files changed, 127 insertions(+), 56 deletions(-) diff --git a/bridge.go b/bridge.go index 50377e0..011b403 100644 --- a/bridge.go +++ b/bridge.go @@ -2,35 +2,51 @@ package wasm import ( "encoding/binary" + "fmt" + "math" + "sync" + "unsafe" "github.com/wasmerio/go-ext-wasm/wasmer" ) -func init() { - Bridge = new(bridge) +var undefined = &struct{}{} +var bridges = map[string]*Bridge{} +var mu sync.RWMutex // to protect bridges + +type context struct { + n string } -// Bridge connects go wasm builds -var Bridge *bridge +func setBridge(b *Bridge) unsafe.Pointer { + mu.Lock() + defer mu.Unlock() + bridges[b.name] = b + return unsafe.Pointer(&context{n: b.name}) +} -type bridge struct { +func getBridge(ctx unsafe.Pointer) *Bridge { + ictx := wasmer.IntoInstanceContext(ctx) + c := (*context)(ictx.Data()) + mu.RLock() + defer mu.RUnlock() + return bridges[c.n] +} + +type Bridge struct { + name string 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 - } - +func (b *Bridge) InitWASMBytes(name string, bytes []byte, imports *wasmer.Imports) error { if imports == nil { imports = wasmer.NewImports() } - err = b.addImports(imports) + b.name = name + err := b.addImports(imports) if err != nil { return err } @@ -41,11 +57,21 @@ func (b *bridge) InitWASM(file string, imports *wasmer.Imports) (err error) { } b.instance = inst + inst.SetContextData(setBridge(b)) return nil } +func (b *Bridge) InitWASM(name, file string, imports *wasmer.Imports) (err error) { + bytes, err := wasmer.ReadBytes(file) + if err != nil { + return err + } + + return b.InitWASMBytes(name, bytes, imports) +} + // Run start the wasm instance. -func (b *bridge) Run() error { +func (b *Bridge) Run() error { defer b.instance.Close() run := b.instance.Exports["run"] @@ -62,26 +88,65 @@ func (b *bridge) Run() error { } } + fmt.Printf("WASM exited with code: %v\n", b.exitCode) return nil } -func (b *bridge) mem() []byte { +func (b *Bridge) mem() []byte { return b.instance.Memory.Data() } -func (b bridge) setInt64(offset int32, v int64) { +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 { +func (b Bridge) setUint64(offset int32, v uint64) { + mem := b.mem() + binary.LittleEndian.PutUint64(mem[offset:], v) +} + +func (b Bridge) getUnit64(offset int32) uint64 { + mem := b.mem() + return binary.LittleEndian.Uint64(mem[offset+0:]) +} + +func (b Bridge) setFloat64(offset int32, v float64) { + uf := math.Float64bits(v) + b.setUint64(offset, uf) +} + +func (b Bridge) getFloat64(offset int32) float64 { + uf := b.getUnit64(offset) + return math.Float64frombits(uf) +} + +func (b Bridge) getUint32(offset int32) uint32 { + return binary.LittleEndian.Uint32(b.mem()[offset+0:]) +} + +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 { +func (b Bridge) loadString(addr int32) string { d := b.loadSlice(addr) return string(d) } + +func (b Bridge) loadValue(addr int32) interface{} { + f := b.getFloat64(addr) + if f == 0 { + return undefined + } + + if !math.IsNaN(f) { + return f + } + + // return value instead of uint32 + return b.getUint32(addr) +} diff --git a/imports.go b/imports.go index 8ac4560..a6143ae 100644 --- a/imports.go +++ b/imports.go @@ -38,47 +38,47 @@ import ( ) //export debug -func debug(ctx unsafe.Pointer, a int32) { - log.Println(a) +func debug(ctx unsafe.Pointer, sp int32) { + log.Println(sp) } //export wexit -func wexit(ctx unsafe.Pointer, a int32) { - Bridge.vmExit = true - mem := Bridge.mem() - Bridge.exitCode = int(binary.LittleEndian.Uint32(mem[a+8:])) - fmt.Println("Wasm exited with code", Bridge.exitCode) +func wexit(ctx unsafe.Pointer, sp int32) { + b := getBridge(ctx) + b.vmExit = true + mem := b.mem() + b.exitCode = int(binary.LittleEndian.Uint32(mem[sp+8:])) } //export wwrite -func wwrite(ctx unsafe.Pointer, a int32) { - fmt.Println("wasm write", a) +func wwrite(ctx unsafe.Pointer, sp int32) { + fmt.Println("wasm write", sp) } //export nanotime -func nanotime(ctx unsafe.Pointer, a int32) { +func nanotime(ctx unsafe.Pointer, sp int32) { n := time.Now().UnixNano() - Bridge.setInt64(a+8, n) + getBridge(ctx).setInt64(sp+8, n) } //export walltime -func walltime(ctx unsafe.Pointer, a int32) { +func walltime(ctx unsafe.Pointer, sp int32) { fmt.Println("wall time") } //export scheduleCallback -func scheduleCallback(ctx unsafe.Pointer, a int32) { +func scheduleCallback(ctx unsafe.Pointer, sp int32) { fmt.Println("schedule callback") } //export clearScheduledCallback -func clearScheduledCallback(ctx unsafe.Pointer, a int32) { +func clearScheduledCallback(ctx unsafe.Pointer, sp int32) { fmt.Println("clear scheduled callback") } //export getRandomData -func getRandomData(ctx unsafe.Pointer, a int32) { - s := Bridge.loadSlice(a + 8) +func getRandomData(ctx unsafe.Pointer, sp int32) { + s := getBridge(ctx).loadSlice(sp + 8) _, err := rand.Read(s) if err != nil { fmt.Println("failed: getRandomData", err) @@ -86,73 +86,78 @@ func getRandomData(ctx unsafe.Pointer, a int32) { } //export stringVal -func stringVal(ctx unsafe.Pointer, a int32) { +func stringVal(ctx unsafe.Pointer, sp int32) { fmt.Println("stringVal") } //export valueGet -func valueGet(ctx unsafe.Pointer, a int32) { - str := Bridge.loadString(a + 16) - fmt.Println("valueGet", str) +func valueGet(ctx unsafe.Pointer, sp int32) { + b := getBridge(ctx) + str := b.loadString(sp + 16) + val := b.loadValue(sp + 8) + fmt.Println("valueGet", str, val) } //export valueSet -func valueSet(ctx unsafe.Pointer, a int32) { - fmt.Println("valueSet") +func valueSet(ctx unsafe.Pointer, sp int32) { + str := getBridge(ctx).loadString(sp + 16) + fmt.Println("valueSet", str) } //export valueIndex -func valueIndex(ctx unsafe.Pointer, a int32) { +func valueIndex(ctx unsafe.Pointer, sp int32) { fmt.Println("valueIndex") } //export valueSetIndex -func valueSetIndex(ctx unsafe.Pointer, a int32) { +func valueSetIndex(ctx unsafe.Pointer, sp int32) { fmt.Println("valueSetIndex") } //export valueCall -func valueCall(ctx unsafe.Pointer, a int32) { - fmt.Println("valueCall") +func valueCall(ctx unsafe.Pointer, sp int32) { + str := getBridge(ctx).loadString(sp + 16) + fmt.Println("valueCall", str) } //export valueInvoke -func valueInvoke(ctx unsafe.Pointer, a int32) { +func valueInvoke(ctx unsafe.Pointer, sp int32) { fmt.Println("valueInvoke") } //export valueNew -func valueNew(ctx unsafe.Pointer, a int32) { - fmt.Println("valueNew") +func valueNew(ctx unsafe.Pointer, sp int32) { + str := getBridge(ctx).loadString(sp + 16) + fmt.Println("valueNew", str) } //export valueLength -func valueLength(ctx unsafe.Pointer, a int32) { +func valueLength(ctx unsafe.Pointer, sp int32) { fmt.Println("valueLength") } //export valuePrepareString -func valuePrepareString(ctx unsafe.Pointer, a int32) { +func valuePrepareString(ctx unsafe.Pointer, sp int32) { fmt.Println("valuePrepareString") } //export valueLoadString -func valueLoadString(ctx unsafe.Pointer, a int32) { +func valueLoadString(ctx unsafe.Pointer, sp int32) { fmt.Println("valueLoadString") } //export scheduleTimeoutEvent -func scheduleTimeoutEvent(ctx unsafe.Pointer, a int32) { +func scheduleTimeoutEvent(ctx unsafe.Pointer, sp int32) { fmt.Println("scheduleTimeoutEvent") } //export clearTimeoutEvent -func clearTimeoutEvent(ctx unsafe.Pointer, a int32) { +func clearTimeoutEvent(ctx unsafe.Pointer, sp int32) { fmt.Println("clearTimeoutEvent") } -// addImports adds go bridge imports in "go" namespace. -func (b *bridge) addImports(imps *wasmer.Imports) error { +// 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 diff --git a/simple/caller/main.go b/simple/caller/main.go index 9c6f10e..61070aa 100644 --- a/simple/caller/main.go +++ b/simple/caller/main.go @@ -7,12 +7,13 @@ import ( ) func main() { - err := wasmgo.Bridge.InitWASM("./simple/prog/main.wasm", nil) + b := wasmgo.Bridge{} + err := b.InitWASM("test", "./simple/prog/main.wasm", nil) if err != nil { log.Fatal(err) } - if err := wasmgo.Bridge.Run(); err != nil { + if err := b.Run(); err != nil { log.Fatal(err) } }