working go wasm bridge
This commit is contained in:
		
							parent
							
								
									d528eeada8
								
							
						
					
					
						commit
						5a771cc80d
					
				
							
								
								
									
										87
									
								
								bridge.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								bridge.go
									
									
									
									
									
										Normal file
									
								
							@ -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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user