objc_msgSend is the Objective-C message
dispatcher. It's the function-calling function, using selector and
the receiver object's class to decide where to jump
to. objc_msgSend_stret is exactly the same, but for
methods that return values of struct types. Why does
objc_msgSend_stret exist?
Because of the machine-level guts of the C language require it,
and Objective-C methods are C functions if you tilt your head and
squint a bit.
On most processors, the first few parameters to a function are
passed in CPU registers, and return values are handed back in CPU
registers. Objective-C
methods do the same, but with id self and SEL
_cmd as the first two parameters. Here's a PowerPC example:
-(int) method:(id)arg;
r3 = self
r4 = _cmd, @selector(method:)
r5 = arg
(on exit) r3 = returned int
CPU registers work fine for small return values like ints and
pointers, but structure values can be too big to fit. For structs,
the caller allocates stack space for the returned struct,
passes the address of that storage to the function, and the
function writes its return value into that space. The address of
the struct is an implicit first parameter just like
self and _cmd :
-(struct st) method:(id)arg;
r3 = &struct_var (in caller's stack frame)
r4 = self
r5 = _cmd, @selector(method:)
r6 = arg
(on exit) return value written into struct_var
Now consider objc_msgSend 's task. It uses
_cmd and self->isa to choose the
destination. But self and _cmd are in
different registers if the method will return a struct, and
objc_msgSend can't tell that in advance. Thus
objc_msgSend_stret : just like
objc_msgSend , but reading its values from different
registers.
But there's a catch.
On most architectures, some small C structs are returned in registers
after all, instead of using the struct-address first parameter
that objc_msgSend_stret expects. If the struct type
falls into this category, then objc_msgSend is used
instead. So the "struct return" part of
objc_msgSend_stret refers to the architecture's
definition of a stack-returned struct, which may not match C struct.
The rules for which struct types return in registers are always
arcane, sometimes insane. ppc32 is trivial: structs never return in
registers. i386 is straightforward: structs with
sizeof exactly equal to 1, 2, 4, or 8 return in
registers. x86_64 is more complicated, including rules for
returning floating-point struct fields in FPU registers, and
ppc64's rules and exceptions will make your head spin. The gory
details are documented in the Mac
OS X ABI Guide, though as usual if the documentation and the
compiler disagree then the documentation is wrong.
If you're calling objc_msgSend directly and need to
know whether to use objc_msgSend_stret for a
particular struct type, I recommend the empirical approach: write
a line of code that calls your method, compile it on each
architecture you care about, and look at the
assembly code to see which dispatch function the compiler
uses.
|