• Aucun résultat trouvé

Le langage des observateurs

Nous définissons ici un langage d’aspect qui assure que tout aspect défini avec ce langage est un observateur. Comme vu à la Section 3.4.1 (page 61), un observateur ne modifie pas le flot de contrôle du programme de base mais insère uniquement des instructions ne modifiant pas l’état de base (ia). Afin d’être compatible avec AspectJ et la majorité des langages à aspects, nous considérons des aspectsarounddont l’action est composée d’instructionsiaavec une unique commandeproceedpour exécuter l’instruction filtrée. Quand l’action termine son exécution, le programme de base continue à l’instruction qui suit celle filtrée.

Notre instructionproceedn’a pas de paramètre car dans le cas contraire, l’aspect pourrait modifier les paramètres des procédures et changer arbitrairement le flot de contrôle ou l’état du programme de base. L’action doit également terminer, sinon le programme de base ne peut poursuivre son exécution et son flot de contrôle est donc modifié. Nous assurons cette termi-naison en empêchant l’emploi de la commandewhiledans l’action, en vérifiant qu’il n’existe

aucun cycle dans le graphe d’appel des procédures de l’action et en assurant que tout point de coupure ne puisse pas filtrer les instructions de son action. Une autre option serait de lever ces restrictions et de laisser ainsi le programmeur assurer cette terminaison. La préservation serait garantie modulo la terminaison des actions.

La seconde condition qu’un observateur doit respecter est de ne pas modifier l’état du pro-gramme de base (c.-à-d.,les instructionsiane changent pasΣb). Pour cela, le langage distingue les variables du programme de base (qui peuvent être lues par l’action) et les variables de l’as-pect (qui peuvent être lues et écrites paria).

La sémantique deproceedest exprimée à l’aide d’une pile proceed (ΣP) dans l’état global

Σ. Lorsqu’un aspectaroundest tissé, l’instruction filtrée est placée au sommet de cette pile (voir Section 2.3.3, page 46). La commandeproceed dépile et exécute l’instruction en som-met de pile proceed. Comme ici, l’action possède exactement unproceed, la Règle PROCEED

(voir page 46) est simplifiée en supprimant l’instruction sémantique pushp. Cette instruction permettait de replacer l’instruction filtrée au sommet de la pile proceed afin qu’elle puisse être réexécutée par un autreproceedde l’action.

PROCEED ΣP =i: ΣP

(proceed:C, X∪ΣP)→(i:C, X ∪ΣP)

La syntaxe des observateurs est définie par la Grammaire 11.

GRAMMAIRE11. Aspo ::= Do around P {So 1; proceed ; So 2} Do ::= var go := Ao |proc po(lo 1, . . . , lo n)So | Do 1;Do 2 So ::= Vo := Ao |po(Ao 1, . . . , Ao n)|So 1;So 2 |skip| if(Bo) then So 1 else So 2 |loop(Ao)So Ao ::= n |V |Ao 1+Ao 2A Bo ::= true |Ao 1 = Ao 2 |Ao 1 < Ao 2 |Bo 1 & Bo 2 | !BoB Vo ::= go |lo V ::= Vo |g |βV

Un observateurAspo définit des variablesgoet des procédures po qui forme son état local. C’est un aspect du typearoundqui associe un point de coupure avec une action qui contient exactement unproceed. Pour simplifier la présentation, nous avons considéré que l’aspect a un point de coupure et une action mais cela peut être facilement généralisé à plusieurs points de coupure et actions. Les déclarations Do ne doivent pas contenir de variables de motif car les valeurs étant associées aux variables de motif par l’intermédiaire des points de coupure, s’il existe de variables de motif utilisées dans les déclarations qui n’apparaissent pas dans les points de coupure, celles-ci se retrouveront sans valeur après la substitution. Par exemple, si

var x := βA est une déclaration alors βA se retrouvera sans valeur après la substitution s’il n’apparait pas dans le point de coupure. Les autres instructions So sont similaires aux motifs

Sp mais sans la négation ¬. En effet, une action doit être un code exécutable valide après la substitution de ses variables de motif (βABV). Remarquons que l’instructionabortne peut pas être employée dans l’action car elle changerait le flot de contrôle du programme de base. De façon similaire, la variable de motif pour les commandesβSne peut pas être utilisée car elle pourrait filtrer et exécuter des affectations aux variables du programme de base. Les affectations dans l’action modifient uniquement les variables de l’aspect (Vo). Bien sûr les variables de l’aspect comme celles du programme de base (V

) peuvent être lues. Enfin, une action ne peut appeler que des procédures définies (po) dans l’aspect car appeler une procédure du programme de base modifierait le flot de contrôle (et potentiellement l’état) du programme de base.

Un aspect qui compte les appels àfib(Exemple 19) est défini par l’Exemple 21. Cet aspect de profilage respecte la grammaireAspoet est donc un observateur

EXEMPLE21. L’aspect suivant enregistre dans la variablenle nombre d’appels àfib.

var n:=0;

around fib(βA) {n:=n+1; proceed; skip}

