5 ms·
An Illustrated History of objc_msgSend
- gilgoomesh 13y agoFascinating stuff. It's so weird to realize that such a critical piece of code is still changing significantly after 10 years at NeXT and 10 years at Apple.
- kryptiskt 13y agoI think it's weirder that so often such critical bits still are the makeshift unoptimized first version. But I know how it works in the real world, it's good enough and there are no reported bugs, so don't touch it until you have implemented all these features and fixed all these issues....
- program 13y agoAs you can clearly see from the code it's perfectly acceptable in Objective-C to send a message to nil. This is a powerful feature that prevents the program from crashing but it is confusing for beginners.
- LinaLauneBaer 13y agoThe ability to send messages to nil is not only there to prevent crashes. It can also be used to make clean APIs or to use APIs with a lot of convenience. It also gives you a lot of flexibility... It allows you to do the error handling on a case by case basis. If you are not interested in erros simply do not check for nil and go on... Object *o = [Object new]; if(o==nil) { /*handle error and return */ return; } [o doSomething]; vs. Object *o = [Object new]; [o doSomething]; In the first case I catch a potential error explicitly and in the second case I simply send doSomething to nil which is perfectly fine.
- pavlov 13y agoIt doesn't seem particularly confusing. It's pretty much the first thing you learn: square brackets send a message, and if there's no recipient, the return value will be zero. (Granted, it used to be more complicated in the PowerPC era, when e.g. a selector that returns a double was not guaranteed to return 0.0 with a nil receiver, but those cases were fixed in the runtime.) I suspect the messaging-to-nil behavior is mostly confusing to intermediate programmers who only have experience with Java's passive-aggressive null references.
- MaxGabriel 13y agoPavlov, I think you meant square brackets
- pavlov 13y agoYes, thanks! (I still haven't learned the English names for the various brackets, it seems... In my mind, the ones with the straight angles are the "angle" ones.)
- unfunco 13y ago() parenthesis [] brackets {} braces
- pavlov 13y agoSo is there are single-word name for "angle brackets", the ones you write with less-than/greater-than symbols? If I had my way, I'd call them pointyparens.
- Someone 13y agoThe Hacker's Dictionary (http://www.dourish.com/goodies/jargon.html http://www.dourish.com/goodies/jargon.html) calls them Brokets, as shorthand for "broken brackets". And, by the way, the less pointy variant that is used in 'proper' typography is called a chevron or guillemet (http://en.wikipedia.org/wiki/Guillemet http://en.wikipedia.org/wiki/Guillemet)
- Someone 13y agoFor those learning English: parenthesis is the singular, parentheses the plural: ( opening parenthesis ) closing parenthesis () parentheses (( two opening parentheses )) two closing parentheses Way more info at http://en.wikipedia.org/wiki/Bracket http://en.wikipedia.org/wiki/Bracket
- 13y ago
- pavlov 13y agoIt's cool to get a look at a piece of assembly code that seems oddly familiar from all those times when my app has crashed in objc_msgSend due to a prematurely released object... (I still write non-ARC code for compatibility reasons. Sigh.) I find the following claim slightly misleading: 32-bit x86 was quickly overtaken by 64-bit, so this code received little attention after Tiger and many of those inefficiencies remain to this day. There are still major 3rd party apps that run in 32-bit mode on the Mac. Google Chrome is probably the most popular.
- chrisdevereux 13y agoProbably a more accurate claim would be: The 32-bit x86 runtime was quickly overtaken by 64-bit. 32-bit apps will mostly be cross-platform C++ codebases, which, if they use Obj-C at all, will do so very minimally.
- mikeash 13y agoIt's perfectly correct from Apple's perspective (which is the perspective from which this article is written). Apple started shipping 64-bit Intel Macs less than a year after they started shipping Intel Macs at all. OS X 10.4 was the first version to support Intel, 10.5 was the first version to fully support 64-bit, and by 10.6 most of the system was running 64-bit. 10.7 dropped support for 32-bit Macs entirely. Apple had little reason to improve 32-bit since apps can simply target 64-bit if they want the speed improvement. From Apple's perspective, Chrome makes a deliberate choice to run in that environment and they have no particular reason to help them out.
- jamesaguilar 13y agoAnyway, since Chrome is mostly C++ code, especially in the inner loop, I doubt that a faster objc_msgSend would noticeably improve performance.
- chc 13y ago"X was quickly overtaken by Y" does not imply "X completely vanished." Yes, a few notable apps are still 32-bit. But if you look at all Mac OS X programs in existence, a very healthy majority preferentially target the 64-bit platform. The 32-bit apps are the odd ducks, no matter how big a couple of those ducks have grown.
- taspeotis 13y agoDoes anyone know if this function is actually written in asm? Case in point: The code was probably originally written for NeXT by an engineer who was familiar with load-store architectures like PowerPC but not so familiar with register-memory architectures like x86 ... Those of you who do know x86 better may be able to identify some of the inefficiencies in this code Why wouldn't/couldn't this function be written in C (are there any instructions that would need some non-portable intrinsics?) and leave it to an optimizing compiler to get the instructions right. Sure, sending messages is low-level and needs to be high performance but that, to me, doesn't necessitate "we have to do this by hand" asm instead of C.
- fyolnish 13y agoIt can't be written in C since the stack/registers need to be preserved for the call to the actual method implementation.
- pavlov 13y agoIf you don't care about performance, you can do the method lookup in C, and have the asm implementation of objc_msgSend simply call that C function and then the returned method. A working implementation of this minimal objc_msgSend can be found in Cocotron sources: http://code.google.com/p/cocotron/source/browse/objc/platform_linux/objc-msgsend.s http://code.google.com/p/cocotron/source/browse/objc/platfor... It's the commented-out piece of code at line 10. Here's the C function it calls: http://code.google.com/p/cocotron/source/browse/objc/objc_msg_lookup.m http://code.google.com/p/cocotron/source/browse/objc/objc_ms...
- fyolnish 13y agoSure but that would probably be about as performant as: `(objc_lookupImp(obj, sel) ?: objc_nilImp())(obj, sel, ..params..)` (I realize you said "if you don't care about performance", but ObjC would be a pretty terrible language if it wasn't fast)
- 13y ago
- fyolnish 13y agoWhere does he get that code from? The actual objc_msgSend function is much much longer and employs a bunch of other tricks.
- mikeash 13y agoWhere do you get that idea? What's shown is it. There's a lot more to the message send system, but the rest is helpers that live outside of objc_msgSend and aren't on the fast path. There's no room for "a bunch of other tricks", because objc_msgSend needs to be as fast as possible, and the more it does, the slower it'll run.
- jws 13y agoIn the Mavericks version there are two jumps to labels that are not present in the code shown. One is for tagged pointers, the other is for a cache miss. The cache miss is probably interesting, tricky code. Apropos nothing… the cache search algorithm is "enter at predictable point, linear search everything". When one thinks of all the PhD time spent developing and analyzing search data structures, this is a good reminder that at small N, other factors dominate. Also, adding a one byte instruction prefix that you know will be ignored because your processor is happier if instructions aren't so bunched up is so close to witchcraft that the author should avoid campfires with stakes in the center.
- mikeash 13y agoThe cache miss may or may not be interesting, depending on your interests, but it's all written in C and is much longer and more boring. As soon as you miss the cache, you're off the fast path, so the cache miss code in objc_msgSend just does the requisite register preservation and then calls into C.
- nviennot 13y agoRelated: If you want to see what messages are being passed around in your programs, you can use this: https://github.com/nviennot/objc-tracer https://github.com/nviennot/objc-tracer
- adamnemecek 13y agoWhile this was probably an interesting exercise, I should remind everyone that one can get the same functionality by setting the environment variable NSObjCMessageLoggingEnabled to YES.
- jarjoura 13y agoWould be great to see the changes made in the ARM variants too. I know there's no value in compiling libobjc for ARM, but at least for academic value.