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 valueLength(void *context, int32_t a);
|
||||||
extern void valuePrepareString(void *context, int32_t a);
|
extern void valuePrepareString(void *context, int32_t a);
|
||||||
extern void valueLoadString(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 "C"
|
||||||
import (
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/wasmerio/go-ext-wasm/wasmer"
|
"github.com/wasmerio/go-ext-wasm/wasmer"
|
||||||
|
@ -39,17 +44,21 @@ func debug(ctx unsafe.Pointer, a int32) {
|
||||||
|
|
||||||
//export wexit
|
//export wexit
|
||||||
func wexit(ctx unsafe.Pointer, a int32) {
|
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
|
//export wwrite
|
||||||
func wwrite(ctx unsafe.Pointer, a int32) {
|
func wwrite(ctx unsafe.Pointer, a int32) {
|
||||||
fmt.Println("wasm write")
|
fmt.Println("wasm write", a)
|
||||||
}
|
}
|
||||||
|
|
||||||
//export nanotime
|
//export nanotime
|
||||||
func nanotime(ctx unsafe.Pointer, a int32) {
|
func nanotime(ctx unsafe.Pointer, a int32) {
|
||||||
fmt.Println("nano time")
|
n := time.Now().UnixNano()
|
||||||
|
Bridge.setInt64(a+8, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
//export walltime
|
//export walltime
|
||||||
|
@ -69,7 +78,11 @@ func clearScheduledCallback(ctx unsafe.Pointer, a int32) {
|
||||||
|
|
||||||
//export getRandomData
|
//export getRandomData
|
||||||
func getRandomData(ctx unsafe.Pointer, a int32) {
|
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
|
//export stringVal
|
||||||
|
@ -79,7 +92,8 @@ func stringVal(ctx unsafe.Pointer, a int32) {
|
||||||
|
|
||||||
//export valueGet
|
//export valueGet
|
||||||
func valueGet(ctx unsafe.Pointer, a int32) {
|
func valueGet(ctx unsafe.Pointer, a int32) {
|
||||||
fmt.Println("valueGet")
|
str := Bridge.loadString(a + 16)
|
||||||
|
fmt.Println("valueGet", str)
|
||||||
}
|
}
|
||||||
|
|
||||||
//export valueSet
|
//export valueSet
|
||||||
|
@ -127,9 +141,19 @@ func valueLoadString(ctx unsafe.Pointer, a int32) {
|
||||||
fmt.Println("valueLoadString")
|
fmt.Println("valueLoadString")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Imports returns wasm go specific imports
|
//export scheduleTimeoutEvent
|
||||||
func Imports() (*wasmer.Imports, error) {
|
func scheduleTimeoutEvent(ctx unsafe.Pointer, a int32) {
|
||||||
imps := wasmer.NewImports().Namespace("go")
|
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 {
|
var is = []struct {
|
||||||
name string
|
name string
|
||||||
imp interface{}
|
imp interface{}
|
||||||
|
@ -143,6 +167,8 @@ func Imports() (*wasmer.Imports, error) {
|
||||||
{"runtime.scheduleCallback", scheduleCallback, C.scheduleCallback},
|
{"runtime.scheduleCallback", scheduleCallback, C.scheduleCallback},
|
||||||
{"runtime.clearScheduledCallback", clearScheduledCallback, C.clearScheduledCallback},
|
{"runtime.clearScheduledCallback", clearScheduledCallback, C.clearScheduledCallback},
|
||||||
{"runtime.getRandomData", getRandomData, C.getRandomData},
|
{"runtime.getRandomData", getRandomData, C.getRandomData},
|
||||||
|
{"runtime.scheduleTimeoutEvent", scheduleTimeoutEvent, C.scheduleTimeoutEvent},
|
||||||
|
{"runtime.clearTimeoutEvent", clearTimeoutEvent, C.clearTimeoutEvent},
|
||||||
{"syscall/js.stringVal", stringVal, C.stringVal},
|
{"syscall/js.stringVal", stringVal, C.stringVal},
|
||||||
{"syscall/js.valueGet", valueGet, C.valueGet},
|
{"syscall/js.valueGet", valueGet, C.valueGet},
|
||||||
{"syscall/js.valueSet", valueSet, C.valueSet},
|
{"syscall/js.valueSet", valueSet, C.valueSet},
|
||||||
|
@ -160,9 +186,9 @@ func Imports() (*wasmer.Imports, error) {
|
||||||
for _, imp := range is {
|
for _, imp := range is {
|
||||||
imps, err = imps.Append(imp.name, imp.imp, imp.cgo)
|
imps, err = imps.Append(imp.name, imp.imp, imp.cgo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return imps, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +1,18 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "C"
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
wasmgo "github.com/vedhavyas/wasm"
|
wasmgo "github.com/vedhavyas/wasm"
|
||||||
wasm "github.com/wasmerio/go-ext-wasm/wasmer"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Reads the WebAssembly module as bytes.
|
err := wasmgo.Bridge.InitWASM("./simple/prog/main.wasm", nil)
|
||||||
bytes, err := wasm.ReadBytes("./simple/prog/main.wasm")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
imports, err := wasmgo.Imports()
|
if err := wasmgo.Bridge.Run(); err != nil {
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
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"
|
"syscall/js"
|
||||||
)
|
)
|
||||||
|
|
||||||
func printWasm(v []js.Value) {
|
func printWasm(this js.Value, v []js.Value) interface{} {
|
||||||
fmt.Println("Hello from WASM", v)
|
fmt.Println("Hello from WASM", v)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
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...")
|
fmt.Println("Done...")
|
||||||
<-make(chan struct{})
|
<-c
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue