qjs/bridge.go

115 lines
2.5 KiB
Go

package quickjs
import (
"runtime/cgo"
"sync"
"sync/atomic"
"unsafe"
)
/*
#include <stdint.h>
#include "bridge.h"
*/
import "C"
type funcEntry struct {
ctx *Context
fn func(ctx *Context, this Value, args []Value) Value
asyncFn func(ctx *Context, this Value, promise Value, args []Value) Value
}
var funcPtrLen int64
var funcPtrLock sync.Mutex
var funcPtrStore = make(map[int64]funcEntry)
var funcPtrClassID C.JSClassID
func init() {
C.JS_NewClassID(&funcPtrClassID)
}
func storeFuncPtr(v funcEntry) int64 {
id := atomic.AddInt64(&funcPtrLen, 1) - 1
if id >= 9223372036854775807 {
id = 0
}
funcPtrLock.Lock()
defer funcPtrLock.Unlock()
funcPtrStore[id] = v
return id
}
func restoreFuncPtr(ptr int64) funcEntry {
funcPtrLock.Lock()
defer funcPtrLock.Unlock()
return funcPtrStore[ptr]
}
func freeFuncPtr(ptr int64) {
funcPtrLock.Lock()
defer funcPtrLock.Unlock()
delete(funcPtrStore, ptr)
}
func freeFuncPtrs(ptrs []int64) {
funcPtrLock.Lock()
defer funcPtrLock.Unlock()
for _, ptr := range ptrs {
delete(funcPtrStore, ptr)
}
}
//export goProxy
func goProxy(ctx *C.JSContext, thisVal C.JSValueConst, argc C.int, argv *C.JSValueConst) C.JSValue {
// https://github.com/golang/go/wiki/cgo#turning-c-arrays-into-go-slices
refs := unsafe.Slice(argv, argc) // Go 1.17 and later
id := C.int64_t(0)
C.JS_ToInt64(ctx, &id, refs[0])
entry := restoreFuncPtr(int64(id))
args := make([]Value, len(refs)-1)
for i := 0; i < len(args); i++ {
args[i].ctx = entry.ctx
args[i].ref = refs[1+i]
}
result := entry.fn(entry.ctx, Value{ctx: entry.ctx, ref: thisVal}, args)
return result.ref
}
//export goAsyncProxy
func goAsyncProxy(ctx *C.JSContext, thisVal C.JSValueConst, argc C.int, argv *C.JSValueConst) C.JSValue {
// https://github.com/golang/go/wiki/cgo#turning-c-arrays-into-go-slices
refs := unsafe.Slice(argv, argc) // Go 1.17 and later
id := C.int64_t(0)
C.JS_ToInt64(ctx, &id, refs[0])
entry := restoreFuncPtr(int64(id))
args := make([]Value, len(refs)-1)
for i := 0; i < len(args); i++ {
args[i].ctx = entry.ctx
args[i].ref = refs[1+i]
}
promise := args[0]
result := entry.asyncFn(entry.ctx, Value{ctx: entry.ctx, ref: thisVal}, promise, args[1:])
return result.ref
}
//export goInterruptHandler
func goInterruptHandler(rt *C.JSRuntime, handlerArgs unsafe.Pointer) C.int {
handlerArgsStruct := (*C.handlerArgs)(handlerArgs)
hFn := cgo.Handle(handlerArgsStruct.fn)
hFnValue := hFn.Value().(InterruptHandler)
// defer hFn.Delete()
return C.int(hFnValue())
}