objc_msgSend is the Objective-C message
dispatcher. objc_msgSend_stret is exactly the same,
but for methods that return values of struct types. And
objc_msgSend_fpret is for methods that return
floating-point values on some architectures.
| objc_msgSend_fpret return types |
i386 |
float , double , long double |
x86_64 |
long double |
ppc |
none (identical to
objc_msgSend ) |
ppc64 |
arm |
objc_msgSend_stret exists because the parameters are
passed in different places for struct-returning functions. That's
not the problem that objc_msgSend_fpret
solves. Instead, objc_msgSend_fpret exists to handle
the return value itself correctly. Specifically, the return value
of a message sent to nil on i386 and x86_64.
Messages to nil return zero if possible. On ppc,
objc_msgSend with a nil receiver clears registers r3,
r4, f1, and f2 before returning. This means any pointer or integer
or floating-point return value will be zero, and structs are
undefined. On ppc, objc_msgSend_fpret is unnecessary,
because clearing f1 and f2 is harmless if the caller is actually
expecting a value in r3 or r4.
i386 is different. The floating-point registers there are
historically derived from the 8087 FPU for the original 8086
CPU. The x87 unit is an odd beast: it has eight floating-point
registers, but the registers themselves are used as if they were a
stack. Values are pushed and popped from this stack even though
the stack is stored in registers and has a maximum of eight
entries.
For return values, the callee pushes the value on the x87
stack and the caller pops it. This is fine for C functions, but
not so good when objc_msgSend returns
zero. objc_msgSend does not know what return type the
caller really wants, and it must not push a zero on the x87
stack unless the caller expects to pop a floating-point value.
The solution is objc_msgSend_fpret . During a message
to nil on i386, objc_msgSend_fpret pushes a zero on
the x87 stack which the caller will pop, and
objc_msgSend does not. The caller knows which return
type the caller expects, and uses the matching dispatcher. On ppc,
ppc64, and arm, objc_msgSend_fpret is identical to
objc_msgSend and is usually unused.
What about x86_64? This architecture is one step forward,
two steps back. The good news is that return values of types
float and double are returned in the XMM
registers. objc_msgSend can handle that itself just
like ppc. The bad news is that long double still uses
the x87 stack. So objc_msgSend_fpret still exists,
but is only used for long double on x86_64. The worse
news is that C99's complex long double returns two
values on the x87 stack. So now there's
objc_msgSend_fp2ret for that case only. Currently no
compiler actually uses objc_msgSend_fp2ret , so
hopefully nobody is writing code that sends a message to nil on
x86_64 and expects a zero return value of type complex long
double .
One last thing: Mac OS X 10.4 and earlier did not return zero for
floating-point messages to nil on ppc. Be careful if you're
writing code for those older systems. All other architectures have
always returned floating-point zero, including i386 on 10.4.
|