Objective-C message-to-nil optimization?

Just curious if clang optimizes ObjC messages that it knows have a nil
receiver?

I'm converting a subclass of NSTextStorage to lazily create its backing
store. To make this very clear to readers, I want to wrap all accesses
to the backing store in conditional checks.

For example:

- (NSUInteger)length;
{
  return _contents ? _contents.length : 0;
}

Strictly speaking, this is unnecessary, because sending -length to nil
will result in 0 anyway.

Part of the reason I'm making this change is for optimization, so I'd
feel a lot better if I knew that clang would optimize away conditional
expressions when it determines that they are 1) solely determined by the
NULL-ness of an object and 2) the result of evaluating either branch is
known to be exactly equal to sending the message to the receiver.

Is this something that clang does already?

--Kyle Sluder

Hi, Kyle. It looks like Clang does not perform this optimization, even under -O3 or -Oz. I can guess why: even though sending a message to nil will result in 0, it’s still more work to call objc_msgSend, have it do the comparison to nil, and then have it clean things up properly to return 0. (In fact, you can poke at the source for objc_msgSend and see exactly how much work it is: not much, but still more than doing the check yourself.)

I could see this being a valid optimization for -Os or -Oz mode, though, where the stated goal of optimization is to make the program fast and minimize code size. If you agree, you can file a bug at http://llvm.org/bugs/, or against Apple at http://bugreport.apple.com.

Jordan

Hi, Kyle. It looks like Clang does not perform this optimization, even under -O3 or -Oz. I can guess why: even though sending a message to nil will result in 0, it’s still more work to call objc_msgSend, have it do the comparison to nil, and then have it clean things up properly to return 0. (In fact, you can poke at the source for objc_msgSend and see exactly how much work it is: not much, but still more than doing the check yourself.)

Understood. Though I’m curious: is there a hard-and-fast rule against optimizations introducing function calls and/or branches where they would otherwise not appear?

Nonetheless, this optimization also introduces the possibility of involving the nil message handler (which AFAIK is undocumented), so there is a semantic difference as well as a performance difference.

I could see this being a valid optimization for -Os or -Oz mode, though, where the stated goal of optimization is to make the program fast and minimize code size. If you agree, you can file a bug at http://llvm.org/bugs/, or against Apple at http://bugreport.apple.com.

Will do. I might even gin up a patch myself; I’m on a bit of an exploratory kick.

Thanks,
–Kyle Sluder

I didn’t want to muddy the situation, but yes, that is exactly a case where messaging nil will not be equivalent. That might actually mean you’d end up having to hide your optimization behind a flag. Since the custom nil receiver is so rare, though, it might be okay to be on by default. (Can you tell that’s not my area of the compiler? :slight_smile: )

Jordan