115 lines
2.5 KiB
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())
|
||
|
}
|