@@ -11,6 +11,7 @@ import (
11
11
"math"
12
12
"reflect"
13
13
"regexp"
14
+ "runtime"
14
15
"unicode"
15
16
"unsafe"
16
17
@@ -20,28 +21,30 @@ import (
20
21
// TODO: support try/catch?
21
22
// https://stackoverflow.com/questions/7062599/example-of-how-objective-cs-try-catch-implementation-is-executed-at-runtime
22
23
var (
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
45
48
)
46
49
47
50
func init () {
@@ -53,6 +56,16 @@ func init() {
53
56
if err != nil {
54
57
panic (fmt .Errorf ("objc: %w" , err ))
55
58
}
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
+ }
56
69
purego .RegisterFunc (& objc_msgSend , objc_msgSend_fn )
57
70
objc_msgSendSuper2_fn , err = purego .Dlsym (objc , "objc_msgSendSuper2" )
58
71
if err != nil {
@@ -104,12 +117,22 @@ func (id ID) SetIvar(ivar Ivar, value ID) {
104
117
object_setIvar (id , ivar , value )
105
118
}
106
119
120
+ // keep in sync with func.go
121
+ const maxRegAllocStructSize = 16
122
+
107
123
// Send is a convenience method for sending messages to objects that can return any type.
108
124
// This function takes a SEL instead of a string since RegisterName grabs the global Objective-C lock.
109
125
// It is best to cache the result of RegisterName.
110
126
func Send [T any ](id ID , sel SEL , args ... any ) T {
111
127
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
+ }
113
136
return fn (id , sel , args ... )
114
137
}
115
138
@@ -141,7 +164,14 @@ func SendSuper[T any](id ID, sel SEL, args ...any) T {
141
164
superClass : id .Class (),
142
165
}
143
166
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
+ }
145
175
return fn (super , sel , args ... )
146
176
}
147
177
0 commit comments