github.com/hsfzxjy/dgo/go@v0.2.0/ffi.go (about)

     1  package dgo
     2  
     3  /*
     4  #include "ffi.h"
     5  */
     6  import "C"
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"math"
    11  	"reflect"
    12  	"runtime"
    13  	"runtime/cgo"
    14  	"sync"
    15  	"unsafe"
    16  
    17  	"github.com/hsfzxjy/dgo/go/keepalive"
    18  )
    19  
    20  type (
    21  	Dart_CObject                     = C.dgo__Dart_CObject
    22  	Dart_CObject_Type                = C.Dart_CObject_Type
    23  	Dart_CObject_AsArray             = C.dgo__Dart_CObject_AsArray
    24  	Dart_CObject_AsTypedData         = C.dgo__Dart_CObject_AsTypedData
    25  	Dart_Cobject_AsExternalTypedData = C.dgo__Dart_Cobject_AsExternalTypedData
    26  )
    27  
    28  const (
    29  	Dart_CObject_kNull      = C.Dart_CObject_kNull
    30  	Dart_CObject_kBool      = C.Dart_CObject_kBool
    31  	Dart_CObject_kInt32     = C.Dart_CObject_kInt32
    32  	Dart_CObject_kInt64     = C.Dart_CObject_kInt64
    33  	Dart_CObject_kDouble    = C.Dart_CObject_kDouble
    34  	Dart_CObject_kString    = C.Dart_CObject_kString
    35  	Dart_CObject_kArray     = C.Dart_CObject_kArray
    36  	Dart_CObject_kTypedData = C.Dart_CObject_kTypedData
    37  )
    38  
    39  type PortKey C.Dart_Port_DL
    40  
    41  func dgo__PostCObjects(port *Port, n int, arr *Dart_CObject) bool {
    42  	return bool(C.dgo__PostCObjects(C.Dart_Port_DL(port.sendPortKey), C.int(n), noescape(arr)))
    43  }
    44  
    45  /* Port Methods */
    46  
    47  func (p *Port) panicPostFailure() {
    48  	panic("dgo:go: fail to post via " + p.String())
    49  }
    50  
    51  func (p *Port) postInt(value int64, raises bool) bool {
    52  	ret := bool(C.dgo__PostInt(C.Dart_Port_DL(p.sendPortKey), C.int64_t(value)))
    53  	if !ret && raises {
    54  		p.panicPostFailure()
    55  	}
    56  	return ret
    57  }
    58  
    59  func (p *Port) postCObject(obj *Dart_CObject, raises bool) bool {
    60  	ret := bool(C.dgo__PostCObject(C.Dart_Port_DL(p.sendPortKey), noescape(obj)))
    61  	runtime.KeepAlive(obj)
    62  	if !ret && raises {
    63  		p.panicPostFailure()
    64  	}
    65  	return ret
    66  }
    67  
    68  func (p *Port) postCObjects(objs []Dart_CObject, keepAlive keepalive.Holder, raises bool) bool {
    69  	var pobjs *Dart_CObject
    70  	if len(objs) != 0 {
    71  		pobjs = &objs[0]
    72  	}
    73  	ret := bool(C.dgo__PostCObjects(
    74  		C.Dart_Port_DL(p.sendPortKey),
    75  		C.int(len(objs)),
    76  		noescape(pobjs)))
    77  	runtime.KeepAlive(objs)
    78  	runtime.KeepAlive(keepAlive)
    79  	keepAlive.Free()
    80  	if !ret && raises {
    81  		p.panicPostFailure()
    82  	}
    83  	return ret
    84  }
    85  
    86  func (p *Port) postCObjects2(objs1, objs2 []Dart_CObject, keepAlive keepalive.Holder, raises bool) bool {
    87  	var p1, p2 *Dart_CObject
    88  	if len(objs1) != 0 {
    89  		p1 = &objs1[0]
    90  	}
    91  	if len(objs2) != 0 {
    92  		p2 = &objs2[0]
    93  	}
    94  	ret := bool(C.dgo__PostCObjects2(
    95  		C.Dart_Port_DL(p.sendPortKey),
    96  		C.int(len(objs1)),
    97  		noescape(p1),
    98  		C.int(len(objs2)),
    99  		noescape(p2)))
   100  	runtime.KeepAlive(objs1)
   101  	runtime.KeepAlive(objs2)
   102  	runtime.KeepAlive(keepAlive)
   103  	keepAlive.Free()
   104  	if !ret && raises {
   105  		p.panicPostFailure()
   106  	}
   107  	return ret
   108  }
   109  
   110  func (p *Port) close() {
   111  	if !p.isClosed.CompareAndSwap(false, true) {
   112  		return
   113  	}
   114  
   115  	p.postCObject(&Dart_CObject{Type: Dart_CObject_kNull}, false)
   116  
   117  	portMap.removePort(p)
   118  	C.dgo__CloseNativePort(C.Dart_Port_DL(p.receivePortKey))
   119  }
   120  
   121  /* _PortMap Methods */
   122  
   123  func (m *_PortMap) initPort(sendPortKey PortKey) PortKey {
   124  	receivePortKey := C.dgo__InitPort(C.Dart_Port_DL(sendPortKey))
   125  	if receivePortKey == C.ILLEGAL_PORT {
   126  		panic("dgo:go: fail to create a new receive port")
   127  	}
   128  	return PortKey(receivePortKey)
   129  }
   130  
   131  /* CallableDartCallback Methods */
   132  
   133  func (dcb CallableDartCallback) Call(args ...any) bool {
   134  	cf := CallbackFlag(dcb.payload)
   135  	port := dcb.port
   136  	if cf.HasFast() {
   137  		if len(args) != 0 {
   138  			panic("dgo:go: expect no argument when CF_FAST set")
   139  		}
   140  		return port.postInt(int64(dcb.serialize()), true)
   141  	}
   142  	var keepAlive keepalive.Holder
   143  	n := len(args)
   144  	cobjs := make([]Dart_CObject, n+1)
   145  	cobjectLoadFromValue(&cobjs[0], dcb.serialize(), &keepAlive)
   146  	for i, arg := range args {
   147  		cobjectLoadFromValue(&cobjs[i+1], arg, &keepAlive)
   148  	}
   149  	return port.postCObjects(cobjs[:n+1], keepAlive, true)
   150  }
   151  
   152  func (dcb CallableDartCallback) callRaw(args []Dart_CObject) bool {
   153  	var head [1]Dart_CObject
   154  	head[0].Type = Dart_CObject_kInt64
   155  	*(*C.int64_t)(unsafe.Pointer(&head[0].Value)) = C.int64_t(dcb.serialize())
   156  	return dcb.port.postCObjects2(head[:], args, keepalive.Holder{}, false)
   157  }
   158  
   159  /* dartCallbackGroup Methods */
   160  
   161  func (g dartCallbackGroup) callRaw(args []Dart_CObject) bool {
   162  	head := make([]Dart_CObject, 1+len(g))
   163  	head[0].Type = Dart_CObject_kInt64
   164  	*(*C.int64_t)(unsafe.Pointer(&head[0].Value)) = C.int64_t(g.serialize())
   165  	for i, dcb := range g {
   166  		s := math.Float64frombits(dcb.serialize())
   167  		head[i+1].Type = Dart_CObject_kDouble
   168  		*(*C.double)(unsafe.Pointer(&head[i+1].Value)) = C.double(s)
   169  	}
   170  	return g[0].port.postCObjects2(head, args, keepalive.Holder{}, false)
   171  }
   172  
   173  /* EXPORTS */
   174  
   175  var apiDLOnce sync.Once
   176  
   177  //export dgo_InitPort
   178  func dgo_InitPort(apiDLData *C.void, sendPortKey C.Dart_Port_DL, isDefault C.bool) {
   179  	apiDLOnce.Do(func() {
   180  		C.dgo__InitFFI(unsafe.Pointer(apiDLData))
   181  	})
   182  	portMap.addPort(PortKey(sendPortKey), bool(isDefault))
   183  }
   184  
   185  //export dgo__GoFinalizer
   186  func dgo__GoFinalizer(callback_data C.uintptr_t, peer C.uintptr_t) {
   187  	handle := cgo.Handle(peer)
   188  	handle.Value().(hasCallback).call()
   189  	handle.Delete()
   190  }
   191  
   192  //export dgo__HandleNativeMessage
   193  func dgo__HandleNativeMessage(portKey C.Dart_Port_DL, msg *Dart_CObject) {
   194  	var handler _SpecialInt
   195  	var port *Port
   196  	var success bool
   197  
   198  	var firstArg uint64
   199  	var cobjs []*Dart_CObject
   200  	var firstObj = msg
   201  
   202  	var atTopLevel = true
   203  
   204  SWITCH:
   205  	pValue := unsafe.Pointer(&firstObj.Value)
   206  	switch firstObj.Type {
   207  	case Dart_CObject_kInt32:
   208  		firstArg = uint64(*(*C.int32_t)(pValue))
   209  	case Dart_CObject_kInt64:
   210  		firstArg = uint64(*(*C.int64_t)(pValue))
   211  	case Dart_CObject_kDouble:
   212  		firstArg = math.Float64bits(*(*float64)(pValue))
   213  	case Dart_CObject_kNull:
   214  		if atTopLevel {
   215  			goto CLOSE_PORT
   216  		}
   217  	case Dart_CObject_kArray:
   218  		pValue := (*Dart_CObject_AsArray)(pValue)
   219  		if pValue.Length == 0 {
   220  			panic("dgo:go: received empty array")
   221  		}
   222  		if atTopLevel {
   223  			atTopLevel = false
   224  			cobjs = (*[MAX_ARRAY_LEN]*Dart_CObject)(unsafe.Pointer(pValue.Values))[1:pValue.Length]
   225  			firstObj = (*Dart_CObject)(unsafe.Pointer(*pValue.Values))
   226  			goto SWITCH
   227  		}
   228  		goto BAD_FIRST_ARGUMENT
   229  	}
   230  
   231  	if firstArg == 0 {
   232  		return
   233  	}
   234  
   235  	port = portMap.GetByPortKey(PortKey(portKey))
   236  	handler, success = parseSpecialInt(port, firstArg, true)
   237  	if !success {
   238  		goto DESERIALIZE_FAILURE
   239  	}
   240  	handler.(_Handlable).handleCObjects(cobjs)
   241  	return
   242  
   243  CLOSE_PORT:
   244  	portMap.GetByPortKey(PortKey(portKey)).close()
   245  	return
   246  
   247  DESERIALIZE_FAILURE:
   248  	panic(fmt.Sprintf(
   249  		"dgo:go: cannot deserialize the first argument %064b as handler",
   250  		firstArg))
   251  
   252  BAD_FIRST_ARGUMENT:
   253  	panic(fmt.Sprintf(
   254  		"dgo:go: bad cobject kind=%d for the first argument",
   255  		firstObj.Type))
   256  }
   257  
   258  const MAX_ARRAY_LEN = 1<<30 - 1
   259  
   260  /* Dart_CObject Parsing & Serializing */
   261  
   262  func cobjectParseInt(cobj *Dart_CObject) int64 {
   263  	pValue := unsafe.Pointer(&cobj.Value)
   264  	switch cobj.Type {
   265  	case C.Dart_CObject_kInt32:
   266  		return int64(*(*C.int32_t)(pValue))
   267  	case C.Dart_CObject_kInt64:
   268  		return int64(*(*C.int64_t)(pValue))
   269  	default:
   270  		panic(fmt.Sprintf("dgo:go: cannot parse cobject into int, kind=%d", cobj.Type))
   271  	}
   272  }
   273  
   274  func cobjectParse(port *Port, cobj *Dart_CObject) any {
   275  	pValue := unsafe.Pointer(&cobj.Value)
   276  	switch cobj.Type {
   277  	case C.Dart_CObject_kNull:
   278  		return nil
   279  	case C.Dart_CObject_kBool:
   280  		return bool(*(*C.bool)(pValue))
   281  	case C.Dart_CObject_kInt32:
   282  		return int64(*(*C.int32_t)(pValue))
   283  	case C.Dart_CObject_kInt64:
   284  		return int64(*(*C.int64_t)(pValue))
   285  	case C.Dart_CObject_kDouble:
   286  		value := float64(*(*C.double)(pValue))
   287  		si, success := parseSpecialInt(port, math.Float64bits(value), false)
   288  		if success {
   289  			return si
   290  		} else {
   291  			return value
   292  		}
   293  	case C.Dart_CObject_kString:
   294  		pArr := *(**[MAX_ARRAY_LEN]byte)(pValue)
   295  		length := bytes.IndexByte(pArr[:], '\x00')
   296  		if length < 0 || pArr[length] != '\x00' {
   297  			panic("dgo:go string too long")
   298  		}
   299  		bytes := make([]byte, length)
   300  		copy(bytes[:length], pArr[:length])
   301  		return string(bytes)
   302  	case C.Dart_CObject_kTypedData:
   303  		pStruct := (*C.dgo__Dart_CObject_AsTypedData)(pValue)
   304  		length := pStruct.Length
   305  		pAddr := unsafe.Pointer(pStruct.Values)
   306  		switch pStruct.Type {
   307  		case C.Dart_TypedData_kUint8:
   308  			return unsafe.Slice((*uint8)(pAddr), length)
   309  		default:
   310  			panic(fmt.Sprintf("dgo:go unsupported typed data, kind=%d", pStruct.Type))
   311  		}
   312  	default:
   313  		panic(fmt.Sprintf("dgo:go unsupport cobject, kind=%d", cobj.Type))
   314  	}
   315  }
   316  
   317  func cobjectLoadFromValue(cobj *Dart_CObject, xx any, keepAlive *keepalive.Holder) {
   318  	pValue := unsafe.Pointer(&cobj.Value)
   319  	switch x := xx.(type) {
   320  	case nil:
   321  		cobj.Type = C.Dart_CObject_kNull
   322  	case bool:
   323  		cobj.Type = C.Dart_CObject_kBool
   324  		*(*C.bool)(pValue) = C.bool(x)
   325  
   326  	// parse integer types
   327  	case int:
   328  		cobj.Type = C.Dart_CObject_kInt64
   329  		*(*C.int64_t)(pValue) = C.int64_t(x)
   330  	case int8:
   331  		cobj.Type = C.Dart_CObject_kInt64
   332  		*(*C.int64_t)(pValue) = C.int64_t(x)
   333  	case int16:
   334  		cobj.Type = C.Dart_CObject_kInt64
   335  		*(*C.int64_t)(pValue) = C.int64_t(x)
   336  	case int32:
   337  		cobj.Type = C.Dart_CObject_kInt64
   338  		*(*C.int64_t)(pValue) = C.int64_t(x)
   339  	case int64:
   340  		cobj.Type = C.Dart_CObject_kInt64
   341  		*(*C.int64_t)(pValue) = C.int64_t(x)
   342  	case uint:
   343  		cobj.Type = C.Dart_CObject_kInt64
   344  		*(*C.int64_t)(pValue) = C.int64_t(x)
   345  	case uint8:
   346  		cobj.Type = C.Dart_CObject_kInt64
   347  		*(*C.int64_t)(pValue) = C.int64_t(x)
   348  	case uint16:
   349  		cobj.Type = C.Dart_CObject_kInt64
   350  		*(*C.int64_t)(pValue) = C.int64_t(x)
   351  	case uint32:
   352  		cobj.Type = C.Dart_CObject_kInt64
   353  		*(*C.int64_t)(pValue) = C.int64_t(x)
   354  	case uint64:
   355  		cobj.Type = C.Dart_CObject_kInt64
   356  		*(*C.int64_t)(pValue) = C.int64_t(x)
   357  
   358  	// parse float types
   359  	case float32:
   360  		cobj.Type = C.Dart_CObject_kDouble
   361  		*(*C.double)(pValue) = C.double(canonicalizeNAN(float64(x)))
   362  	case float64:
   363  		cobj.Type = C.Dart_CObject_kDouble
   364  		*(*C.double)(pValue) = C.double(canonicalizeNAN(x))
   365  
   366  	case []byte:
   367  		header := (*reflect.SliceHeader)(unsafe.Pointer(&x))
   368  		cobj.Type = C.Dart_CObject_kTypedData
   369  		pValue := (*C.dgo__Dart_CObject_AsTypedData)(pValue)
   370  		pValue.Type = C.Dart_TypedData_kUint8
   371  		pValue.Length = C.intptr_t(header.Len)
   372  		pValue.Values = (*C.uint8_t)(unsafe.Pointer(header.Data))
   373  	case string:
   374  		if len(x) == 0 || x[len(x)-1] != '\x00' {
   375  			x = x + "\x00"
   376  		}
   377  		keepAlive.AddString(x)
   378  		header := (*reflect.StringHeader)(unsafe.Pointer(&x))
   379  		cobj.Type = C.Dart_CObject_kString
   380  		*(*uintptr)(pValue) = header.Data
   381  	case ExtSlice:
   382  		var tkind C.Dart_TypedData_Type
   383  		var header *reflect.SliceHeader
   384  		switch slice := x.slice.(type) {
   385  		case []byte:
   386  			tkind = C.Dart_TypedData_kUint8
   387  			header = (*reflect.SliceHeader)(unsafe.Pointer(&slice))
   388  		default:
   389  			panic(fmt.Sprintf("dgo:go: cannot use %#v as typed object", x.slice))
   390  		}
   391  		cobj.Type = C.Dart_CObject_kExternalTypedData
   392  		pValue := (*C.dgo__Dart_Cobject_AsExternalTypedData)(pValue)
   393  		pValue.Type = tkind
   394  		pValue.Length = C.intptr_t(header.Len)
   395  		pValue.Data = (*C.uint8_t)(unsafe.Pointer(header.Data))
   396  		pValue.Peer = C.uintptr_t(x.asCgoHandle())
   397  		pValue.Callback = C.dgo__pGoFinalizer
   398  	case _Serializable:
   399  		cobj.Type = Dart_CObject_kDouble
   400  		serialized := math.Float64frombits(serializeSpecialInt(x))
   401  		*(*C.double)(pValue) = C.double(serialized)
   402  	default:
   403  		panic(fmt.Sprintf("dgo:go cannot convert %#[1]v to Dart_CObject", x))
   404  	}
   405  	return
   406  }