13
  1. Does LLVM automatically convert Objective-C methods to inline functions when possible?

    (I.e., is it just as performant to create an Objective-C method for a block of code that you could otherwise paste inline?)

  2. If LLVM doesn't perform this optimization, why not? If it does, (a) are there certain build settings I must set for this to happen? (b) How can I tell if an Objective-C method will be inlined?

ma11hew28
  • 121,420
  • 116
  • 450
  • 651

3 Answers3

12

No, because its impossible to know in the context of the Obj-C runtime if those kind of optimizations can be performed. The thing to remember is that Obj-C methods are invoked by a message send, these messages can come from more than just the [myObject doSomething] syntax.

Consider [obj performSelector:NSSelectorFromString(@"hello")] the fact that this can happen means that it would be impossible to ever inline any method.

There is also a chain of events that happens when a message is received by a class, these events can reroute, or even change the message that is being sent. This happens transparently underneath the message send.

Joshua Weinberg
  • 28,598
  • 2
  • 97
  • 90
  • Why can't LLVM just replace regular calls, e.g., `[obj x]; obj.x` and `performSelector` calls, e.g., `[obj performSelector:x_sel]` , etc., with the method body of `x`? And, why can't it check the implementation of methods like `forwardInvocation:` to determine if it should inline? C'mon LLVM, be smarter! :) – ma11hew28 Nov 24 '11 at 05:39
  • 7
    Because they can be swapped out at runtime trivially. I can change the implenentafion of any method in 3 or 4 lines of runtime code. – Joshua Weinberg Nov 24 '11 at 14:04
9

No. It is an essential feature of Objective-C that message dispatch (remember that in Obj-C you send a message, you don't call a method) happens dynamically at runtime, not at compile time.

Because of this, a message dispatch in Obj-C will always be a little slower than a pure function call (even if the function is not inlined).

Ole Begemann
  • 135,006
  • 31
  • 278
  • 256
9

Let's assume for a moment that the compiler inlines a method:

@implementation AwesomeClass 

- (void)doFoo OBJC_INLINE { // or some way to indicate "this is an inline method"
  NSLog(@"doing foo!");
}

- (void)doBar {
  [self doAwesomeStuff];
  [self doFoo];
}

@end

so that -doBar essentially becomes:

- (void)doBar {
  [self doAwesomeStuff];
  {
    NSLog(@"doing foo!");
  }
}

Awesome, that seems like it'd be faster, right? We save ourselves a whole dozen instructions by not calling objc_msgSend. So you package this up and post it online as a .a file.

NSCleverCoder comes along and says "but I want doFoo to do a little bit more", so he does:

@interface SuperAwesomeClass : AwesomeClass @end
@implementation SuperAwesomeClass
- (void)doFoo {
  NSLog(@"doing more foo!");
  [super doFoo];
}
@end

When he tries to run this, it never gets called, because AwesomeClass never actually invokes the -doFoo method.

"But," you say, "this is a contrived example!"

No, it's not. In Objective-C, it is perfectly legal to do this at any point in the development or execution of an app. I can do this when writing the code. Heck, I can even do this at runtime by using objc_allocateClassPair and class_addMethod to dynamically create a subclass and add a method override.

I can also swizzle method implementations. Don't like the existing implementation of -doFoo? That's cool; replace it with your own. Oh wait; if the method was inlined, your new implementation would never get called, because -doBar is never actually invoking the -doFoo method.

The only time I could see this being possible is if there were some sort of way to annotate a method as being un-overridable. But there's no way to do that, so that issue is moot. And even then, it would still be a bad idea; just because the compiler doesn't let you do it doesn't mean you can't still work around it at runtime. And again, you'd run in to problems.

Dave DeLong
  • 242,470
  • 58
  • 448
  • 498
  • I guess I was just thinking the compiler could detect such cases where the method is being called within an overridden method and also insert it into the overriding method... But, I can see how to compiler would have to be pretty darn smart to do that. Still... ARC is pretty amazing... Maybe they could add another cool feature to LLVM that knows how to inline methods. – ma11hew28 Dec 02 '11 at 13:36