<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"><channel><title>mikeash.com pyblog/friday-qa-2009-04-24-code-generation-with-llvm-part-2-fast-objective-c-forwarding.html comments</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-04-24-code-generation-with-llvm-part-2-fast-objective-c-forwarding.html#comments</link><description>mikeash.com Recent Comments</description><lastBuildDate>Sun, 10 May 2026 05:15:07 GMT</lastBuildDate><generator>PyRSS2Gen-1.0.0</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Atii - 2013-04-16 06:42:55</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-04-24-code-generation-with-llvm-part-2-fast-objective-c-forwarding.html#comments</link><description>Hi Mike,
&lt;br /&gt;Thnx for the wonderful post. Would you also do a tutorial about fast enumeration using LLVM code generation technique and also suggest some more use of it in objective C. That would be really great.. :) </description><guid isPermaLink="true">db10b72720c9ea260f4f3e2a6e7158ae</guid><pubDate>Tue, 16 Apr 2013 06:42:55 GMT</pubDate></item><item><title>mikeash - 2009-06-10 23:21:13</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-04-24-code-generation-with-llvm-part-2-fast-objective-c-forwarding.html#comments</link><description>I searched around and found almost no information about the LLVM C API. What I did find indicated that it was incomplete, although that information was old.
&lt;br /&gt;
&lt;br /&gt;In any case, I figure that if you don't know C++ and you want to do this kind of thing, you probably ought to just learn it. LLVM is not a beginners' library, and C++, while an ugly and horrible language in so many ways, is also an essential part of an advanced developer's toolkit.</description><guid isPermaLink="true">6fac0e1480a4b1baa8ae72cd8dd7f262</guid><pubDate>Wed, 10 Jun 2009 23:21:13 GMT</pubDate></item><item><title>wombat - 2009-06-10 14:57:09</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-04-24-code-generation-with-llvm-part-2-fast-objective-c-forwarding.html#comments</link><description>Hi Mike,
&lt;br /&gt;
&lt;br /&gt;thanks for this two-part series on how to use LLVM. Although it seems most of the posters have misunderstood the purpose of the example, I'd like to encourage you to do some more "LLVM how-to" in the future.
&lt;br /&gt;
&lt;br /&gt;In particular, it would be interesting to see how the LLVM API's C-wrapper is used to call LLVM from C. Every Objective-C developer knows C of course, but not necessarily C++.</description><guid isPermaLink="true">aa38422fcd90271d3a565b44cbd8b488</guid><pubDate>Wed, 10 Jun 2009 14:57:09 GMT</pubDate></item><item><title>mikeash - 2009-04-26 11:22:10</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-04-24-code-generation-with-llvm-part-2-fast-objective-c-forwarding.html#comments</link><description>I didn't bother to look into the amount of overhead, although it's definitely an interesting question. It seems to be pretty fast. In testing I dropped the timer to half a second instead of five seconds, and I couldn't see any startup delay with that. Whether that means it's 100ms or 100us, I don't know. If you decide to test it, please post your results!
&lt;br /&gt;
&lt;br /&gt;As for the optimizations, it was pretty much just copy/paste from the tutorials for that section. Your best bet would be to read the LLVM documentation for the various stuff being passed to the FunctionPassManager.</description><guid isPermaLink="true">81004ade817a0e1e17a383a8fa628ae0</guid><pubDate>Sun, 26 Apr 2009 11:22:10 GMT</pubDate></item><item><title>Matt Gallagher - 2009-04-26 11:20:50</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-04-24-code-generation-with-llvm-part-2-fast-objective-c-forwarding.html#comments</link><description>Wow, this is a huge post. Even if you had the code written, it must have taken a while to put together.
&lt;br /&gt;
&lt;br /&gt;Thanks for taking the time!</description><guid isPermaLink="true">5cd7f55fe322a776d79f7e666cd7de1f</guid><pubDate>Sun, 26 Apr 2009 11:20:50 GMT</pubDate></item><item><title>david - 2009-04-26 10:10:23</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-04-24-code-generation-with-llvm-part-2-fast-objective-c-forwarding.html#comments</link><description>nice post -- any perf metrics on the time needed to dynamically compile the code? what about memory foot print? what kind of optimizations are being performed during code gen?</description><guid isPermaLink="true">bcc682bc993f858b7b0fff4e5c48b052</guid><pubDate>Sun, 26 Apr 2009 10:10:23 GMT</pubDate></item><item><title>mikeash - 2009-04-26 07:21:17</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-04-24-code-generation-with-llvm-part-2-fast-objective-c-forwarding.html#comments</link><description>The LLVM voodoo can't go in resolveInstanceMethod: because you can't get the true method signature there, as it's a class method. (My original implementation used that, and cheated by stashing the "current proxy" in a global variable, but that's just plain ugly.) However it shouldn't matter speed-wise because forwardInvocation: only happens once. After the initial setup, method dispatch goes straight to the newly generated function and never passes through forwardInvocation: again. The setup cost is already huge due to building and compiling this dynamically-created function, so a bit of extra work doing forwardInvocation: isn't going to matter.</description><guid isPermaLink="true">11277f93e13197c066857a426194a4b9</guid><pubDate>Sun, 26 Apr 2009 07:21:17 GMT</pubDate></item><item><title>jason - 2009-04-26 06:58:54</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-04-24-code-generation-with-llvm-part-2-fast-objective-c-forwarding.html#comments</link><description>Thanks Mr. Ash! I've been looking for just this for some time.</description><guid isPermaLink="true">f84712afdef282bfac1ce34eb2e81ae0</guid><pubDate>Sun, 26 Apr 2009 06:58:54 GMT</pubDate></item><item><title>Harvey - 2009-04-26 06:47:51</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-04-24-code-generation-with-llvm-part-2-fast-objective-c-forwarding.html#comments</link><description>Very nice!  Does it get much faster if you implement the llvm voodoo in resolveInstanceMethod: instead of forwardInvocation:?</description><guid isPermaLink="true">189da142de888707e21fc759cdb00242</guid><pubDate>Sun, 26 Apr 2009 06:47:51 GMT</pubDate></item><item><title>mikeash - 2009-04-26 04:09:06</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-04-24-code-generation-with-llvm-part-2-fast-objective-c-forwarding.html#comments</link><description>It is true that there's a difference between lookup done by the standard for loop and the one done by the HOM implementation. But neither one is correct for a loop that contains distinct method signatures for the selector in question. Consider this code:
&lt;br /&gt;
&lt;br /&gt;&lt;code&gt;for(id obj in array) [obj foo:bar];&lt;/code&gt;
&lt;br /&gt;
&lt;br /&gt;When the compiler generates the code for &lt;code&gt;[obj foo:bar]&lt;/code&gt;, it needs to know the method signature &lt;i&gt;at compile time&lt;/i&gt; in order to generate the correct code. (If foo: returns a struct, it needs to generate a call to &lt;code&gt;objc_msgSend_stret&lt;/code&gt;, if foo: takes a float, it needs to pass bar as a float, etc. In order to do this, is just looks at whatever declaration for a foo: method is in scope. If none is in scope, it assumes vararg calling conventions. If more than one is in scope, it picks one at random.
&lt;br /&gt;
&lt;br /&gt;While different from using the last object's method signature, it works no better.
&lt;br /&gt;
&lt;br /&gt;As for your second question, sure, both cases use bog-standard ObjC messaging to talk to the contents of the array and therefore do the exact same thing in terms of invoking forwarding methods.</description><guid isPermaLink="true">c1082b0b80a53e885a5f9e64cec4fdb4</guid><pubDate>Sun, 26 Apr 2009 04:09:06 GMT</pubDate></item><item><title>Steve Wart - 2009-04-26 02:54:50</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-04-24-code-generation-with-llvm-part-2-fast-objective-c-forwarding.html#comments</link><description>I think there's a difference between the dynamic method lookup done by the standard for loop and binding every object in an array to
&lt;br /&gt;
&lt;br /&gt;[[_array lastObject] methodSignatureForSelector:sel];
&lt;br /&gt;
&lt;br /&gt;if I have [NSArray arrayWithObjects:dog, cat, nil] and invoke @selector(bark) on each object, will the cat's forwardInvocation: method will be called in both the LLVM and the normal case? (assuming dog understands SEL(bark) but cat doesn't)
&lt;br /&gt;</description><guid isPermaLink="true">22fd66ddc22620ec461808171182bf49</guid><pubDate>Sun, 26 Apr 2009 02:54:50 GMT</pubDate></item><item><title>mikeash - 2009-04-26 01:48:35</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-04-24-code-generation-with-llvm-part-2-fast-objective-c-forwarding.html#comments</link><description>The difference between the 6x speedup and the factor of 1000 comes about because of all the other work that's going on. The thousand times slower comes from doing forwardInvocation: and nothing else. Here, the program creates two objects (the proxy and the array) and then does some more work on them.
&lt;br /&gt;
&lt;br /&gt;As for typing, this is just an inherent problem with Objective-C. Objective-C doesn't really tolerate having multiple methods in an application with the same selector but different signatures. It'll survive if you keep them well separated, but if you load them into an array and try to do something with them, you'll fall down. Even a standard for loop will break here. In practice, this problem does not occur very frequently. The array does not need to be homogenous, it just needs to have every object respond to that selector and use the same signature. In practice, the former will imply the latter.
&lt;br /&gt;
&lt;br /&gt;For what it does, Objective-C messaging is basically as fast as it can possibly be. At 13 CPU cycles on i386 there's little to shave further. Smalltalk can go faster &lt;i&gt;in some cases&lt;/i&gt; because it's actually doing something completely different. Namely, it's running a JIT compiler on the code at runtime, identifying places where dynamic dispatch can be eliminated due to proving what type of objects will be there, and doing a direct jump to the method in question or even inlining the implementation. That is, in fact, &lt;i&gt;exactly&lt;/i&gt; the sort of "invoking the compiler" that you say you don't think are where performance gains lie.
&lt;br /&gt;
&lt;br /&gt;One last note: since both comments so far seem to have missed this, it bears repeating. This example is &lt;i&gt;not meant to be practical&lt;/i&gt;. This post is "how to integrate LLVM-generated code with your real code", not "how to make your Objective-C go faster". Faster is not the goal of this code, illustration is. That it's also several times faster than the simple implementation is a nice bonus, but it's not the point.</description><guid isPermaLink="true">e8f297bb614ac15b4721947f8c36a21c</guid><pubDate>Sun, 26 Apr 2009 01:48:35 GMT</pubDate></item><item><title>Steve Wart - 2009-04-26 01:17:02</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-04-24-code-generation-with-llvm-part-2-fast-objective-c-forwarding.html#comments</link><description>Thanks for taking the time to put together this post. There are a couple of things I'm not comfortable with however.
&lt;br /&gt;
&lt;br /&gt;It seems unfortunate that you can only get a 6x speedup with the LLVM implementation when you say that forwardInvocation: is "about a thousand times slower" than direct method invocation. I wonder if there's a better approach than invoking the compiler to create a method on an arbitrary class. Dynamic translation and inline caching is probably the "right" approach, although this requires runtime support (there are some interesting comments about an approach to doing this with LLVM here &lt;a href="http://www.mirandabanda.org/cogblog/2008/06/06/cog/#comment-17"&gt;http://www.mirandabanda.org/cogblog/2008/06/06/cog/#comment-17&lt;/a&gt;).
&lt;br /&gt;
&lt;br /&gt;The second issue pertains to typing. Both the normal and the LLVM implementations obtain the method signature from the last object in the array. Setting aside the case of an empty array, assuming that the binding for the last object applies to every other object is not safe unless there is some way to ensure the array is homogeneous.
&lt;br /&gt;
&lt;br /&gt;Still, it's great to see these sorts of features being discussed for Objective-C. I was surprised to to come across some results indicating that Smalltalk message dispatching is still faster than the approach used in Objective-C (see the comment thread on this post &lt;a href="http://ridiculousfish.com/blog/?p=22"&gt;http://ridiculousfish.com/blog/?p=22&lt;/a&gt;). Obviously that's more than made up for by the ability to include as much "raw" C as you need, but it suggests that a good runtime can be used to improve performance as well as to provide dynamic access to type information.
&lt;br /&gt;
&lt;br /&gt;[I started building an equivalent test harness in Smalltalk but none of the implementations I am familiar with have a good quality microsecond timer. Eliot Miranda has some advice on how to do that so I might be able to cobble something together. I'll let you know how that goes :-)]
&lt;br /&gt;
&lt;br /&gt;I suspect that the best opportunities for performance gains for dynamic Objective-C code will come from a smarter runtime than from invoking the compiler in this way. Nonetheless, it's useful to have such a realistic and detailed example about using LLVM with Objective-C.</description><guid isPermaLink="true">a9e18f7c3429b267b9437c18b641f736</guid><pubDate>Sun, 26 Apr 2009 01:17:02 GMT</pubDate></item><item><title>mikeash - 2009-04-25 08:34:42</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-04-24-code-generation-with-llvm-part-2-fast-objective-c-forwarding.html#comments</link><description>I really don't see how your code is &lt;i&gt;easier&lt;/i&gt; than this:
&lt;br /&gt;
&lt;br /&gt;&lt;code&gt;NSArray *newArray = [[array map] stringByAppendingString:@"suffix"];&lt;/code&gt;
&lt;br /&gt;
&lt;br /&gt;One line versus three. If you're counting the support code to implement map, well, don't. You don't count the support code to implement arrayWithCapacity: in your version....
&lt;br /&gt;
&lt;br /&gt;As for your other one, that's nice and all, but falls apart the moment you want more parameters, or a parameter of a different type, which is most of the time.
&lt;br /&gt;
&lt;br /&gt;Looking further, a more sophisticated HOM implementation can do something like this:
&lt;br /&gt;
&lt;br /&gt;&lt;code&gt;NSArray *newArray = [[prefixes map] stringByAppendingString:[suffixes each]];&lt;/code&gt;
&lt;br /&gt;
&lt;br /&gt;To provide multi-array iteration.
&lt;br /&gt;
&lt;br /&gt;Of course blocks will pretty much put HOM to rest for most people who are aware of it in the first place, but the whole point of this example was to show how you could use LLVM, not to show how you could use HOM.</description><guid isPermaLink="true">57f54ecebba9a7ff454f5d1a93234e28</guid><pubDate>Sat, 25 Apr 2009 08:34:42 GMT</pubDate></item><item><title>Gwynne - 2009-04-25 06:41:58</title><link>http://www.mikeash.com/?page=pyblog/friday-qa-2009-04-24-code-generation-with-llvm-part-2-fast-objective-c-forwarding.html#comments</link><description>The LLVM approach is elegant and powerful, but I feel that it's worth noting that the particular problem you were solving here could done with the rather this rather easier code:
&lt;br /&gt;
&lt;br /&gt;&lt;div class="blogcommentquote"&gt;&lt;div class="blogcommentquoteinner"&gt;
&lt;br /&gt;NSMutableArray   *result = [NSMutableArray arrayWithCapacity:[array count]];
&lt;br /&gt;
&lt;br /&gt;for (NSString *str in array)
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[result addObject:[str stringByAppendingString:@"suffix"]];
&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;This code is less "Wow, look at the cool things I can do with Objective-C!"-ish, but it's simple, it works, and it doesn't incur the overhead of message forwarding. You could even generalize it with something like this:
&lt;br /&gt;
&lt;br /&gt;&lt;div class="blogcommentquote"&gt;&lt;div class="blogcommentquoteinner"&gt;
&lt;br /&gt;@implementation NSArray (PerformSelector)
&lt;br /&gt;- (NSArray *)arrayByApplyingSelectorToObjects:(SEL)selector withObject:(id)argOrNil
&lt;br /&gt;{
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;NSMutableArray    *result = [NSMutableArray arrayWithCapacity:[self count]];
&lt;br /&gt;
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for (id obj in self)
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (argOrNil)
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[result addObject:[obj performSelector:selector withObject:argOrNil]];
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[result addObject:[obj performSelector:selector]];
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}
&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return result; // Cast from mutable array to nonmutable array
&lt;br /&gt;}
&lt;br /&gt;@end
&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;This doesn't have the flexibility implied by using full-fledged message forwarding, but it'll work for a lot of cases.</description><guid isPermaLink="true">650ce4c11f98ac9267eeda368c6b4f83</guid><pubDate>Sat, 25 Apr 2009 06:41:58 GMT</pubDate></item></channel></rss>