Il filtre tout appel àfiben utilisant le point de coupurefib(βA). Lorsqu’un appel àfibest filtré, l’action incrémentenensuite exécute l’appel àfib (par l’intermédiaire deproceed) et termine parskipqui ne fait rien.

La sémantique du tissage (Section 2.3, page 44) représente un aspect comme une fonction

Σψqui prend la configuration courante(C,Σ)en paramètre et retourne soit une nouvelle confi-guration(C

), soitnil quand le point de coupure ne filtre pas l’instruction courante. Nous définissons la sémantique de notre langage d’aspect de façon à générerΣψ à partir du code de l’aspect. La fonction résultante prend la configuration courante en paramètre et filtre la première instructioni. [[around p s]] = let (p1 ∧if(b1))∨. . .∨(pn∧if(bn)) =Transf(p)in λ(i:C, X ∪ΣP). case matchs(p1, i) =σ1 7→ (a1 :C, X ∪¯i: ΣP) · · · matchs(pn, i) = σn 7→ (an:C, X ∪¯i: ΣP) else 7→ nil

oùaii(if(bi) then s else proceed)

L’instruction¯iet le codea¯isont tagués (voir Section 2.3, page 44) pour empêcher un tissage in-fini. Afin de distinguer sa partie statique de sa partie dynamique, la fonctionTransf transforme tout point de coupurepen une disjonction de la forme(p1∧if(b1))∨. . .∨(pn∧if(bn))où les

– le point de coupurepest mis sous une forme normale disjonctivep

1∨. . .∨p n; – chaquep

jest alors converti sous la formep′′

j ∧ if(bj)tel quep′′

j soit un point de coupure statique. On le fait en utilisant l’associativité et la commutativité de l’opérateur ∧ et la règle suivante

if(b1) ∧ if(b2) ≡ if(b1∧b2)

sip

jest uniquement statique ou conditionnel, il peut toujours être converti avec les règles :

if(b) ≡ βS ∧ if(b) Sp ≡ Sp ∧ if(true)

– l’aspect maintenant de la forme

around((p′′1 ∧ if(b1))∨. . .∨(p′′n ∧ if(bn)))s

peut être transformé en plusieurs aspects de la forme around (pj ∧ if(bj)) s. Par exemple, l’aspect

around((p1∧if(b1))∨(p2 ∧ if(b2)))s

est converti en trois aspects

around(p1 ∧ ¬p2 ∧ if(b1))s

around(p2 ∧ ¬p1 ∧ if(b2))s

around(p1 ∧ p2 ∧ if(b1 ∨ b2))s

Ces aspects sont mutuellement exclusifs (c.-à-d.,au plus un est appliqué). Ils peuvent être vus comme un aspect de la forme

around((p1 ∧ ¬p2 ∧ if(b1))

∨(p2 ∧ ¬p1 ∧ if(b2))

∨(p1 ∧ p2 ∧ if(b1 ∨ b2)))s

où les points de coupure statiques sont mutuellement exclusifs. Cette transformation se généralise à n disjonctions. Si les preuves des premières transformations sont claires et standards, la preuve du passage d’un aspect à plusieurs aspects mutuellement exclusifs est faite à la Section 5.3.3, page 110.

La fonction Σψ teste donc si l’instruction courante i est filtrée par un des points de coupure statique pj. Si i n’est pas filtrée, la fonction retournenil. Sinon, i est remplacée par un code

a et placée au sommet de la pile proceed. Lorsqu’il est exécuté, a teste la partie dynamique

bj du point de coupure statique pj qui a filtré i. Si bj est satisfaite, l’action s est exécutée. Sinon, l’exécution continue avec l’instructioni (l’action n’est pas exécutée). Les variables de motifs dansbj etssont remplacées par leurs valeurs en utilisant la substitutionσretournée par

matchs qui est une surcharge de la fonction match (définie à la Section 2.5, page 51) sur les

anti-patterns.

Cette sémantique distingue l’évaluation de la partie statique du point de coupure de celle de la partie dynamique. Nous avons fait ce choix afin de modéliser les langages à la AspectJ où plusieurs aspects peuvent interagir (c.-à-d.,la partie dynamique d’un point de coupure peut dépendre de l’exécution de l’action précédente).

PROPRIÉTÉ22. ∀a∈Aspo.[[a]]∈ Ao

En effet, comme les commandes de Aspo modifient uniquement les variables déclarées par l’aspect, une réduction de toute commande de Aspo par →b modifie uniquement Σa ( c.-à-d.,l’aspect ne modifie pas l’état du programme de base). De plus comme tout aspect deAspo

possède unproceedsans paramètres et appelle uniquement ses méthodes, alors la sémantique deproceedci-dessus et→b garantissent que la séquence d’instructions de base dans la trace tissée est la même que la trace d’instructions du programme de base (c.-à-d.,l’aspect ne modi-fie pas le flot de contrôle du programme de base). Une preuve de cette propriété est présentée à l’Appendice B.3, page 128. Cette preuve est une induction sur la longueur de la trace de base.