working go wasm bridge
parent
d528eeada8
commit
5a771cc80d
|
@ -0,0 +1,87 @@
|
|||
package wasm
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/wasmerio/go-ext-wasm/wasmer"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Bridge = new(bridge)
|
||||
}
|
||||
|
||||
// Bridge connects go wasm builds
|
||||
var Bridge *bridge
|
||||
|
||||
type bridge struct {
|
||||
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
|
||||
}
|
||||
|
||||
if imports == nil {
|
||||
imports = wasmer.NewImports()
|
||||
}
|
||||
|
||||
err = b.addImports(imports)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
inst, err := wasmer.NewInstanceWithImports(bytes, imports)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b.instance = inst
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run start the wasm instance.
|
||||
func (b *bridge) Run() error {
|
||||
defer b.instance.Close()
|
||||
|
||||
run := b.instance.Exports["run"]
|
||||
resume := b.instance.Exports["resume"]
|
||||
_, err := run(0, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for !b.vmExit {
|
||||
_, err = resume()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *bridge) mem() []byte {
|
||||
return b.instance.Memory.Data()
|
||||
}
|
||||
|
||||
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 {
|
||||
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 {
|
||||
d := b.loadSlice(addr)
|
||||
return string(d)
|
||||
}
|
46
imports.go
46
imports.go
|
@ -22,11 +22,16 @@ extern void valueNew(void *context, int32_t a);
|
|||
extern void valueLength(void *context, int32_t a);
|
||||
extern void valuePrepareString(void *context, int32_t a);
|
||||
extern void valueLoadString(void *context, int32_t a);
|
||||
extern void scheduleTimeoutEvent(void *context, int32_t a);
|
||||
extern void clearTimeoutEvent(void *context, int32_t a);
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/wasmerio/go-ext-wasm/wasmer"
|
||||
|
@ -39,17 +44,21 @@ func debug(ctx unsafe.Pointer, a int32) {
|
|||
|
||||
//export wexit
|
||||
func wexit(ctx unsafe.Pointer, a int32) {
|
||||
fmt.Println("wasm exit")
|
||||
Bridge.vmExit = true
|
||||
mem := Bridge.mem()
|
||||
Bridge.exitCode = int(binary.LittleEndian.Uint32(mem[a+8:]))
|
||||
fmt.Println("Wasm exited with code", Bridge.exitCode)
|
||||
}
|
||||
|
||||
//export wwrite
|
||||
func wwrite(ctx unsafe.Pointer, a int32) {
|
||||
fmt.Println("wasm write")
|
||||
fmt.Println("wasm write", a)
|
||||
}
|
||||
|
||||
//export nanotime
|
||||
func nanotime(ctx unsafe.Pointer, a int32) {
|
||||
fmt.Println("nano time")
|
||||
n := time.Now().UnixNano()
|
||||
Bridge.setInt64(a+8, n)
|
||||
}
|
||||
|
||||
//export walltime
|
||||
|
@ -69,7 +78,11 @@ func clearScheduledCallback(ctx unsafe.Pointer, a int32) {
|
|||
|
||||
//export getRandomData
|
||||
func getRandomData(ctx unsafe.Pointer, a int32) {
|
||||
fmt.Println("getRandomData")
|
||||
s := Bridge.loadSlice(a + 8)
|
||||
_, err := rand.Read(s)
|
||||
if err != nil {
|
||||
fmt.Println("failed: getRandomData", err)
|
||||
}
|
||||
}
|
||||
|
||||
//export stringVal
|
||||
|
@ -79,7 +92,8 @@ func stringVal(ctx unsafe.Pointer, a int32) {
|
|||
|
||||
//export valueGet
|
||||
func valueGet(ctx unsafe.Pointer, a int32) {
|
||||
fmt.Println("valueGet")
|
||||
str := Bridge.loadString(a + 16)
|
||||
fmt.Println("valueGet", str)
|
||||
}
|
||||
|
||||
//export valueSet
|
||||
|
@ -127,9 +141,19 @@ func valueLoadString(ctx unsafe.Pointer, a int32) {
|
|||
fmt.Println("valueLoadString")
|
||||
}
|
||||
|
||||
// Imports returns wasm go specific imports
|
||||
func Imports() (*wasmer.Imports, error) {
|
||||
imps := wasmer.NewImports().Namespace("go")
|
||||
//export scheduleTimeoutEvent
|
||||
func scheduleTimeoutEvent(ctx unsafe.Pointer, a int32) {
|
||||
fmt.Println("scheduleTimeoutEvent")
|
||||
}
|
||||
|
||||
//export clearTimeoutEvent
|
||||
func clearTimeoutEvent(ctx unsafe.Pointer, a int32) {
|
||||
fmt.Println("clearTimeoutEvent")
|
||||
}
|
||||
|
||||
// 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
|
||||
imp interface{}
|
||||
|
@ -143,6 +167,8 @@ func Imports() (*wasmer.Imports, error) {
|
|||
{"runtime.scheduleCallback", scheduleCallback, C.scheduleCallback},
|
||||
{"runtime.clearScheduledCallback", clearScheduledCallback, C.clearScheduledCallback},
|
||||
{"runtime.getRandomData", getRandomData, C.getRandomData},
|
||||
{"runtime.scheduleTimeoutEvent", scheduleTimeoutEvent, C.scheduleTimeoutEvent},
|
||||
{"runtime.clearTimeoutEvent", clearTimeoutEvent, C.clearTimeoutEvent},
|
||||
{"syscall/js.stringVal", stringVal, C.stringVal},
|
||||
{"syscall/js.valueGet", valueGet, C.valueGet},
|
||||
{"syscall/js.valueSet", valueSet, C.valueSet},
|
||||
|
@ -160,9 +186,9 @@ func Imports() (*wasmer.Imports, error) {
|
|||
for _, imp := range is {
|
||||
imps, err = imps.Append(imp.name, imp.imp, imp.cgo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return imps, nil
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,32 +1,18 @@
|
|||
package main
|
||||
|
||||
import "C"
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
wasmgo "github.com/vedhavyas/wasm"
|
||||
wasm "github.com/wasmerio/go-ext-wasm/wasmer"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Reads the WebAssembly module as bytes.
|
||||
bytes, err := wasm.ReadBytes("./simple/prog/main.wasm")
|
||||
err := wasmgo.Bridge.InitWASM("./simple/prog/main.wasm", nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
imports, err := wasmgo.Imports()
|
||||
if err != nil {
|
||||
if err := wasmgo.Bridge.Run(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Instantiates the WebAssembly module.
|
||||
instance, err := wasm.NewInstanceWithImports(bytes, imports)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer instance.Close()
|
||||
|
||||
fmt.Println(instance.Exports)
|
||||
}
|
||||
|
|
|
@ -7,12 +7,17 @@ import (
|
|||
"syscall/js"
|
||||
)
|
||||
|
||||
func printWasm(v []js.Value) {
|
||||
func printWasm(this js.Value, v []js.Value) interface{} {
|
||||
fmt.Println("Hello from WASM", v)
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
js.Global().Set("printWasm", js.NewCallback(printWasm))
|
||||
c := make(chan struct{}, 0)
|
||||
fmt.Println("WASM Go Initialized")
|
||||
|
||||
// register functions
|
||||
js.Global().Set("printWasm", js.FuncOf(printWasm))
|
||||
fmt.Println("Done...")
|
||||
<-make(chan struct{})
|
||||
<-c
|
||||
}
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue