[cfe-users] Expected return value when making Objective C method call on nil object
David Hunt
david.hunt at marmalademail.com
Mon Dec 2 12:01:16 PST 2013
Nick Tuckett <nick.tuckett at ...> writes:
>
> I was wondering if there is an agreed behaviour for Clang compiled
> Objective C when making a method call on a nil object? If so, does
> this define exactly what should be returned in all cases, or are any
> cases left as "undefined"?
>
> With releases 3.1, 3.2 and 3.3 I've been finding some variation
> between very subtly different simple cases when the method called
> returns a C structure by value.
>
> For example, given this class:
>
> typedef struct {
> int x;
> int y;
> int z;
> } Vec3;
>
> <at> interface Fuzz : NSObject {
> Vec3 data;
> }
> <at> property Vec3 data;
> <at> end
>
> <at> implementation Fuzz
> <at> synthesize data;
> <at> end
>
> This code will leave the variable "vec" uninitialised:
>
> Fuzz * obj = nil;
> Vec3 vec = obj.data;
>
> Whereas this code will initialise the fields of "vec" all to zero:
>
> Fuzz * obj = nil;
> Vec3 vec;
> vec = obj.data;
>
> I've studied the assembly code generated for x86 and ARM both in
> unoptimised and optimised builds, and it would appear that return
> value optimisation is applied regardless in the first example (even
> with -O0).
>
> This results in "vec" remaining uninitialised as though it generates
> an initialised temporary on the stack, it is never copied into "vec"
> nor is "vec" explicitly initialised to zero if obj is nil.
>
> If obj is not nil, obviously the returned values go straight into vec
> as one would expect with RVO.
>
I have been investigating this. It only happens in the -fgnu-runtime,
the Next runtime appears to handle it correctly in both the double and
triple line cases. (In so far as the aggregate is cleared when called with
a nil pointer).
The fact it works correctly in the three line case with gnu runtime appears
to be an unintended side effect of uncertainty about pointer aliasing.
Specifically AggExprEmitter::EmitMoveFromReturnSlot in CGExprAgg.cpp
will emit directly into the return slot unless the pointer could be aliased,
as it could be in the 3 line case.
This optimisation is fine, except in the case of ObjC nil receivers.
BTW: I notice that even in cases where the return by value is elided into
the return value, space is redundantly reserved and cleared for a copy
of the aggregate (gnu runtime), which is then never used. Clearly the
assumption is that it is supposed to always be used.
More information about the cfe-users
mailing list