Halide 22.0.0 Halide compiler and libraries

objc_support.h
Go to the documentation of this file.
1#ifndef HALIDE_OBJC_SUPPORT_H
2#define HALIDE_OBJC_SUPPORT_H
3
4extern "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
38namespace Halide {
39namespace Runtime {
40namespace Internal {
41
42 WEAK objc_id create_autorelease_pool() {
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
50 WEAK void drain_autorelease_pool(objc_id pool) {
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
56 WEAK void retain_ns_object(objc_id obj) {
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
62 WEAK void release_ns_object(objc_id obj) {
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
88 WEAK void ns_log_object(objc_id obj) {
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::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::release_ns_object
WEAK void release_ns_object(objc_id obj)
Definition: objc_support.h:62
Halide::Runtime::Internal::drain_autorelease_pool
WEAK void drain_autorelease_pool(objc_id pool)
Definition: objc_support.h:50
Halide::Runtime::Internal::ns_log_utf8_string
WEAK void ns_log_utf8_string(const char *string)
Definition: objc_support.h:80
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
Halide::Runtime::Internal::ns_log_object
WEAK void ns_log_object(objc_id obj)
Definition: objc_support.h:88
Halide::Runtime::Internal::create_autorelease_pool
WEAK objc_id create_autorelease_pool()
Definition: objc_support.h:42
Halide
This file defines the class FunctionDAG, which is our representation of a Halide pipeline,...
Definition: AbstractGenerator.h:19
Halide::LinkageType::Internal
@ Internal
Not visible externally, similar to 'static' linkage in C.
objc_getClass
objc_id objc_getClass(const char *name)
objc_msgSend
void objc_msgSend(void)
objc_id
void * objc_id
Definition: objc_support.h:5
NSLog
void NSLog(objc_id format,...)
objc_sel
void * objc_sel
Definition: objc_support.h:6
sel_getUid
objc_sel sel_getUid(const char *string)
uint8_t
unsigned __INT8_TYPE__ uint8_t
Definition: runtime_internal.h:29
WEAK
#define WEAK
Definition: runtime_internal.h:52