locks
parent
2a22ca2a7f
commit
6029286b43
39
bridge.go
39
bridge.go
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
24
imports.go
24
imports.go
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue