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

View File

@ -1,36 +1,51 @@
package main
import (
"context"
"log"
"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) {
log.Println("In Go", args)
return b.CallFunc("addition", args)
}
}
func main() {
b, err := wasm.BridgeFromFile("test", "./examples/wasm/main.wasm", nil)
func multiply(b *wasm.Bridge, a int) (int, error) {
m, err := b.CallFunc("multiplier", 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 {
panic(err)
}
init, done := make(chan error), make(chan bool)
go b.Run(init, done)
err = b.SetFunc("addProxy", addProxy(b))
if err != nil {
panic(err)
}
init := make(chan error)
ctx, cancF := context.WithCancel(context.Background())
defer cancF()
go b.Run(ctx, init)
err = <-init
if err != nil {
panic(err)
}
<-done
log.Println("wasm exited", err)
mul, err := multiply(b, 10)
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
}
func multiplier(this js.Value, args []js.Value) interface{} {
return 10
}
func main() {
ch := make(chan bool)
// register functions
fun := js.FuncOf(addition)
js.Global().Set("addition", fun)
js.Global().Set("addition", js.FuncOf(addition))
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())
<-ch
}

Binary file not shown.

View File

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