, 18 tweets, 3 min read
My Authors
Read all threads
About objc_direct, a thread.

I should have probably anticipated that people would raise eyebrows and spent more time explaining the point in the LLVM commit, so here it is...
The Obj-C dynamic dispatch comes with many costs, this is common "knowledge". However the details of it are rarely known.

Beside the obvious cost of the h-lookup, it comes with 4 other kinds of costs:
- codegen size
- optimization barrier
- static metadate
- runtime metadata
(1) Codegen size:

In addition to `self`, `_cmd` is passed to objc_msgSend to be able to lookup your IMP. A selector is loaded from a GOT-like slot, called a selref, which in arm64 generates assembly akin to:

adrp x1, mySelector@PAGE
ldr x1, [x1, mySelector@PAGEOFF]
This is 8 bytes that you pay at every call site. The number of calls to objc_msgSend is large enough that these 8 useless bytes add up. For example, in CloudKit, these 2 instructions represent 10.7% of __text. This is fairly typical of Objective-C heavy code.
(2) Optimization barrier:

Swizzling is a powerful tool, but it requires huge guarantees from the compiler. People will call out "inlining" as the lost optimization, but it's way worse. Even without inlining, the optimizer cannot be allowed to know that a trivial readonly...
... integer property won't as a side effect release `self`, which in turn causes ARC to insert superfluous objc_retain()/objc_release() calls around the property access. Even without inlining, in an LTO world, ARC has the opportunity to be smarter because it sees more.
(3) Static metadata

An Objective-C method comes with extensive metadata (costs as of today, may change in a future runtime):
- a Method that is an entry in your class method list (24 bytes, 3 relocations)
- a type string (completely useless if you never use NSInvocation with it, easily 60+ bytes)
- a selector (average selector length is in the high 20ies bytes)
- a selref to articulate around it (8 bytes, 1 "relocation")
This is a grand total of typically 150-250 bytes of metadata and 4 relocations to be able to use it. I ignored the cost of the symbol table entry that a pure C call also has.

Properties are more costly as they have an entry in the property list, raising the toll even further
(4) Runtime metadata:

To perform a message dispatch, the runtime build IMP caches. This is not a small cost, and adds up quickly. The VAST majority of IMP caches entries aren't called often and are dead weight of dirty memory that is useless to the process.
Building that metadata is also more expensive when the amount of methods in your class is larger for quite obvious reasons.
So why direct methods/properties?

While it has always been possible to use C (and the compiler helps you by giving you visibility into your private ivars if you place the C function within your @implementation block), it is cumbersome and irregular in syntax.
It also comes with overhead of having to spell out self-> everywhere to access ivars, and also doesn't respect the create/new/... ARC rules which can lead to surprising performance issues. As such this is rarely used.
When used on a typical Obj-C framework, it is easy to reduce your binary size by 5% or more. Using LTO will easily make this win even larger. It means in turn that the working-set of the processes is smaller, which gives you more space for things that are actually useful.
As such, you now star to see that despite the obvious initial reaction which is "holy s**t this is great for hot code", the target audience is even more the long tail of rarely used monomorphic calls that are killing your binary size for very little added value.
Can it be used to prevent Swizzling?

Yes, obviously, for the reasons explained above, writing C functions is cumbersome, and rarely used, and an attribute makes it extremely cheap (in keystrokes) to do en masse.
However, not only wasn't it a motivation at all, but on the opposite, it is widely considered as an ABI risk and this risk has been at the center of many discussions. However, in many cases, the performance benefits vastly out-weight the ABI concern.
/ the end
Missing some Tweet in this thread? You can try to force a refresh.

Enjoying this thread?

Keep Current with Pierre Habouzit

Profile picture

Stay in touch and get notified when new unrolls are available from this author!

Read all threads

This Thread may be Removed Anytime!

Twitter may remove this content at anytime, convert it as a PDF, save and print for later use!

Try unrolling a thread yourself!

how to unroll video

1) Follow Thread Reader App on Twitter so you can easily mention us!

2) Go to a Twitter thread (series of Tweets by the same owner) and mention us with a keyword "unroll" @threadreaderapp unroll

You can practice here first or read more on our help page!

Follow Us on Twitter!

Did Thread Reader help you today?

Support us! We are indie developers!

This site is made by just three indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3.00/month or $30.00/year) and get exclusive features!

Become Premium

Too expensive? Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal Become our Patreon

Thank you for your support!