Vous l'avez expliqué vous-même. L'"adresse de retour", par définition, vous indique votre prochaine destination .
Il n'y a aucune exigence que l'adresse de retour qui est placée sur la pile soit une adresse à l'intérieur de la méthode qui a été utilisée. appelé la méthode dans laquelle vous vous trouvez actuellement. Il s'agit typiquement ce qui facilite grandement le débogage. Mais il n'y a pas de exigence que l'adresse de retour soit une adresse à l'intérieur de l'appelant. L'optimiseur est autorisé à modifier l'adresse de retour - ce qu'il fait parfois - si cela permet au programme d'être plus rapide (ou plus petit, ou tout autre objectif d'optimisation) sans en modifier la signification.
Le but de la pile est de s'assurer que lorsque ce sous-programme se termine, il est suite -- ce qui se passe ensuite -- est correcte. Le but de la pile n'est pas de vous dire d'où vous venez. Le fait qu'elle le fasse habituellement est un heureux accident.
De plus, la pile n'est qu'un détail de mise en œuvre des concepts de suite y l'activation . Il n'est pas nécessaire que les deux concepts soient mis en œuvre par la même pile ; il peut y avoir deux piles, l'une pour les activations (variables locales) et l'autre pour la continuation (adresses de retour). De telles architectures sont évidemment beaucoup plus résistantes aux attaques de destruction de pile par des logiciels malveillants, car l'adresse de retour ne se trouve nulle part à proximité des données.
Plus intéressant encore, il n'est pas nécessaire qu'il y ait une pile ! Nous utilisons les piles d'appels pour implémenter la continuation parce qu'elles sont pratiques pour le type de programmation que nous faisons habituellement : les appels synchrones basés sur des sous-routines. Nous pourrions choisir d'implémenter le langage C# en tant que langage "Continuation Passing Style", où la continuation est en fait réifié en tant que sur le tas et non comme un paquet d'octets poussés sur une pile système d'un million d'octets . Cet objet est ensuite transmis d'une méthode à l'autre, aucune d'entre elles n'utilisant de pile. (Les activations sont ensuite réifiées en décomposant chaque méthode en plusieurs délégués possibles, chacun d'entre eux étant associé à un objet d'activation).
Dans le style continuation passing, il n'y a tout simplement pas de pile et il n'y a aucun moyen de savoir d'où l'on vient ; l'objet continuation n'a pas cette information. Il sait seulement où vous allez ensuite.
Cela peut sembler être un charabia théorique de haute volée, mais nous transformons essentiellement C# et VB en langages de type "continuation passing". dans la prochaine version ; la fonctionnalité "async" à venir n'est qu'une continuation du style passing sous un fin déguisement. Dans la prochaine version, si vous utilisez la fonctionnalité asynchrone, vous abandonnerez essentiellement la programmation basée sur la pile ; il n'y aura aucun moyen de regarder la pile d'appels et de savoir comment vous en êtes arrivé là, parce que la pile sera souvent vide.
Les continuations réifiées en tant que quelque chose d'autre qu'une pile d'appels est une idée difficile à assimiler pour beaucoup de gens ; cela a certainement été le cas pour moi. Mais une fois qu'on l'a comprise, elle s'impose d'elle-même et prend tout son sens. Pour une introduction en douceur, voici un certain nombre d'articles que j'ai écrits sur le sujet :
Une introduction à CPS, avec des exemples en JScript :
http://blogs.msdn.com/b/ericlippert/archive/2005/08/08/recursion-part-four-continuation-passing-style.aspx
http://blogs.msdn.com/b/ericlippert/archive/2005/08/11/recursion-part-five-more-on-cps.aspx
http://blogs.msdn.com/b/ericlippert/archive/2005/08/15/recursion-part-six-making-cps-work.aspx
Voici une douzaine d'articles qui commencent par une plongée plus profonde dans le CPS, puis expliquent comment tout cela fonctionne avec la fonction "asynchrone" à venir. Commencez par le bas :
http://blogs.msdn.com/b/ericlippert/archive/tags/async/
Les langages qui supportent le style de passage de continuation ont souvent une primitive magique de flux de contrôle appelée "call with current continuation", ou "call/cc" en abrégé. Dans cette question de stackoverflow, j'explique la différence triviale entre "await" et "call/cc" :
Comment la nouvelle fonctionnalité asynchrone de c# 5.0 pourrait-elle être mise en œuvre avec call/cc ?
Pour mettre la main sur la "documentation" officielle (une série de livres blancs) et une version préliminaire de la nouvelle fonction "async await" de C# et VB, ainsi qu'un forum pour les questions-réponses, rendez-vous à l'adresse suivante :
http://msdn.com/vstudio/async