update bridge

pull/2/head
vedhavyas 2019-08-13 17:11:23 +02:00
parent 5a771cc80d
commit 4aefd0446f
No known key found for this signature in database
GPG Key ID: 317BF0923E3EB7E5
3 changed files with 127 additions and 56 deletions

101
bridge.go
View File

@ -2,35 +2,51 @@ package wasm
import ( import (
"encoding/binary" "encoding/binary"
"fmt"
"math"
"sync"
"unsafe"
"github.com/wasmerio/go-ext-wasm/wasmer" "github.com/wasmerio/go-ext-wasm/wasmer"
) )
func init() { var undefined = &struct{}{}
Bridge = new(bridge) var bridges = map[string]*Bridge{}
var mu sync.RWMutex // to protect bridges
type context struct {
n string
} }
// Bridge connects go wasm builds func setBridge(b *Bridge) unsafe.Pointer {
var Bridge *bridge 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 instance wasmer.Instance
vmExit bool vmExit bool
exitCode int exitCode int
} }
// GoBridge returns a new bridge. func (b *Bridge) InitWASMBytes(name string, bytes []byte, imports *wasmer.Imports) error {
func (b *bridge) InitWASM(file string, imports *wasmer.Imports) (err error) {
bytes, err := wasmer.ReadBytes(file)
if err != nil {
return err
}
if imports == nil { if imports == nil {
imports = wasmer.NewImports() imports = wasmer.NewImports()
} }
err = b.addImports(imports) b.name = name
err := b.addImports(imports)
if err != nil { if err != nil {
return err return err
} }
@ -41,11 +57,21 @@ func (b *bridge) InitWASM(file string, imports *wasmer.Imports) (err error) {
} }
b.instance = inst b.instance = inst
inst.SetContextData(setBridge(b))
return nil 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. // Run start the wasm instance.
func (b *bridge) Run() error { func (b *Bridge) Run() error {
defer b.instance.Close() defer b.instance.Close()
run := b.instance.Exports["run"] 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 return nil
} }
func (b *bridge) mem() []byte { func (b *Bridge) mem() []byte {
return b.instance.Memory.Data() return b.instance.Memory.Data()
} }
func (b bridge) setInt64(offset int32, v int64) { func (b Bridge) setInt64(offset int32, v int64) {
mem := b.mem() mem := b.mem()
binary.LittleEndian.PutUint64(mem[offset:], uint64(v)) 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() mem := b.mem()
array := binary.LittleEndian.Uint64(mem[addr+0:]) array := binary.LittleEndian.Uint64(mem[addr+0:])
length := binary.LittleEndian.Uint64(mem[addr+8:]) length := binary.LittleEndian.Uint64(mem[addr+8:])
return mem[array : array+length] return mem[array : array+length]
} }
func (b bridge) loadString(addr int32) string { func (b Bridge) loadString(addr int32) string {
d := b.loadSlice(addr) d := b.loadSlice(addr)
return string(d) 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)
}

View File

