Halide
objc_support.h
Go to the documentation of this file.
1 #ifndef HALIDE_OBJC_SUPPORT_H
2 #define HALIDE_OBJC_SUPPORT_H
3 
4 extern "C" {
5 typedef void *objc_id;
6 typedef void *objc_sel;
7 extern objc_id objc_getClass(const char *name);
8 extern objc_sel sel_getUid(const char *string);
9 
10 // Recent versions of macOS have changed the signature
11 // for objc_msgSend(), since its implementation is ABI-dependent.
12 // With this signature, users must always cast the call to the
13 // correct function type, and any calls without casting to the right
14 // function type will be caught at compile time.
15 //
16 // A good explanation of why is here: https://www.mikeash.com/pyblog/objc_msgsends-new-prototype.html
17 //
18 // The TL;DR is that objc_msgSend is special in that what it does is not touch
19 // the registers at all and 1) loads the ObjC class corresponding to the object, 2)
20 // looks up the selector in the class’s method cache, and 3) jumps to the location of
21 // the method if it’s in the cache. objc_msgSend takes as parameters an object,
22 // the method selector, then all the other parameters to the method; when it
23 // jumps to the method implementation, it's as if the method implementation was called
24 // directly.
25 // C doesn’t have a way to express this kind of function: the method implementation (usually) uses the ABI
26 // calling convention for a normal non-variadic function, but the C prototype for
27 // this has to be variadic. That used to be okay(ish) on x64 because the variadic and
28 // normal conventions are basically the same, but on ARM a variadic function passes
29 // all params on the stack, which would be a huge amount of overhead given how many
30 // times its called (every single method invocation in ObjC).
31 // The other problem with using a variadic signature is that C does type promotion on a variadic
32 // call.
33 extern void objc_msgSend(void);
34 
35 void NSLog(objc_id /* NSString * */ format, ...);
36 }
37 
38 namespace Halide {
39 namespace Runtime {
40 namespace Internal {
41 
43  typedef objc_id (*pool_method)(objc_id obj, objc_sel sel);
44  pool_method method = (pool_method)&objc_msgSend;
45  objc_id pool = (*method)(objc_getClass("NSAutoreleasePool"), sel_getUid("alloc"));
46  pool = (*method)(pool, sel_getUid("init"));
47  return pool;
48 }
49 
51  typedef objc_id (*drain_method)(objc_id obj, objc_sel sel);
52  drain_method method = (drain_method)&objc_msgSend;
53  (*method)(pool, sel_getUid("drain"));
54 }
55 
57  typedef objc_id (*retain_method)(objc_id obj, objc_sel sel);
58  retain_method method = (retain_method)&objc_msgSend;
59  (*method)(obj, sel_getUid("retain"));
60 }
61 
63  typedef objc_id (*release_method)(objc_id obj, objc_sel sel);
64  release_method method = (release_method)&objc_msgSend;
65  (*method)(obj, sel_getUid("release"));
66 }
67 
68 WEAK objc_id wrap_string_as_ns_string(const char *string, size_t length) {
69  typedef objc_id (*init_with_bytes_no_copy_method)(objc_id ns_string, objc_sel sel, const char *string, size_t length, size_t encoding, uint8_t freeWhenDone);
70  typedef objc_id (*alloc_method)(objc_id objc, objc_sel sel);
71  alloc_method method1 = (alloc_method)&objc_msgSend;
72  objc_id ns_string = (*method1)(objc_getClass("NSString"), sel_getUid("alloc"));
73  init_with_bytes_no_copy_method method = (init_with_bytes_no_copy_method)&objc_msgSend;
74  return (*method)(ns_string, sel_getUid("initWithBytesNoCopy:length:encoding:freeWhenDone:"),
75  string, length, 4, 0);
76 }
77 
78 extern "C" size_t strlen(const char *string);
79 
80 WEAK void ns_log_utf8_string(const char *string) {
81  objc_id format_string = wrap_string_as_ns_string("%@", 2);
82  objc_id ns_string = wrap_string_as_ns_string(string, strlen(string));
83  NSLog(format_string, ns_string);
84  release_ns_object(ns_string);
85  release_ns_object(format_string);
86 }
87 
89  objc_id format_string = wrap_string_as_ns_string("%@", 2);
90  NSLog(format_string, obj);
91  release_ns_object(format_string);
92 }
93 
94 } // namespace Internal
95 } // namespace Runtime
96 } // namespace Halide
97 
98 #endif
Halide::Runtime::Internal::create_autorelease_pool
WEAK objc_id create_autorelease_pool()
Definition: objc_support.h:42
uint8_t
unsigned __INT8_TYPE__ uint8_t
Definition: runtime_internal.h:25
sel_getUid
objc_sel sel_getUid(const char *string)
Halide::Runtime::Internal::wrap_string_as_ns_string
WEAK objc_id wrap_string_as_ns_string(const char *string, size_t length)
Definition: objc_support.h:68
objc_id
void * objc_id
Definition: objc_support.h:5
Halide::Runtime::Internal::release_ns_object
WEAK void release_ns_object(objc_id obj)
Definition: objc_support.h:62
Halide
This file defines the class FunctionDAG, which is our representation of a Halide pipeline,...
Definition: AddAtomicMutex.h:21
NSLog
void NSLog(objc_id format,...)
Halide::LinkageType::Internal
@ Internal
Not visible externally, similar to 'static' linkage in C.
objc_msgSend
void objc_msgSend(void)
Halide::Runtime::Internal::ns_log_object
WEAK void ns_log_object(objc_id obj)
Definition: objc_support.h:88
Halide::Runtime::Internal::retain_ns_object
WEAK void retain_ns_object(objc_id obj)
Definition: objc_support.h:56
Halide::Runtime::Internal::strlen
size_t strlen(const char *string)
Halide::Runtime::Internal::ns_log_utf8_string
WEAK void ns_log_utf8_string(const char *string)
Definition: objc_support.h:80
WEAK
#define WEAK
Definition: runtime_internal.h:50
objc_sel
void * objc_sel
Definition: objc_support.h:6
Halide::Runtime::Internal::drain_autorelease_pool
WEAK void drain_autorelease_pool(objc_id pool)
Definition: objc_support.h:50
objc_getClass
objc_id objc_getClass(const char *name)