go-wasm/imports.go

330 lines
8.1 KiB
Go
Raw Permalink Normal View History

2019-08-06 16:03:11 +03:00
package wasm
/*
#include <stdlib.h>
extern void debug(void *context, int32_t a);
extern void wexit(void *context, int32_t a);
extern void wwrite(void *context, int32_t a);
extern void nanotime(void *context, int32_t a);
extern void walltime(void *context, int32_t a);
extern void scheduleCallback(void *context, int32_t a);
extern void clearScheduledCallback(void *context, int32_t a);
extern void getRandomData(void *context, int32_t a);
extern void stringVal(void *context, int32_t a);
extern void valueGet(void *context, int32_t a);
extern void valueSet(void *context, int32_t a);
extern void valueIndex(void *context, int32_t a);
extern void valueSetIndex(void *context, int32_t a);
extern void valueCall(void *context, int32_t a);
extern void valueInvoke(void *context, int32_t a);
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);
2019-08-07 13:47:59 +03:00
extern void scheduleTimeoutEvent(void *context, int32_t a);
extern void clearTimeoutEvent(void *context, int32_t a);
2020-01-05 19:56:36 +03:00
extern void copyBytesToGo (void *context, int32_t a);
extern void copyBytesToJS (void *context, int32_t a);
2019-08-06 16:03:11 +03:00
*/
import "C"
import (
2019-08-07 13:47:59 +03:00
"crypto/rand"
2019-08-06 16:03:11 +03:00
"fmt"
2019-08-22 05:24:07 +03:00
"log"
2019-08-20 04:13:53 +03:00
"reflect"
"syscall"
2019-08-07 13:47:59 +03:00
"time"
2019-08-06 16:03:11 +03:00
"unsafe"
"github.com/wasmerio/go-ext-wasm/wasmer"
)
//export debug
2019-08-22 05:24:07 +03:00
func debug(_ unsafe.Pointer, sp int32) {
log.Println(sp)
2019-08-06 16:03:11 +03:00
}
//export wexit
2019-08-13 18:11:23 +03:00
func wexit(ctx unsafe.Pointer, sp int32) {
b := getBridge(ctx)
2019-08-15 21:12:20 +03:00
b.exitCode = int(b.getUint32(sp + 8))
2019-08-22 05:24:07 +03:00
b.cancF()
2019-08-06 16:03:11 +03:00
}
//export wwrite
2019-08-13 18:11:23 +03:00
func wwrite(ctx unsafe.Pointer, sp int32) {
2019-08-20 04:13:53 +03:00
b := getBridge(ctx)
fd := int(b.getInt64(sp + 8))
p := int(b.getInt64(sp + 16))
l := int(b.getInt32(sp + 24))
2019-08-22 05:24:07 +03:00
_, err := syscall.Write(fd, b.mem()[p:p+l])
if err != nil {
panic(fmt.Errorf("wasm-write: %v", err))
}
2019-08-06 16:03:11 +03:00
}
//export nanotime
2019-08-13 18:11:23 +03:00
func nanotime(ctx unsafe.Pointer, sp int32) {
2019-08-07 13:47:59 +03:00
n := time.Now().UnixNano()
2019-08-13 18:11:23 +03:00
getBridge(ctx).setInt64(sp+8, n)
2019-08-06 16:03:11 +03:00
}
//export walltime
2019-08-13 18:11:23 +03:00
func walltime(ctx unsafe.Pointer, sp int32) {
2019-08-20 04:13:53 +03:00
b := getBridge(ctx)
2019-08-20 23:47:40 +03:00
t := time.Now().UnixNano()
2019-08-22 20:12:14 +03:00
nanos := t % int64(time.Second)
b.setInt64(sp+8, t/int64(time.Second))
2019-08-20 04:13:53 +03:00
b.setInt32(sp+16, int32(nanos))
2019-08-06 16:03:11 +03:00
}
//export scheduleCallback
2019-08-22 05:24:07 +03:00
func scheduleCallback(_ unsafe.Pointer, _ int32) {
2019-08-20 04:13:53 +03:00
panic("schedule callback")
2019-08-06 16:03:11 +03:00
}
//export clearScheduledCallback
2019-08-22 05:24:07 +03:00
func clearScheduledCallback(_ unsafe.Pointer, _ int32) {
2019-08-20 04:13:53 +03:00
panic("clear scheduled callback")
2019-08-06 16:03:11 +03:00
}
//export getRandomData
2019-08-13 18:11:23 +03:00
func getRandomData(ctx unsafe.Pointer, sp int32) {
s := getBridge(ctx).loadSlice(sp + 8)
2019-08-07 13:47:59 +03:00
_, err := rand.Read(s)
if err != nil {
2019-08-20 04:13:53 +03:00
panic("failed: getRandomData")
2019-08-07 13:47:59 +03:00
}
2019-08-06 16:03:11 +03:00
}
//export stringVal
2019-08-13 18:11:23 +03:00
func stringVal(ctx unsafe.Pointer, sp int32) {
2019-08-20 04:25:01 +03:00
b := getBridge(ctx)
str := b.loadString(sp + 8)
b.storeValue(sp+24, str)
2019-08-06 16:03:11 +03:00
}
//export valueGet
2019-08-13 18:11:23 +03:00
func valueGet(ctx unsafe.Pointer, sp int32) {
b := getBridge(ctx)
str := b.loadString(sp + 16)
2019-08-20 04:13:53 +03:00
val := b.loadValue(sp + 8)
2019-08-15 21:12:20 +03:00
sp = b.getSP()
obj, ok := val.(*object)
if !ok {
b.storeValue(sp+32, val)
return
}
res, ok := obj.props[str]
if !ok {
2019-08-20 04:13:53 +03:00
panic(fmt.Sprintln("missing property", str, val))
2019-08-15 21:12:20 +03:00
}
b.storeValue(sp+32, res)
2019-08-06 16:03:11 +03:00
}
//export valueSet
2019-08-13 18:11:23 +03:00
func valueSet(ctx unsafe.Pointer, sp int32) {
2019-08-20 04:13:53 +03:00
b := getBridge(ctx)
val := b.loadValue(sp + 8)
obj := val.(*object)
prop := b.loadString(sp + 16)
propVal := b.loadValue(sp + 32)
obj.props[prop] = propVal
2019-08-06 16:03:11 +03:00
}
//export valueIndex
2019-08-13 18:11:23 +03:00
func valueIndex(ctx unsafe.Pointer, sp int32) {
2019-08-20 04:13:53 +03:00
b := getBridge(ctx)
l := b.loadValue(sp + 8)
i := b.getInt64(sp + 16)
rv := reflect.ValueOf(l)
if rv.Kind() == reflect.Ptr {
rv = rv.Elem()
}
iv := rv.Index(int(i))
b.storeValue(sp+24, iv.Interface())
2019-08-06 16:03:11 +03:00
}
//export valueSetIndex
2019-08-22 05:24:07 +03:00
func valueSetIndex(_ unsafe.Pointer, _ int32) {
2019-08-20 04:13:53 +03:00
panic("valueSetIndex")
2019-08-06 16:03:11 +03:00
}
//export valueCall
2019-08-13 18:11:23 +03:00
func valueCall(ctx unsafe.Pointer, sp int32) {
2019-08-20 04:13:53 +03:00
b := getBridge(ctx)
v := b.loadValue(sp + 8)
str := b.loadString(sp + 16)
2020-01-05 19:56:36 +03:00
args := b.loadSliceOfValues(sp + 32)
f, ok := v.(*object).props[str].(Func)
if !ok {
panic(fmt.Sprintf("valueCall: prop not found in %v, %s", v.(*object).name, str))
2019-08-20 04:13:53 +03:00
}
sp = b.getSP()
res, err := f(args)
if err != nil {
b.storeValue(sp+56, err.Error())
b.setUint8(sp+64, 0)
return
}
b.storeValue(sp+56, res)
b.setUint8(sp+64, 1)
2019-08-06 16:03:11 +03:00
}
//export valueInvoke
2019-08-13 18:11:23 +03:00
func valueInvoke(ctx unsafe.Pointer, sp int32) {
2019-08-20 22:20:20 +03:00
b := getBridge(ctx)
val := *(b.loadValue(sp + 8).(*Func))
args := b.loadSliceOfValues(sp + 16)
res, err := val(args)
sp = b.getSP()
if err != nil {
b.storeValue(sp+40, err)
b.setUint8(sp+48, 0)
return
}
b.storeValue(sp+40, res)
b.setUint8(sp+48, 1)
2019-08-06 16:03:11 +03:00
}
//export valueNew
2019-08-13 18:11:23 +03:00
func valueNew(ctx unsafe.Pointer, sp int32) {
2019-08-15 21:12:20 +03:00
b := getBridge(ctx)
2019-08-20 04:13:53 +03:00
val := b.loadValue(sp + 8)
2019-08-15 21:12:20 +03:00
args := b.loadSliceOfValues(sp + 16)
2019-08-20 04:13:53 +03:00
res := val.(*object).new(args)
sp = b.getSP()
b.storeValue(sp+40, res)
b.setUint8(sp+48, 1)
2019-08-06 16:03:11 +03:00
}
//export valueLength
2019-08-13 18:11:23 +03:00
func valueLength(ctx unsafe.Pointer, sp int32) {
2019-08-20 04:13:53 +03:00
b := getBridge(ctx)
val := b.loadValue(sp + 8)
rv := reflect.ValueOf(val)
if rv.Kind() == reflect.Ptr {
rv = rv.Elem()
}
2020-01-05 19:56:36 +03:00
var l int
switch {
case rv.Kind() == reflect.Slice:
l = rv.Len()
case rv.Type() == reflect.TypeOf(array{}):
l = len(val.(*array).buf)
default:
panic(fmt.Sprintf("valueLength on %T", val))
}
b.setInt64(sp+16, int64(l))
2019-08-06 16:03:11 +03:00
}
//export valuePrepareString
2019-08-13 18:11:23 +03:00
func valuePrepareString(ctx unsafe.Pointer, sp int32) {
2019-08-20 04:13:53 +03:00
b := getBridge(ctx)
val := b.loadValue(sp + 8)
var str string
if val != nil {
2019-08-20 04:25:01 +03:00
str = fmt.Sprint(val)
2019-08-20 04:13:53 +03:00
}
b.storeValue(sp+16, str)
b.setInt64(sp+24, int64(len(str)))
2019-08-06 16:03:11 +03:00
}
//export valueLoadString
2019-08-13 18:11:23 +03:00
func valueLoadString(ctx unsafe.Pointer, sp int32) {
2019-08-20 04:25:01 +03:00
b := getBridge(ctx)
str := b.loadValue(sp + 8).(string)
sl := b.loadSlice(sp + 16)
copy(sl, str)
2019-08-06 16:03:11 +03:00
}
2019-08-07 13:47:59 +03:00
//export scheduleTimeoutEvent
2019-08-22 05:24:07 +03:00
func scheduleTimeoutEvent(_ unsafe.Pointer, _ int32) {
2019-08-20 04:13:53 +03:00
panic("scheduleTimeoutEvent")
2019-08-07 13:47:59 +03:00
}
//export clearTimeoutEvent
2019-08-22 05:24:07 +03:00
func clearTimeoutEvent(_ unsafe.Pointer, _ int32) {
2019-08-20 04:13:53 +03:00
panic("clearTimeoutEvent")
2019-08-07 13:47:59 +03:00
}
2020-01-05 19:56:36 +03:00
//export copyBytesToJS
func copyBytesToJS(ctx unsafe.Pointer, sp int32) {
b := getBridge(ctx)
dst, ok := b.loadValue(sp + 8).(*array)
if !ok {
b.setUint8(sp+48, 0)
return
}
src := b.loadSlice(sp + 16)
n := copy(dst.buf, src[:len(dst.buf)])
b.setInt64(sp+40, int64(n))
b.setUint8(sp+48, 1)
}
//export copyBytesToGo
func copyBytesToGo(ctx unsafe.Pointer, sp int32) {
b := getBridge(ctx)
dst := b.loadSlice(sp + 8)
src, ok := b.loadValue(sp + 32).(*array)
if !ok {
b.setUint8(sp+48, 0)
return
}
n := copy(dst, src.buf[:len(dst)])
b.setInt64(sp+40, int64(n))
b.setUint8(sp+48, 1)
}
2019-08-13 18:11:23 +03:00
// addImports adds go Bridge imports in "go" namespace.
func (b *Bridge) addImports(imps *wasmer.Imports) error {
2019-08-07 13:47:59 +03:00
imps = imps.Namespace("go")
2019-08-06 16:03:11 +03:00
var is = []struct {
name string
imp interface{}
cgo unsafe.Pointer
}{
{"debug", debug, C.debug},
{"runtime.wasmExit", wexit, C.wexit},
{"runtime.wasmWrite", wwrite, C.wwrite},
{"runtime.nanotime", nanotime, C.nanotime},
{"runtime.walltime", walltime, C.walltime},
{"runtime.scheduleCallback", scheduleCallback, C.scheduleCallback},
{"runtime.clearScheduledCallback", clearScheduledCallback, C.clearScheduledCallback},
{"runtime.getRandomData", getRandomData, C.getRandomData},
2019-08-07 13:47:59 +03:00
{"runtime.scheduleTimeoutEvent", scheduleTimeoutEvent, C.scheduleTimeoutEvent},
{"runtime.clearTimeoutEvent", clearTimeoutEvent, C.clearTimeoutEvent},
2019-08-06 16:03:11 +03:00
{"syscall/js.stringVal", stringVal, C.stringVal},
{"syscall/js.valueGet", valueGet, C.valueGet},
{"syscall/js.valueSet", valueSet, C.valueSet},
{"syscall/js.valueIndex", valueIndex, C.valueIndex},
{"syscall/js.valueSetIndex", valueSetIndex, C.valueSetIndex},
{"syscall/js.valueCall", valueCall, C.valueCall},
{"syscall/js.valueInvoke", valueInvoke, C.valueInvoke},
{"syscall/js.valueNew", valueNew, C.valueNew},
{"syscall/js.valueLength", valueLength, C.valueLength},
{"syscall/js.valuePrepareString", valuePrepareString, C.valuePrepareString},
{"syscall/js.valueLoadString", valueLoadString, C.valueLoadString},
2020-01-05 19:56:36 +03:00
{"syscall/js.copyBytesToGo", copyBytesToGo, C.copyBytesToGo},
{"syscall/js.copyBytesToJS", copyBytesToJS, C.copyBytesToJS},
2019-08-06 16:03:11 +03:00
}
var err error
for _, imp := range is {
imps, err = imps.Append(imp.name, imp.imp, imp.cgo)
if err != nil {
2019-08-07 13:47:59 +03:00
return err
2019-08-06 16:03:11 +03:00
}
}
2019-08-07 13:47:59 +03:00
return nil
2019-08-06 16:03:11 +03:00
}