Loading...
Searching...
No Matches
objc_support.h
Go to the documentation of this file.
#ifndef HALIDE_OBJC_SUPPORT_H
#define HALIDE_OBJC_SUPPORT_H
extern "C" {
typedef void *objc_id;
typedef void *objc_sel;
extern objc_id objc_getClass(const char *name);
extern objc_sel sel_getUid(const char *string);
// Recent versions of macOS have changed the signature
// for objc_msgSend(), since its implementation is ABI-dependent.
// With this signature, users must always cast the call to the
// correct function type, and any calls without casting to the right
// function type will be caught at compile time.
//
// A good explanation of why is here: https://www.mikeash.com/pyblog/objc_msgsends-new-prototype.html
//
// The TL;DR is that objc_msgSend is special in that what it does is not touch
// the registers at all and 1) loads the ObjC class corresponding to the object, 2)
// looks up the selector in the class’s method cache, and 3) jumps to the location of
// the method if it’s in the cache. objc_msgSend takes as parameters an object,
// the method selector, then all the other parameters to the method; when it
// jumps to the method implementation, it's as if the method implementation was called
// directly.
// C doesn’t have a way to express this kind of function: the method implementation (usually) uses the ABI
// calling convention for a normal non-variadic function, but the C prototype for
// this has to be variadic. That used to be okay(ish) on x64 because the variadic and
// normal conventions are basically the same, but on ARM a variadic function passes
// all params on the stack, which would be a huge amount of overhead given how many
// times its called (every single method invocation in ObjC).
// The other problem with using a variadic signature is that C does type promotion on a variadic
// call.
extern void objc_msgSend(void);
void NSLog(objc_id /* NSString * */ format, ...);
}
namespace Halide {
namespace Runtime {
namespace Internal {
WEAK objc_id create_autorelease_pool() {
typedef objc_id (*pool_method)(objc_id obj, objc_sel sel);
pool_method method = (pool_method)&objc_msgSend;
objc_id pool = (*method)(objc_getClass("NSAutoreleasePool"), sel_getUid("alloc"));
pool = (*method)(pool, sel_getUid("init"));
return pool;
}
WEAK void drain_autorelease_pool(objc_id pool) {
typedef objc_id (*drain_method)(objc_id obj, objc_sel sel);
drain_method method = (drain_method)&objc_msgSend;
(*method)(pool, sel_getUid("drain"));
}
WEAK void retain_ns_object(objc_id obj) {
typedef objc_id (*retain_method)(objc_id obj, objc_sel sel);
retain_method method = (retain_method)&objc_msgSend;
(*method)(obj, sel_getUid("retain"));
}
WEAK void release_ns_object(objc_id obj) {
typedef objc_id (*release_method)(objc_id obj, objc_sel sel);
release_method method = (release_method)&objc_msgSend;
(*method)(obj, sel_getUid("release"));
}
WEAK objc_id wrap_string_as_ns_string(const char *string, size_t length) {
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);
typedef objc_id (*alloc_method)(objc_id objc, objc_sel sel);
alloc_method method1 = (alloc_method)&objc_msgSend;
objc_id ns_string = (*method1)(objc_getClass("NSString"), sel_getUid("alloc"));
init_with_bytes_no_copy_method method = (init_with_bytes_no_copy_method)&objc_msgSend;
return (*method)(ns_string, sel_getUid("initWithBytesNoCopy:length:encoding:freeWhenDone:"),
string, length, 4, 0);
}
extern "C" size_t strlen(const char *string);
WEAK void ns_log_utf8_string(const char *string) {
objc_id format_string = wrap_string_as_ns_string("%@", 2);
objc_id ns_string = wrap_string_as_ns_string(string, strlen(string));
NSLog(format_string, ns_string);
release_ns_object(ns_string);
release_ns_object(format_string);
}
WEAK void ns_log_object(objc_id obj) {
objc_id format_string = wrap_string_as_ns_string("%@", 2);
NSLog(format_string, obj);
release_ns_object(format_string);
}
} // namespace Internal
} // namespace Runtime
} // namespace Halide
#endif
Halide::Runtime::Internal
Definition constants.h:13
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::Runtime
Definition constants.h:12
Halide
This file defines the class FunctionDAG, which is our representation of a Halide pipeline,...
Definition AbstractGenerator.h:19
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