@ -38,47 +38,47 @@ import (
) )
//export debug //export debug
func debug(ctx unsafe.Pointer, a int32) { func debug(ctx unsafe.Pointer, sp int32) {
log.Println(a) log.Println(sp)
} }
//export wexit //export wexit
func wexit(ctx unsafe.Pointer, a int32) { func wexit(ctx unsafe.Pointer, sp int32) {
Bridge.vmExit = true b := getBridge(ctx)
mem := Bridge.mem() b.vmExit = true
Bridge.exitCode = int(binary.LittleEndian.Uint32(mem[a+8:])) mem := b.mem()
fmt.Println("Wasm exited with code", Bridge.exitCode) b.exitCode = int(binary.LittleEndian.Uint32(mem[sp+8:]))
} }
//export wwrite //export wwrite
func wwrite(ctx unsafe.Pointer, a int32) { func wwrite(ctx unsafe.Pointer, sp int32) {
fmt.Println("wasm write", a) fmt.Println("wasm write", sp)
} }
//export nanotime //export nanotime
func nanotime(ctx unsafe.Pointer, a int32) { func nanotime(ctx unsafe.Pointer, sp int32) {
n := time.Now().UnixNano() n := time.Now().UnixNano()
Bridge.setInt64(a+8, n) getBridge(ctx).setInt64(sp+8, n)
} }
//export walltime //export walltime
func walltime(ctx unsafe.Pointer, a int32) { func walltime(ctx unsafe.Pointer, sp int32) {
fmt.Println("wall time") fmt.Println("wall time")
} }
//export scheduleCallback //export scheduleCallback
func scheduleCallback(ctx unsafe.Pointer, a int32) { func scheduleCallback(ctx unsafe.Pointer, sp int32) {
fmt.Println("schedule callback") fmt.Println("schedule callback")
} }
//export clearScheduledCallback //export clearScheduledCallback
func clearScheduledCallback(ctx unsafe.Pointer, a int32) { func clearScheduledCallback(ctx unsafe.Pointer, sp int32) {
fmt.Println("clear scheduled callback") fmt.Println("clear scheduled callback")
} }
//export getRandomData //export getRandomData
func getRandomData(ctx unsafe.Pointer, a int32) { func getRandomData(ctx unsafe.Pointer, sp int32) {
s := Bridge.loadSlice(a + 8) s := getBridge(ctx).loadSlice(sp + 8)
_, err := rand.Read(s) _, err := rand.Read(s)
if err != nil { if err != nil {
fmt.Println("failed: getRandomData", err) fmt.Println("failed: getRandomData", err)
@ -86,73 +86,78 @@ func getRandomData(ctx unsafe.Pointer, a int32) {
} }
//export stringVal //export stringVal
func stringVal(ctx unsafe.Pointer, a int32) { func stringVal(ctx unsafe.Pointer, sp int32) {
fmt.Println("stringVal") fmt.Println("stringVal")
} }
//export valueGet //export valueGet
func valueGet(ctx unsafe.Pointer, a int32) { func valueGet(ctx unsafe.Pointer, sp int32) {
str := Bridge.loadString(a + 16) b := getBridge(ctx)
fmt.Println("valueGet", str) str := b.loadString(sp + 16)
val := b.loadValue(sp + 8)
fmt.Println("valueGet", str, val)
} }
//export valueSet //export valueSet
func valueSet(ctx unsafe.Pointer, a int32) { func valueSet(ctx unsafe.Pointer, sp int32) {
fmt.Println("valueSet") str := getBridge(ctx).loadString(sp + 16)
fmt.Println("valueSet", str)
} }
//export valueIndex //export valueIndex
func valueIndex(ctx unsafe.Pointer, a int32) { func valueIndex(ctx unsafe.Pointer, sp int32) {
fmt.Println("valueIndex") fmt.Println("valueIndex")
} }
//export valueSetIndex //export valueSetIndex
func valueSetIndex(ctx unsafe.Pointer, a int32) { func valueSetIndex(ctx unsafe.Pointer, sp int32) {
fmt.Println("valueSetIndex") fmt.Println("valueSetIndex")
} }
//export valueCall //export valueCall
func valueCall(ctx unsafe.Pointer, a int32) { func valueCall(ctx unsafe.Pointer, sp int32) {
fmt.Println("valueCall") str := getBridge(ctx).loadString(sp + 16)
fmt.Println("valueCall", str)
} }
//export valueInvoke //export valueInvoke
func valueInvoke(ctx unsafe.Pointer, a int32) { func valueInvoke(ctx unsafe.Pointer, sp int32) {
fmt.Println("valueInvoke") fmt.Println("valueInvoke")
} }
//export valueNew //export valueNew
func valueNew(ctx unsafe.Pointer, a int32) { func valueNew(ctx unsafe.Pointer, sp int32) {
fmt.Println("valueNew") str := getBridge(ctx).loadString(sp + 16)
fmt.Println("valueNew", str)
} }
//export valueLength //export valueLength
func valueLength(ctx unsafe.Pointer, a int32) { func valueLength(ctx unsafe.Pointer, sp int32) {
fmt.Println("valueLength") fmt.Println("valueLength")
} }
//export valuePrepareString //export valuePrepareString
func valuePrepareString(ctx unsafe.Pointer, a int32) { func valuePrepareString(ctx unsafe.Pointer, sp int32) {
fmt.Println("valuePrepareString") fmt.Println("valuePrepareString")
} }
//export valueLoadString //export valueLoadString
func valueLoadString(ctx unsafe.Pointer, a int32) { func valueLoadString(ctx unsafe.Pointer, sp int32) {
fmt.Println("valueLoadString") fmt.Println("valueLoadString")
} }
//export scheduleTimeoutEvent //export scheduleTimeoutEvent
func scheduleTimeoutEvent(ctx unsafe.Pointer, a int32) { func scheduleTimeoutEvent(ctx unsafe.Pointer, sp int32) {
fmt.Println("scheduleTimeoutEvent") fmt.Println("scheduleTimeoutEvent")
} }
//export clearTimeoutEvent //export clearTimeoutEvent
func clearTimeoutEvent(ctx unsafe.Pointer, a int32) { func clearTimeoutEvent(ctx unsafe.Pointer, sp int32) {
fmt.Println("clearTimeoutEvent") fmt.Println("clearTimeoutEvent")
} }
// addImports adds go bridge imports in "go" namespace. // addImports adds go Bridge imports in "go" namespace.
func (b *bridge) addImports(imps *wasmer.Imports) error { func (b *Bridge) addImports(imps *wasmer.Imports) error {
imps = imps.Namespace("go") imps = imps.Namespace("go")
var is = []struct { var is = []struct {
name string name string

View File

@ -7,12 +7,13 @@ import (
) )
func main() { 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 { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
if err := wasmgo.Bridge.Run(); err != nil { if err := b.Run(); err != nil {
log.Fatal(err) log.Fatal(err)
} }
} }