pull/2/head
vedhavyas 2019-08-21 19:24:07 -07:00
parent 2a22ca2a7f
commit 6029286b43
No known key found for this signature in database
GPG Key ID: 317BF0923E3EB7E5
5 changed files with 74 additions and 32 deletions

View File

@ -1,8 +1,10 @@
package wasm package wasm
import ( import (
"context"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"log"
"math" "math"
"reflect" "reflect"
"sync" "sync"
@ -16,7 +18,7 @@ import (
var undefined = &struct{}{} var undefined = &struct{}{}
var bridges = map[string]*Bridge{} var bridges = map[string]*Bridge{}
var mu sync.RWMutex // to protect bridges var mu sync.RWMutex // to protect bridges
type context struct{ n string } type bctx struct{ n string }
func getCtxData(b *Bridge) (unsafe.Pointer, error) { func getCtxData(b *Bridge) (unsafe.Pointer, error) {
mu.Lock() mu.Lock()
@ -26,12 +28,12 @@ func getCtxData(b *Bridge) (unsafe.Pointer, error) {
} }
bridges[b.name] = b bridges[b.name] = b
return unsafe.Pointer(&context{n: b.name}), nil return unsafe.Pointer(&bctx{n: b.name}), nil
} }
func getBridge(ctx unsafe.Pointer) *Bridge { func getBridge(ctx unsafe.Pointer) *Bridge {
ictx := wasmer.IntoInstanceContext(ctx) ictx := wasmer.IntoInstanceContext(ctx)
c := (*context)(ictx.Data()) c := (*bctx)(ictx.Data())
mu.RLock() mu.RLock()
defer mu.RUnlock() defer mu.RUnlock()
return bridges[c.n] return bridges[c.n]
@ -40,12 +42,13 @@ func getBridge(ctx unsafe.Pointer) *Bridge {
type Bridge struct { type Bridge struct {
name string name string
instance wasmer.Instance instance wasmer.Instance
done chan bool
exitCode int exitCode int
values []interface{} values []interface{}
valuesMu sync.RWMutex
refs map[interface{}]int refs map[interface{}]int
memory []byte memory []byte
exited bool exited bool
cancF context.CancelFunc
} }
func BridgeFromBytes(name string, bytes []byte, imports *wasmer.Imports) (*Bridge, error) { func BridgeFromBytes(name string, bytes []byte, imports *wasmer.Imports) (*Bridge, error) {
@ -175,11 +178,10 @@ func (b *Bridge) check() {
} }
// Run start the wasm instance. // Run start the wasm instance.
func (b *Bridge) Run(init chan error, done chan bool) { func (b *Bridge) Run(ctx context.Context, init chan error) {
b.check() b.check()
defer b.instance.Close() defer b.instance.Close()
b.done = done
run := b.instance.Exports["run"] run := b.instance.Exports["run"]
_, err := run(0, 0) _, err := run(0, 0)
if err != nil { if err != nil {
@ -187,9 +189,15 @@ func (b *Bridge) Run(init chan error, done chan bool) {
return return
} }
ctx, cancF := context.WithCancel(ctx)
b.cancF = cancF
init <- nil init <- nil
<-b.done select {
fmt.Printf("WASM exited with code: %v\n", b.exitCode) case <-ctx.Done():
log.Printf("stopping WASM[%s] instance...\n", b.name)
b.exited = true
return
}
} }
func (b *Bridge) mem() []byte { func (b *Bridge) mem() []byte {
@ -297,6 +305,9 @@ func (b *Bridge) loadValue(addr int32) interface{} {
return f return f
} }
b.valuesMu.RLock()
defer b.valuesMu.RUnlock()
return b.values[b.getUint32(addr)] return b.values[b.getUint32(addr)]
} }
@ -353,9 +364,11 @@ func (b *Bridge) storeValue(addr int32, v interface{}) {
ref, ok := b.refs[v] ref, ok := b.refs[v]
if !ok { if !ok {
b.valuesMu.RLock()
ref = len(b.values) ref = len(b.values)
b.values = append(b.values, v) b.values = append(b.values, v)
b.refs[v] = ref b.refs[v] = ref
b.valuesMu.RUnlock()
} }
typeFlag := 0 typeFlag := 0
@ -422,7 +435,9 @@ type funcWrapper struct {
} }
func (b *Bridge) makeFuncWrapper(id, this interface{}, args *[]interface{}) (interface{}, error) { func (b *Bridge) makeFuncWrapper(id, this interface{}, args *[]interface{}) (interface{}, error) {
b.valuesMu.RLock()
goObj := b.values[7].(*object) goObj := b.values[7].(*object)
b.valuesMu.RUnlock()
event := propObject("_pendingEvent", map[string]interface{}{ event := propObject("_pendingEvent", map[string]interface{}{
"id": id, "id": id,
"this": nil, "this": nil,
@ -440,15 +455,21 @@ func (b *Bridge) makeFuncWrapper(id, this interface{}, args *[]interface{}) (int
func (b *Bridge) CallFunc(fn string, args []interface{}) (interface{}, error) { func (b *Bridge) CallFunc(fn string, args []interface{}) (interface{}, error) {
b.check() b.check()
b.valuesMu.RLock()
fw, ok := b.values[5].(*object).props[fn] fw, ok := b.values[5].(*object).props[fn]
if !ok { if !ok {
return nil, fmt.Errorf("missing function: %v", fn) return nil, fmt.Errorf("missing function: %v", fn)
} }
return b.makeFuncWrapper(fw.(*funcWrapper).id, b.values[7], &args) this := b.values[7]
b.valuesMu.RUnlock()
return b.makeFuncWrapper(fw.(*funcWrapper).id, this, &args)
} }
func (b *Bridge) SetFunc(fname string, fn Func) error { func (b *Bridge) SetFunc(fname string, fn Func) error {
b.valuesMu.RLock()
defer b.valuesMu.RUnlock()
b.values[5].(*object).props[fname] = &fn b.values[5].(*object).props[fname] = &fn
return nil return nil
} }

View File

@ -1,36 +1,51 @@
package main package main
import ( import (
"context"
"log" "log"
"github.com/vedhavyas/go-wasm" "github.com/vedhavyas/go-wasm"
) )
func proxy(b *wasm.Bridge) wasm.Func { func addProxy(b *wasm.Bridge) wasm.Func {
return func(args []interface{}) (i interface{}, e error) { return func(args []interface{}) (i interface{}, e error) {
log.Println("In Go", args) log.Println("In Go", args)
return b.CallFunc("addition", args) return b.CallFunc("addition", args)
} }
} }
func main() { func multiply(b *wasm.Bridge, a int) (int, error) {
b, err := wasm.BridgeFromFile("test", "./examples/wasm/main.wasm", nil) m, err := b.CallFunc("multiplier", nil)
if err != nil { if err != nil {
log.Fatal(err) return 0, err
} }
err = b.SetFunc("proxy", proxy(b)) return a * int(m.(float64)), nil
}
func main() {
b, err := wasm.BridgeFromFile("test", "./examples/wasm/main.wasm", nil)
if err != nil { if err != nil {
panic(err) panic(err)
} }
init, done := make(chan error), make(chan bool) err = b.SetFunc("addProxy", addProxy(b))
go b.Run(init, done) if err != nil {
panic(err)
}
init := make(chan error)
ctx, cancF := context.WithCancel(context.Background())
defer cancF()
go b.Run(ctx, init)
err = <-init err = <-init
if err != nil { if err != nil {
panic(err) panic(err)
} }
<-done mul, err := multiply(b, 10)
log.Println("wasm exited", err) if err != nil {
panic(err)
}
log.Printf("Multiplier: %v\n", mul)
} }

View File

@ -13,14 +13,18 @@ func addition(this js.Value, args []js.Value) interface{} {
return a + b return a + b
} }
func multiplier(this js.Value, args []js.Value) interface{} {
return 10
}
func main() { func main() {
ch := make(chan bool) ch := make(chan bool)
// register functions // register functions
fun := js.FuncOf(addition) js.Global().Set("addition", js.FuncOf(addition))
js.Global().Set("addition", fun) js.Global().Set("multiplier", js.FuncOf(multiplier))
res := js.Global().Get("proxy").Invoke(1, 2) res := js.Global().Get("addProxy").Invoke(1, 2)
log.Printf("1 + 2 = %d\n", res.Int()) log.Printf("1 + 2 = %d\n", res.Int())
<-ch <-ch
} }

Binary file not shown.

View File

@ -29,6 +29,7 @@ import "C"
import ( import (
"crypto/rand" "crypto/rand"
"fmt" "fmt"
"log"
"reflect" "reflect"
"syscall" "syscall"
"time" "time"
@ -38,16 +39,15 @@ import (
) )
//export debug //export debug
func debug(ctx unsafe.Pointer, sp int32) { func debug(_ unsafe.Pointer, sp int32) {
fmt.Println(sp) log.Println(sp)
} }
//export wexit //export wexit
func wexit(ctx unsafe.Pointer, sp int32) { func wexit(ctx unsafe.Pointer, sp int32) {
b := getBridge(ctx) b := getBridge(ctx)
b.exitCode = int(b.getUint32(sp + 8)) b.exitCode = int(b.getUint32(sp + 8))
b.exited = true b.cancF()
close(b.done)
} }
//export wwrite //export wwrite
@ -56,7 +56,10 @@ func wwrite(ctx unsafe.Pointer, sp int32) {
fd := int(b.getInt64(sp + 8)) fd := int(b.getInt64(sp + 8))
p := int(b.getInt64(sp + 16)) p := int(b.getInt64(sp + 16))
l := int(b.getInt32(sp + 24)) l := int(b.getInt32(sp + 24))
syscall.Write(fd, b.mem()[p:p+l]) _, err := syscall.Write(fd, b.mem()[p:p+l])
if err != nil {
panic(fmt.Errorf("wasm-write: %v", err))
}
} }
//export nanotime //export nanotime
@ -76,12 +79,12 @@ func walltime(ctx unsafe.Pointer, sp int32) {
} }
//export scheduleCallback //export scheduleCallback
func scheduleCallback(ctx unsafe.Pointer, sp int32) { func scheduleCallback(_ unsafe.Pointer, _ int32) {
panic("schedule callback") panic("schedule callback")
} }
//export clearScheduledCallback //export clearScheduledCallback
func clearScheduledCallback(ctx unsafe.Pointer, sp int32) { func clearScheduledCallback(_ unsafe.Pointer, _ int32) {
panic("clear scheduled callback") panic("clear scheduled callback")
} }
@ -89,7 +92,6 @@ func clearScheduledCallback(ctx unsafe.Pointer, sp int32) {
func getRandomData(ctx unsafe.Pointer, sp int32) { func getRandomData(ctx unsafe.Pointer, sp int32) {
s := getBridge(ctx).loadSlice(sp + 8) s := getBridge(ctx).loadSlice(sp + 8)
_, err := rand.Read(s) _, err := rand.Read(s)
// TODO how to pass error?
if err != nil { if err != nil {
panic("failed: getRandomData") panic("failed: getRandomData")
} }
@ -146,7 +148,7 @@ func valueIndex(ctx unsafe.Pointer, sp int32) {
} }
//export valueSetIndex //export valueSetIndex
func valueSetIndex(ctx unsafe.Pointer, sp int32) { func valueSetIndex(_ unsafe.Pointer, _ int32) {
panic("valueSetIndex") panic("valueSetIndex")
} }
@ -234,12 +236,12 @@ func valueLoadString(ctx unsafe.Pointer, sp int32) {
} }
//export scheduleTimeoutEvent //export scheduleTimeoutEvent
func scheduleTimeoutEvent(ctx unsafe.Pointer, sp int32) { func scheduleTimeoutEvent(_ unsafe.Pointer, _ int32) {
panic("scheduleTimeoutEvent") panic("scheduleTimeoutEvent")
} }
//export clearTimeoutEvent //export clearTimeoutEvent
func clearTimeoutEvent(ctx unsafe.Pointer, sp int32) { func clearTimeoutEvent(_ unsafe.Pointer, _ int32) {
panic("clearTimeoutEvent") panic("clearTimeoutEvent")
} }