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 }