4 ms·
I don't remember why, but years ago I remember coming to the firm conclusion that it was impossible to write it in anything but assembly.
by sdegutis 10y ago
I don't remember why, but years ago I remember coming to the firm conclusion that it was impossible to write it in anything but assembly.
- pjmlp 10y agoI don't see why the naive approach to a possible implementation cannot be done in C, even if using extensions to ANSI C.
- ksherlock 10y agoDon't tell that to the GCC Objective C runtime. With the NeXT/Apple runtime, [object selector: arguments...] is syntactic sugar for objc_msgSend(object, @selector(selector:), arguments) With the GCC runtime, that's syntactic sugar for: IMP tmp = objc_msg_lookup(object, @selector(selector:)); tmp(object, @selector(selector:), arguments...) No assembly necessary. I believe there are also compiler flags to assume the function won't be replaced behind your back so objc_msg_lookup can be hoisted out of a loop, etc.
- DHowett 10y agoobjc_msg_lookup is very emphatically not objc_msgSend. Lookup operates differently from the nominally tail-calling msgSend in that it cannot support transparent forwarding (where the receiver is switched to another object before dispatch.) Since objc_msgSend is given control over the final call, the destination can be swapped if necessary. It's not possible[1] to implement objc_msgSend in plain (portable) C, as it needs to pass on an unknowable number of arguments without damaging the ones passed in registers, the stack frame, or the optional hidden return value pointer. Any methods attempting to do so using, say, naked functions and the method's type encoding will be more fragile than a perfect argument forwarding stub written in assembly. [1]: __builtin_apply_args, __builtin_apply and __builtin_return (https://gcc.gnu.org/onlinedocs/gcc-5.1.0/gcc/Constructing-Calls.html https://gcc.gnu.org/onlinedocs/gcc-5.1.0/gcc/Constructing-Ca...) notwithstanding.
- groovy2shoes 10y agoGCC's C is emphatically not "plain" (ANSI/ISO) C, but that does not mean it isn't "portable" C, given that GCC itself targets many platforms, and other compilers (clang, at least) do attempt to support GCC's dialect.
- DHowett 10y agoI couldn't find documentation that supports Clang offering the __builtin_apply intrinsics, but their availability would make a C objc_msgSend somewhat more palatable.
- groovy2shoes 10y agoAh. I don't mean to be too argumentative. You've helped me to understand why objc_msgSend() could not be done in standard C, and I thank you for that :) However, in the case of GCC's ObjC implementation, I don't see why it couldn't be implemented in GCC's dialect, thus obviating any need for assembly. Pardon me while I reflect on (and lament) the fact that we're still stuck using such crude and ancient tools for systems programming...
- lilyball 10y agoFWIW, it appears that Mulle-objc gets around this by actually changing the calling convention for Obj-C methods, so the IMP takes a single parameter (beyond self and _cmd) which is a struct that contains all of the method parameters. This way the compiler can just synthesize the struct for you, and then objc_msgSend() itself can be written in C because it just needs to pass the pointer to the struct along to the IMP rather than messing about with forwarding arbitrary arguments.
- groovy2shoes 10y agoInteresting. Thanks!
- groovy2shoes 10y agoI don't see anything w.r.t. objc_msgSend() that obviously prevents it from being written in C, as opposed to objc_msg_lookup(). I mean, worst case scenario, could it not just be: id objc_msgSend(id object, id selector, ...) { IMP tmp = objc_msg_lookup(object, selector); return tmp(object, selector, ...); } (forgive me for any mistyping here, as I'm not an Obj-C programmer, and for the varargs shorthand, to keep things simple)? Especially given that GCC supports some extensions to C that could reduce the overhead a bit (tail-recursion elimination, for example), I don't see why such a function couldn't be implementable in (GCC) C. Would you be willing to enlighten me?
- DHowett 10y agoIt's the ... that's the hard part; I've explained a little more here: https://news.ycombinator.com/item?id=13046391 https://news.ycombinator.com/item?id=13046391.
- ksherlock 10y agoConceptually, it is: IMP tmp = objc_msg_lookup(object, selector); goto *tmp; but C can't handle that (and even with gcc computed gotos you need to preserve any argument registers and not screw up the stack). objc_msgSend has a variable number of arguments and no way to determine how many there are.