# Reducing Objective-C overhead in Rust
## A brief overview of Objective-C selectors
An Objective-C selector is an interned string that is exposed as a pointer. It is an important argument for `objc_msgSend`.
`objc_msgSend` is an `extern "C"` function that is... very special. It serves as a key component for FFI interface to the Objective-C runtime. For the purpose of the rest of this explanation, we are going to pretend the signature of `objc_msgSend` and the selector looks like the following, but in actuality, the way this function is truly called is... more interesting.
```rust
unsafe extern "C" {
type ObjCSelector;
type ObjCObject;
fn objc_msgSend(this: Id, op: Selector, ...) -> Id;
}
type Id = *mut ObjCObject;
type Selector = *mut ObjCSelector;
```
Objective-C is a very classical object-oriented programming language, where the Objective-C language's method calls are literally "sending a message". This selector is part of this message, and determines
- what method to invoke on `this`
- what arity `objc_msgSend` has been called with
### Obtaining selectors at runtime
A `CStr` can be interned into a `Selector` at runtime by calling `sel_registerName`.
```rust
unsafe extern "C" {
fn sel_registerName(cstr: *mut c_char) -> Selector;
}
```
This can induce a considerable amount of runtime overhead if you already know what methods you want to call. Being forced to do this can be unfortunate for performance on Apple platforms, as Objective-C is a core component of a considerable amount of Apple software.
### Obtaining selectors during linkage
Apple's linkers and dynamic loader support the following convention:
- At compile time, a `Selector` is placed in specific sections that Apple linkers and loaders will examine. It initially points to a nul-terminated string that identifies the method it wishes to become a selector of, again found in a specific section.
- During dynamic loading, the `Selector` is replaced with an opaque/interned pointer.
This can be thought of as emulating a call to `sel_registerName`. However, the dynamic loader already has the answers to this question and does not need to perform any further calls to do this.
Importantly, all instances of a `Selector` that have the same pointee after dynamic loading are interchangeable. They are merely a value. The address this `Selector` might be initially loaded from in the binary is irrelevant.
## The Problem
For Rust, using the existing `#[export_name]` and `#[link_section]` attributes might seem like the obvious solution. However, the way Rust does code generation causes a problem: these symbols are often used inside functions, and code that is instantiated in a caller crate, such as generic and inline code, can wind up separated from the `Selector` symbols. Apple linkers treat symbols in these specific sections specially and expect selectors to be defined in in every object file where they're referenced. Any attempt to reference symbols in these sections from another object file results in undefined symbol errors at link time.
## The Fix
alternatives:
- `#[define_in_every_cgu_used] static`
- `objc_selector!`
### `#[define_in_every_cgu_used] static`
The initial proposal to fix this involves a special attribute which addresses how Rust partitions its code generation units (CGUs). Selectors would involve a `static` with the `#[define_in_every_cgu_used]` and `#[link_section]` attributes. Multiple instances of a `static` defined this way in multiple CGUs would be fine because they would become unified into one "true" static.
```rust
#[inline]
pub fn invoke_method(this: Id) {
#[define_in_every_cgu_used]
#[link_section = "__TEXT,__objc_methname,cstring_literals"]
static METHOD_NAME: [u8; 11] = b"methodName\0";
#[define_in_every_cgu_used]
#[link_section = "__DATA,__objc_selrefs,literal_pointers"]
static mut SELECTOR: Selector = METHOD_NAME.as_ptr().cast();
// SELECTOR value gets replaced at runtime by the dynamic loader.
unsafe { objc_msgSend(this, SELECTOR) };
}
```
An experimental implementation of this attribute can be found here:
[https://github.com/rust-lang/rust/compare/master...jbatez:rust:define_in_every_cgu_used](https://github.com/rust-lang/rust/compare/master...jbatez:rust:define_in_every_cgu_used)
The idea of using `linkonce_odr` came up with it due to its use in C++ and resembling the desired task. However, it's hard to say whether that will have the desired behavior in the actual context of Objective-C interop since this isn't what native Objective-C does. In addition, it has the problem that the linkage is only unified at compile-time, which may cause issues with Rust dylibs.
Using `weak` linkage also came up but it has the same problems.
A solution that focuses more narrowly on Objective-C interop may be preferable to one that has a broader focus.
### `objc::selector!`
A more laser-targeted approach would be to have a macro specifically for this purpose, with indeterminate implementation details. It would simply return the final selector value and hide the fact that it's being loaded from a special global.
```rust
#[inline]
pub fn invoke_method(this: Id) {
let selector = objc::selector!(methodName);
unsafe { objc_msgSend(this, selector) };
}
```
This approach removes the need to consider what happens when `#[define_in_every_cgu_used]` is used outside the context of a special `link_section` and what happens if the multiple copies aren't combined into one "true" static.
#### impl details
There are currently two experimental implementations of this macro. The first introduces a whole new type of expression.
```rust
#[allow_internal_unstable(builtin_syntax)]
pub macro selector($($methname:tt)+) {
builtin # objc_selector ( $($methname)+ )
}
```
It works, but the number of new enum variants and match arms required throughout the compiler was deemed undesirable. You can find it here for reference:
[https://github.com/rust-lang/rust/compare/master...jbatez:rust:core_ffi_objc](https://github.com/rust-lang/rust/compare/master...jbatez:rust:core_ffi_objc)
The latest implementation uses a new rustc internal attribute on an extern static instead. It results in significantly fewer compiler code changes at the cost of a slightly larger macro.
```rust
#[allow_internal_unstable(rustc_attrs)]
pub macro selector($methname:expr) {{
unsafe extern "C" {
#[rustc_objc_selector = $methname]
safe static VAL: $crate::os::darwin::objc::SEL;
}
VAL
}}
```
Objective-C class references can also be initialized at dynamic load time using a similar ABI. This branch builds upon the above and adds an `objc::class!(...)` macro as well: [https://github.com/rust-lang/rust/compare/master...jbatez:rust:darwin_objc](https://github.com/rust-lang/rust/compare/master...jbatez:rust:darwin_objc)