Pourquoi le code essaierait-il activement d’empêcher l’optimisation des appels de queue?

Le titre de la question est peut-être un peu étrange, mais le fait est que, pour autant que je sache, rien ne s’oppose à l’optimisation des appels. Cependant, lors de la navigation sur des projets open source, j’ai déjà rencontré quelques fonctions qui tentent activement d’empêcher le compilateur de procéder à une optimisation des appels de fin, par exemple l’implémentation de CFRunLoopRef qui est remplie de tels hacks . Par exemple:

static void __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__() __atsortingbute__((noinline)); static void __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(CFRunLoopObserverCallBack func, CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) { if (func) { func(observer, activity, info); } getpid(); // thwart tail-call optimization } 

J’aimerais savoir pourquoi cela semble si important, et y a-t-il des cas où, en tant que développeur normal, je dois garder cela à l’esprit? Par exemple. Y a-t-il des pièges courants avec l’optimisation des appels de queue?

    Je suppose que c’est pour s’assurer que __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ est dans la trace de la stack à des fins de débogage. Il a __atsortingbute__((no inline)) qui sauvegarde cette idée.

    Si vous remarquez que cette fonction ne fait que passer et rebondit sur une autre fonction, alors c’est une forme de trampoline que je ne peux que penser avec un nom aussi verbeux pour faciliter le débogage. Cela serait particulièrement utile étant donné que la fonction appelle un pointeur de fonction qui a été enregistré ailleurs et par conséquent, cette fonction peut ne pas avoir de symboles de débogage accessibles.

    Remarquez aussi les autres fonctions nommées de la même façon qui font des choses similaires – il semble vraiment que cela soit là pour aider à voir ce qui est arrivé depuis une trace. N’oubliez pas qu’il s’agit d’un code de base de Mac OS X et qu’il apparaîtra également dans les rapports d’incidents et les exemples de processus.

    Ce n’est qu’une supposition, mais peut-être pour éviter une boucle infinie vs un bombardement avec une erreur de débordement de stack.

    Comme la méthode en question ne met rien sur la stack, il semble possible que l’optimisation de la récursivité d’appel produise du code qui entrerait dans une boucle infinie par opposition au code non optimisé qui placerait l’adresse de retour sur la stack. qui finirait par déborder en cas de mauvaise utilisation.

    La seule autre chose que je pense est liée à la préservation des appels sur la stack pour le débogage et l’impression de stack.

    Une des raisons possibles est de faciliter le débogage et le profilage (avec le TCO, le cadre de la stack parent disparaît, ce qui rend les traces de stack plus difficiles à comprendre).