@@ -11,6 +11,7 @@ import (
1111 "math"
1212 "reflect"
1313 "regexp"
14+ "runtime"
1415 "unicode"
1516 "unsafe"
1617
@@ -20,28 +21,30 @@ import (
2021// TODO: support try/catch?
2122// https://stackoverflow.com/questions/7062599/example-of-how-objective-cs-try-catch-implementation-is-executed-at-runtime
2223var (
23- objc_msgSend_fn uintptr
24- objc_msgSend func (obj ID , cmd SEL , args ... interface {}) ID
25- objc_msgSendSuper2_fn uintptr
26- objc_msgSendSuper2 func (super * objc_super , cmd SEL , args ... interface {}) ID
27- objc_getClass func (name string ) Class
28- objc_getProtocol func (name string ) * Protocol
29- objc_allocateClassPair func (super Class , name string , extraBytes uintptr ) Class
30- objc_registerClassPair func (class Class )
31- sel_registerName func (name string ) SEL
32- class_getSuperclass func (class Class ) Class
33- class_getInstanceVariable func (class Class , name string ) Ivar
34- class_getInstanceSize func (class Class ) uintptr
35- class_addMethod func (class Class , name SEL , imp IMP , types string ) bool
36- class_addIvar func (class Class , name string , size uintptr , alignment uint8 , types string ) bool
37- class_addProtocol func (class Class , protocol * Protocol ) bool
38- ivar_getOffset func (ivar Ivar ) uintptr
39- ivar_getName func (ivar Ivar ) string
40- object_getClass func (obj ID ) Class
41- object_getIvar func (obj ID , ivar Ivar ) ID
42- object_setIvar func (obj ID , ivar Ivar , value ID )
43- protocol_getName func (protocol * Protocol ) string
44- protocol_isEqual func (p * Protocol , p2 * Protocol ) bool
24+ objc_msgSend_fn uintptr
25+ objc_msgSend_stret_fn uintptr
26+ objc_msgSend func (obj ID , cmd SEL , args ... interface {}) ID
27+ objc_msgSendSuper2_fn uintptr
28+ objc_msgSendSuper2_stret_fn uintptr
29+ objc_msgSendSuper2 func (super * objc_super , cmd SEL , args ... interface {}) ID
30+ objc_getClass func (name string ) Class
31+ objc_getProtocol func (name string ) * Protocol
32+ objc_allocateClassPair func (super Class , name string , extraBytes uintptr ) Class
33+ objc_registerClassPair func (class Class )
34+ sel_registerName func (name string ) SEL
35+ class_getSuperclass func (class Class ) Class
36+ class_getInstanceVariable func (class Class , name string ) Ivar
37+ class_getInstanceSize func (class Class ) uintptr
38+ class_addMethod func (class Class , name SEL , imp IMP , types string ) bool
39+ class_addIvar func (class Class , name string , size uintptr , alignment uint8 , types string ) bool
40+ class_addProtocol func (class Class , protocol * Protocol ) bool
41+ ivar_getOffset func (ivar Ivar ) uintptr
42+ ivar_getName func (ivar Ivar ) string
43+ object_getClass func (obj ID ) Class
44+ object_getIvar func (obj ID , ivar Ivar ) ID
45+ object_setIvar func (obj ID , ivar Ivar , value ID )
46+ protocol_getName func (protocol * Protocol ) string
47+ protocol_isEqual func (p * Protocol , p2 * Protocol ) bool
4548)
4649
4750func init () {
@@ -53,6 +56,16 @@ func init() {
5356 if err != nil {
5457 panic (fmt .Errorf ("objc: %w" , err ))
5558 }
59+ if runtime .GOARCH == "amd64" {
60+ objc_msgSend_stret_fn , err = purego .Dlsym (objc , "objc_msgSend_stret" )
61+ if err != nil {
62+ panic (fmt .Errorf ("objc: %w" , err ))
63+ }
64+ objc_msgSendSuper2_stret_fn , err = purego .Dlsym (objc , "objc_msgSendSuper2_stret" )
65+ if err != nil {
66+ panic (fmt .Errorf ("objc: %w" , err ))
67+ }
68+ }
5669 purego .RegisterFunc (& objc_msgSend , objc_msgSend_fn )
5770 objc_msgSendSuper2_fn , err = purego .Dlsym (objc , "objc_msgSendSuper2" )
5871 if err != nil {
@@ -104,12 +117,22 @@ func (id ID) SetIvar(ivar Ivar, value ID) {
104117 object_setIvar (id , ivar , value )
105118}
106119
120+ // keep in sync with func.go
121+ const maxRegAllocStructSize = 16
122+
107123// Send is a convenience method for sending messages to objects that can return any type.
108124// This function takes a SEL instead of a string since RegisterName grabs the global Objective-C lock.
109125// It is best to cache the result of RegisterName.
110126func Send [T any ](id ID , sel SEL , args ... any ) T {
111127 var fn func (id ID , sel SEL , args ... any ) T
112- purego .RegisterFunc (& fn , objc_msgSend_fn )
128+ var zero T
129+ if runtime .GOARCH == "amd64" &&
130+ reflect .ValueOf (zero ).Kind () == reflect .Struct &&
131+ reflect .ValueOf (zero ).Type ().Size () > maxRegAllocStructSize {
132+ purego .RegisterFunc (& fn , objc_msgSend_stret_fn )
133+ } else {
134+ purego .RegisterFunc (& fn , objc_msgSend_fn )
135+ }
113136 return fn (id , sel , args ... )
114137}
115138
@@ -141,7 +164,14 @@ func SendSuper[T any](id ID, sel SEL, args ...any) T {
141164 superClass : id .Class (),
142165 }
143166 var fn func (objcSuper * objc_super , sel SEL , args ... any ) T
144- purego .RegisterFunc (& fn , objc_msgSendSuper2_fn )
167+ var zero T
168+ if runtime .GOARCH == "amd64" &&
169+ reflect .ValueOf (zero ).Kind () == reflect .Struct &&
170+ reflect .ValueOf (zero ).Type ().Size () > maxRegAllocStructSize {
171+ purego .RegisterFunc (& fn , objc_msgSendSuper2_stret_fn )
172+ } else {
173+ purego .RegisterFunc (& fn , objc_msgSendSuper2_fn )
174+ }
145175 return fn (super , sel , args ... )
146176}
147177
0 commit comments