<div dir="ltr"><div><div><div>Hi,<br><br></div>I was in contact with Apple Developer Technical Support, and it was suggested that I send a question to this list.<br><br></div>I will post the complete conversation below, but to summarize.<br><br></div>I have a header file with this declaration:<br><br>protected: bool gravityFlipped_; <br>public: virtual bool getGravityFlipped(void) const { return gravityFlipped_; }<br>public: virtual void setGravityFlipped(bool val) { gravityFlipped_ = val; } <br><div><br></div><div>Everything works fine with optimization disabled -O0, but anything above that introduces issues. The getter seems to be changed in some way to the point where what it returns is garbage.<br><br></div><div>Simply copying the declaration and placing it somewhere else in the header fixes the problem. Removing the "virtual" tag, or adding a log in the getter/setter also fixes the problem.<br><br></div><div>I am out of ideas and any help you could provide would be great, thank you!<br><br></div><div>Best,<br></div><div>Robert<br><br></div><div>Below is the complete conversation with Apple DTS<br></div><div><br></div><div>MESSAGE 1:<br>-------------------------------------------------------<br>Hi,<br><br>I have run into a new problem that started happening once I moved from Xcode 6 to Xcode 7.<br><br>I am using a framework called Cocos2d-x using C++.<br><br>I am getting strange results when compiling with any code optimization above -C0.<br><br>I use a macro called CC_SYNTHESIZE to simply create getters/setters for a variable.<br><br>The macro is defined like this:<br><br>#define CC_SYNTHESIZE(varType, varName, funName)\<br>protected: varType varName;\<br>public: virtual varType get##funName(void) const { return varName; }\<br>public: virtual void set##funName(varType var){ varName = var; } <br><br>Here is an example of usage:<br>CC_SYNTHESIZE(bool, gravityFlipped_, GravityFlipped); <br><br>Without code optimization this works as intended, but with code optimization enabled this variable and others act erratically and does not change when the set function is called.<br><br>If I replace the macro and instead write the code manually it works with code optimization enabled.<br><br>protected: bool gravityFlipped_; <br>public: virtual float getGravityFlipped(void) const { return gravityFlipped_; }<br>public: virtual void setGravityFlipped(float val) { gravityFlipped_ = val; } <br><br>Any idea what the problem could be or any steps for troubleshooting?<br><br><br>RESPONSE 1:<br>-------------------------------------------------------<br>Hello Robert,<div>Thanks for contacting Apple Developer Technical Support (DTS).</div><div><br></div><div>In
general, DTS doesn’t answer questions regarding compiler optimizations,
but before I direct to you other resources about the compiler
optimizations, I wanted to mention a few things to you to investigate
before concluding this is indeed an optimizer question.</div><div><br></div><div>The
code generated by the macro is not identical to the code generated by
your direct implementation. Your macro produces code that is always
using the bool primitive type, while your long-hand version mixes bool
and float types. Is this an intentional difference?</div><div><br></div><div>What behavior does the Xcode 8 beta produce?</div><div><br></div><div>What
do the call sites that call your getter and setter look like? The call
sites could make a difference as well. It would be great if you could
provide a focused Xcode sample which I can run to see the same thing you
do, and make a note of Xcode version number (such as. 7.3.1) you are
using to run the sample.</div><br></div><div><br><br></div><div>MESSAGE 2:<br>-------------------------------------------------------<br><div><div><div><div><div><div><div>Hi,<br></div></div><br></div>You're
right, I accidentally wrote float as the return type. After changing
this to bool I get the same strange behaviour even without using the
macro.<br><br></div>I would create a test sample, but it could be tricky
since the error (so far) only seems to happen in regards to two
different variables in the whole game. What leads me to believe it is
optimizer related is the irregular behaviour.<br><br></div><div>I tried the project in Xcode 8 but got the same results. I am currently using Xcode 7.3.1.<br></div><div><br></div>For example here is the header for the class containing graviyFlipped.<br><br>class LevelSettingsObject : public cocos2d::CCNode<br>{<br>public:<br> LevelSettingsObject()<br> :startMiniMode_(false)<br> ,bGIdx_(0)<br> ,gIdx_(0)<br> ,isLimited_(false)<br> ,startDualMode_(false)<br> ,twoPlayerMode_(false)<br> ,gravityFlipped_(false)<br> ,_songOffset(0)<br> ,_fadeIn(false)<br> ,_fadeOut(false)<br> ,_level(NULL)<br> ,_songChanged(false)<br> ,_lastColorPage(0)<br> ,_gLineIdx(0)<br> ,_fontIdx(0)<br> {}<br> <br> ~LevelSettingsObject();<br><br> static LevelSettingsObject* create();<br> bool init();<br> <br> std::string getSaveString();<br> static LevelSettingsObject* objectFromString(std::string string);<br> static LevelSettingsObject* objectFromDict(cocos2d::CCDictionary *dict);<br> static LevelSettingsObject* objectFromMap(std::map<std::string, std::string> *map);<br> <br> void offsetMusic();<br> <br> const char* getAudioFileName();<br> <br>public:<br> CC_SYNTHESIZE_RETAIN(GJEffectManager*, _colorManager, ColorManager);<br><br> CC_SYNTHESIZE(int, startMode_, StartMode);<br> CC_SYNTHESIZE(int, startSpeed_, StartSpeed);<br> <br> CC_SYNTHESIZE(bool, startMiniMode_, StartMiniMode);<br> CC_SYNTHESIZE(bool, startDualMode_, StartDualMode);<br> <br> CC_SYNTHESIZE(bool, twoPlayerMode_, TwoPlayerMode);<br> <br> CC_SYNTHESIZE(float, _songOffset, SongOffset);<br> CC_SYNTHESIZE(bool, _fadeIn, FadeIn);<br> CC_SYNTHESIZE(bool, _fadeOut, FadeOut);<br> <br> CC_SYNTHESIZE(int, bGIdx_, BGIdx);<br> CC_SYNTHESIZE(int, gIdx_, GIdx);<br> CC_SYNTHESIZE(int, _fontIdx, FontIdx);<br> <br> CC_SYNTHESIZE(bool, isLimited_, IsLimited);<br><br> CC_SYNTHESIZE(bool, gravityFlipped_, GravityFlipped); // <---- The problem<br> <br> CC_SYNTHESIZE(GJGameLevel*, _level, Level);<br> <br> CC_SYNTHESIZE(std::string, _songString, SongString);<br> <br> CC_SYNTHESIZE(bool, _songChanged, SongChanged);<br> <br> CC_SYNTHESIZE(int, _lastColorPage, LastColorPage);<br> <br> CC_SYNTHESIZE(int, _gLineIdx, GLineIdx);<br>};<br><br><br></div>There
are no other variables in the parent class CCNode that are named
gravityFlipped, and this class is not inherited from, yet removing
"virtual" from the getter/setter fixes the problem. Also, moving the
line "CC_SYNTHESIZE(bool, gravityFlipped_, GravityFlipped);" from its
current position to the bottom (below _gLineIdx) also fixes the problem.
It just doesnt make any sense to me.<br><br></div><div>The call to the getter has nothing complicated in it, just a basic check:<br><br>void PlayLayer::setupLevelStart(LevelSettingsObject *settings)<br>{<br> if (settings->getGravityFlipped()) {<br> player_->flipGravity(true, true);<br> }<br><br>//...<br>}<br><br><br></div><div>RESPONSE 2:<br>-------------------------------------------------------<br>Hi Robert,<div>Good job so far on removing a lot of possible reasons for
this behavior - Xcode versions, removing the macro from the picture,
and seeing how the position of the variable within the declaration
affects this.</div><div><br></div><div>Have you ruled out multiple threads calling the getter and setter? That would be the most obvious thing to create this behavior.</div><div><br></div><div>Even
if only one thread is involved, it could be that the optimization level
is letting the CPU reorder the getter and setter calls. You could try
logging when each function is called and seeing if the order is what you
expect. I’d log a statement before the function is called, in the
implementation of the getter/setter, and after the function call
completes.</div><div><br></div><div>If everything is in the order you
expect, the addition of the log may have changed what the compiler does
to the function. In some cases, trivial method implementations inside
header files will be inlined to avoid the overhead of a function call.
If that’s happening here, adding the log may change if the function is
inlined, and change the behavior you see.</div><div><br></div><div>One
other thing to see what happens if you don’t let the compiler inline
these functions. I’d do this without the logging. The following
attribute does this: <span style="font-family:Helvetica;font-size:12px">__attribute__((noinline))</span></div><div><span style="font-family:Helvetica;font-size:12px"><br></span></div><div><span style="font-family:Helvetica;font-size:12px">as in:</span></div><div><span style="font-family:Helvetica;font-size:12px"><br></span></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(4,51,255)"><span>public</span><span style="color:rgb(0,0,0)">: </span><span>virtual</span><span style="color:rgb(0,0,0)"> </span><span>bool</span><span style="color:rgb(0,0,0)"> getGravityFlipped(</span><span>void</span><span style="color:rgb(0,0,0)">) </span><span>const</span><span style="color:rgb(0,0,0)"> </span><span>__attribute__</span><span style="color:rgb(0,0,0)">((noinline)) { </span><span>return</span><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(52,149,175)">gravityFlipped_</span><span style="color:rgb(0,0,0)">; }</span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px"><span style="color:rgb(4,51,255)">public</span><span>: </span><span style="color:rgb(4,51,255)">virtual</span><span> </span><span style="color:rgb(4,51,255)">void</span><span> setGravityFlipped(</span><span style="color:rgb(4,51,255)">bool</span><span> val) </span><span style="color:rgb(4,51,255)">__attribute__</span><span>((noinline)) { </span><span style="color:rgb(52,149,175)">gravityFlipped_</span><span> = val; }</span></p></div><div><br></div><br></div><div>MESSAGE 3:<br>-------------------------------------------------------<br><div><div><div><div>Hi,<br><br></div>Thanks for the suggestions.<br><br></div>I tried adding <span>__attribute__</span><span style="color:rgb(0,0,0)">((noinline)) to the functions but the problem still occured.</span><span style="color:rgb(0,0,0)"> I also tried adding logs in the getter/setter, but as you predicted once I did that the problem was fixed.</span><br><span style="color:rgb(0,0,0)"></span></div><span style="color:rgb(0,0,0)"><br></span></div><div><span style="color:rgb(0,0,0)">Next
I tried logging around the problem to see if I could find anything
interesting, and it seems like the getter is the main culprit.<br><br>I created the object, and used the setter to change the variable:<br><br>LevelSettingsObject *object = LevelSettingsObject::create();<br>object->setGravityFlipped(true);<br><br>CCLog("Gravity: %i, %i", object->getGravityFlipped(), object->gravityFlipped_);<br><br></span></div><div><span style="color:rgb(0,0,0)">The log produced this result: "Gravity: 1034696192, 1"<br><br></span></div><div><span style="color:rgb(0,0,0)">If I instead use: </span><span style="color:rgb(0,0,0)">object->setGravityFlipped(false);<br><br></span><span style="color:rgb(0,0,0)">The log produced this result: "Gravity: 1657850240, 0"<br><br></span></div><div><span style="color:rgb(0,0,0)">I also tried logging </span><span style="color:rgb(0,0,0)"><span style="color:rgb(0,0,0)"></span><span style="color:rgb(0,0,0)">getGravityFlipped()</span> in a scheduled function to see if it changes, but </span><span style="color:rgb(0,0,0)">getGravityFlipped() kept giving the same value. The value is random after each initialization, but then stays constant.<br><br></span></div><div><span style="color:rgb(0,0,0)">So accessing the variable directly works, but for some reason the getter is optimized out?<br><br></span></div><div><span style="color:rgb(0,0,0)">I
could move things around to make this specific problem go away, but
since I dont understand why it is happening it seems like too big a
risk.<br><br></span></div><div><span style="color:rgb(0,0,0)">RESPONSE 3:<br></span>-------------------------------------------------------<br>Rob,<span class="im"><blockquote type="cite" style="margin:0px;padding-left:10px;border-left:2px solid rgb(15,97,200);color:rgb(15,97,200)">I could move things around to make this specific problem go away, but since<br>I dont understand why it is happening it seems like too big a risk.</blockquote></span><div>I
agree - the position of the variable within the class definition
changing the result is especially curious. At this point, the issue
appears to be due to the code generated by the compiler, and beyond what
DTS can assist you with.</div><div><br></div><div>You should try
sending your question and what you’ve learned so far to the Clang Front
End Users mailing list, hosted by the LLVM open source project.</div><div><<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-users" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-users</a>></div><br></div><div><span style="color:rgb(0,0,0)"></span></div></div></div></div>