• Aucun résultat trouvé

Exemple de débogage d’un programme multi-langages

la liste des variables capturées, au cas où la fonction soit une fonction interne. Même si le module Jython n’est pas compilé en mode débogage, l’objet PyCode est présent durant l’exécution. La construction de variables virtuelles est donc un mécanisme « sûr ».

L’affichage d’un objet est pris en charge par le support de débogage Jython si cet objet hérite de la classe PyScriptable. La valeur de l’objet est obtenue en appelant sa méthode JVM toString dans la JVM du débogué.

Enfin, le support de débogage permet de construire des objets virtuels à partir des objets qui héritent de PyScriptable, afin de masquer les champs synthétiques des structures Jython qui n’existent pas dans le fichier source. Pour retrouver les champs logiques d’une structure Jython, le débogueur appelle sa méthode dir, une méthode Python standard permettant de faire de l’introspection. En Python, l’introspection est une fonctionnalité qui peut être surchargée dans les classes utilisateurs. Utiliser la méthode dir permet de respecter les conventions d’introspection du programme utilisateur.

7.3 Exemple de débogage d’un programme multi-langages

Cette section illustre la manière dont les règles de remplacement peuvent être employées pour permettre de déboguer des programmes composés de plusieurs langages de haut niveau, là ou les débogueurs classiques ne sont plus d’aucune utilité.

1 function foo() { 2 Packages.multiscm.DYNAMIC_LOAD_INIT(); 3 var f=Packages.multiscm.hello; 4 var c=Packages.multipy.code(); 5 c.gee(f); 6 } 7 8 foo();

(a) fichier multijs.js (point d’entrée)

1 (module multiscm 2 (export hello)) 3

4 (define hello 5 (lambda ()

6 (print "Hello Scheme!"))) 7

8

(b) fichier multiscm.scm

1 from java.lang import Object; 2 class code(Object):

3 def gee(self, fun):

4 "@sig public java.lang.Object gee(bigloo.procedure fun)" 5 return fun.funcall0()

(c) fichier multipy.py

Fig. 7.5: Programme composé de trois fichiers source écrits dans différents langages :7.5(a)

ECMAScript ;7.5(b) Bigloo ;7.5(c)Jython.

L’exemple de la figure 7.5 présente le code source d’une programme utilisant trois lan-

gages sources différents : Rhino, Jython et Bigloo.

Le point d’entrée du programme à déboguer est l’expression située à la ligne 8 de la

figure 7.5(a) effectuant un appel à la fonction Rhino foo. Cette fonction initialise tout

d’abord la bibliothèque d’exécution Bigloo. Ensuite, elle crée une variable f pour référencer la fermeture Scheme contenue dans la variable hello du module multiscm. Enfin, elle crée une instance de la classe Python code et appelle sa méthode gee en lui passant en paramètre

CHAPITRE 7. EXPÉRIMENTATIONS SUR D’AUTRES LANGAGES

la fermeture Scheme. Supposons qu’un point d’arrêt ait été posé dans le fichier multiscm.-

scm à la ligne 6. Le contenu de la pile au moment où l’exécution atteint cette ligne est

présenté dans la figure 7.6. Manifestement, la pile contient beaucoup trop de fonctions

synthétiques et de fonctions de bibliothèque pour que le programme puisse être débogué correctement. L’utilisation de règle de remplacement permet de remédier à ce problème.

Le chapitre6 a déjà décrit les règles nécessaires au masquage des motifs de code produits

par le compilateur Bigloo. Il est maintenant nécessaire de concevoir un ensemble de règles spécifiques aux langages Rhino et Jython afin d’obtenir une vue virtuelle correcte de la pile du programme. Ces règles sont présentés dans les sections suivantes.

#0 (<anonymous:1003:multiscm.scm:4> ::proc) in file multiscm.scm:6 #1 (funcall0) in file multiscm.scm

#2 invoke0(reflect.Method, Object, Object[]) in file NativeMethodAccessorImpl.java #3 invoke(Object, Object[]) in file sun/reflect/NativeMethodAccessorImpl.java:39 #4 invoke(Object, Object[]) in file sun/reflect/DelegatingMethodAccessorImpl.java:25 #5 invoke(Object, Object[]) in file java/lang/reflect/Method.java:585

#6 __call__(PyObject, PyObject[], String[]) in file PyReflectedFunction.java:160 #7 __call__(PyObject[], String[]) in file org/python/core/PyMethod.java:96 #8 __call__() in file org/python/core/PyObject.java:258

#9 invoke(String) in file org/python/core/PyInstance.java:244 #10 gee$1(PyFrame) in file multipy.java:45

#11 call_function(int, PyFrame) in file multipy.java:33

#12 call(PyFrame, PyObject) in file org/python/core/PyTableCode.java:208

#13 call(PyObject[], String[], PyObject, PyObject[], PyObject) in file PyTableCode.java: #14 call(PyObject, PyObject[], String[], PyObject, PyObject[], PyObject) in file PyTable. #15 __call__(PyObject, PyObject[], String[]) in file org/python/core/PyFunction.java:190 #16 __call__(PyObject[], String[]) in file org/python/core/PyMethod.java:96

#17 __call__(PyObject[]) in file org/python/core/PyObject.java:248 #18 _jcallexc(Object[]) in file org/python/core/PyObject.java:1958 #19 _jcall(Object[]) in file org/python/core/PyObject.java:1990 #20 gee(bigloo.proc) in file multipy.java:69

#21 invoke0(reflect.Method, Object, Object[]) in file sun/reflect/NativeMethodAccessor... #22 invoke(Object, Object[]) in file sun/reflect/NativeMethodAccessorImpl.java:39

#23 invoke(Object, Object[]) in file sun/reflect/DelegatingMethodAccessorImpl.java:25 #24 invoke(Object, Object[]) in file java/lang/reflect/Method.java:585

#25 invoke(Object, Object[]) in file org/mozilla/javascript/MemberBox.java:174 #26 call(Context, Scriptable, Scriptable, Object[]) in file NativeJavaMethod.java:197 #27 call1(Function, Scriptable, Object, Context, Scriptable) in file OptRuntime.java:63 #28 _c1(multijs, Context, Scriptable, Scriptable, Object[]) in class multijs:5

#29 call(Context, Scriptable, Scriptable, Object[]) in class multijs (no line info...) #30 callName0(String, Context, Scriptable) in file OptRuntime.java:105

#31 _c0(multijs, Context, Scriptable, Scriptable, Object[]) in class multijs:8

#32 call(Context, Scriptable, Scriptable, Object[]) in class multijs (no line info...) #33 doTopCall(Callable, Context, Scriptable, Scriptable, Object[]) in file ContextFactory. #34 doTopCall(Callable, Context, Scriptable, Scriptable, Object[]) in file ScriptRuntime. #35 call(Context, Scriptable, Scriptable, Object[]) in class multijs (no line info...) #36 exec(Context, Scriptable) in class multijs (no line info...)

#37 run(Context) in file org/mozilla/javascript/optimizer/OptRuntime.java:242

#38 call(ContextFactory, ContextAction) in file org/mozilla/javascript/Context.java:540 #39 call(ContextAction) in file org/mozilla/javascript/Context.java:457

#40 main(Script, String[]) in file org/mozilla/javascript/optimizer/OptRuntime.java:230 #41 main(String[]) in class multijs (no line info...)

Fig. 7.6: Contenu de la pile d’exécution avant filtrage

7.3. EXEMPLE DE DÉBOGAGE D’UN PROGRAMME MULTI-LANGAGES 7.3.1 Blocs d’activation virtuels pour Rhino

(100

(("doTopCall" any any "org.mozilla.javascript.ContextFactory") ("doTopCall" any any "org.mozilla.javascript.ScriptRuntime")

("call" ("Context" "Scriptable" "Scriptable" "Object[]") any (? any)) ("exec" ("Context" "Scriptable") any (\ 1))

("run" any any "org.mozilla.javascript.optimizer.OptRuntime$1") (* ("call" any any "org.mozilla.javascript.optimizer.Context")) ("main" any any "org.mozilla.javascript.optimizer.OptRuntime") ("main" ("java.lang.String[]") any (\ 1)))

mask) (100

((["^_c[0-9]+$"] ((? any) . (? any)) "java.lang.Object" (\ 1)) ("call" (\ 2) "java.lang.Object" (\ 1))

(* (["^call.*"] any any "org.mozilla.javascript.optimizer.OptRuntime"))) sf-rhino-function)

(100

(("invoke0" any any (? sf-rhino-reflect)) (* ("invoke" any any (\ 1)))

("invoke" any any "java.lang.reflect.Method")

("invoke" any any "org.mozilla.javascript.MemberBox") ("call" any any "org.mozilla.javascript.NativeJavaMethod")

(["^call.*"] any any "org.mozilla.javascript.optimizer.OptRuntime")) mask)

Fig. 7.7: Ensemble de règles de remplacement pour Rhino

Dans le contenu de la pile présentée dans la figure 7.6, les fonctions Rhino sont situées

entre les blocs d’activation 41 et 21. Les blocs d’activation provenant de la classe multijs illustrent le fait que le fichier ECMAScript utilisateur a directement été compilé en code- octet JVM. Les autres blocs d’activation montrent que la bibliothèque d’exécution de Rhino est écrite en Java. Le masquage de ces blocs est pris en charge par les règles de remplacement

présentées dans la figure 7.7.

Un premier motif de code synthétique est formé par les blocs 41 à 33. Il représente le démarrage d’un programme Rhino. Le point d’entrée JVM main est en charge de l’ini- tialisation de la bibliothèque d’exécution de Rhino (bloc 40). Ensuite, cette bibliothèque appelle la fonction principale du programme utilisateur (bloc 36), dont le but est d’évaluer les expressions globales du programme (blocs 34 et 33). La première règle de remplacement

de la figure7.7 est chargée de faire disparaître ces blocs d’activation dans la vue virtuelle.

Plus haut dans la pile, les blocs 32 à 31 et les blocs 30 à 28 représentent le motif responsable de l’implantation de l’appel de fonction d’ordre supérieur, tel qu’il a été décrit

dans la section7.1.1. La seconde règle de remplacement de la figure 7.7permet de masquer

les fonctions intermédiaires de ce motif et la fonction de remplacement sf-rhino-function est en charge de reconstruire les noms de fonctions utilisateur à partir des _cn.

Le dernier motif de code Rhino s’étend du bloc 27 au bloc 21 et représente les appels de fonctions étrangères à la plateforme d’exécution Rhino. Ce type d’appel n’est pas résolu au moment de la compilation, il est implanté à l’aide de l’API de réflexivité de Java.

CHAPITRE 7. EXPÉRIMENTATIONS SUR D’AUTRES LANGAGES

d’activation. Dans le bloc 21, la fonction de remplacement sf-rhino-reflection effectue une détection ad-hoc : elle identifie l’implanteur de l’API de réflexivité (par exemple Sun, IBM, GNU. . . ) et met à jour la mémoire de recherche pour spécifier le nom du package JVM d’où doit provenir la prochaine fonction dans la pile. Cette « gymnastique » est nécessaire car la pile est explorée en partant du sommet.

7.3.2 Blocs d’activation virtuels pour Jython (100

((["^(.*)\\$[0-9]+$"] any any (? any)) ("call_function" any any (\ 2))

(* ("call" any any ["^org.python.core.*"])) (* ("__call__" any any ["^org.python.core.*"])) ("_jcallexc" any any "org.python.core.PyObject") ("_jcall" any any "org.python.core.PyObject") (["\\1"] any any any))

sf-jython-signature-function) (100

(("invoke0" any any (? sf-python-reflect)) (* ("invoke" any any (\ 1)))

("invoke" any any "java.lang.reflect.Method") (* ("__call__" any any ["^org.python.core.*"]))

("invoke" ("java.lang.String") any "org.python.core.PyInstance")) mask)

Fig. 7.8: Ensemble de règles de remplacement pour Jython

Les blocs d’activation Jython sont situés dans la pile entre le bloc 20 et le bloc 2. Le contenu de la pile indique que toutes les fonctions représentées par ces blocs d’activation proviennent de fichiers Java, ce qui prouve que le code source Jython est d’abord traduit en un code Java avant d’être compilé. Cette séquence de blocs contient deux motifs de code synthétique.

Le premier motif de code Jython s’étend du bloc 20 au bloc 10. Le bloc 20 correspond à la fonction gee telle qu’elle est exportée dans le code source multipy.py. Dans les blocs d’activation 19 à 11, la plateforme d’exécution Jython enrobe les arguments étrangers pour qu’ils puissent être utilisés par du code Jython. Enfin, le bloc 10 représente la fonction produite contenant le code réel de la fonction gee. Il est à noter qu’une fois l’enrobage effectué, le motif effectue un appel de fonction classique (entre les blocs 15 et 10). La

première règle de remplacement de la figure 7.8 transforme l’ensemble de ces blocs. Le

premier filtre de bloc conserve en mémoire le nom de la fonction du bloc 10 jusqu’au caractère $. Le second filtre de bloc vérifie que le fonction du bloc suivant provient de la même classe JVM que la fonction du premier bloc du motif. Les quatre filtres de blocs suivants détectent les fonctions intermédiaires provenant de la bibliothèque Jython. Le dernier filtre de bloc vérifier que le nom de la fonction du dernier bloc du motif correspond au nom conservé en mémoire. La fonction sf-jython-signature-function remplace toutes ces fonctions par un bloc d’activation virtuel qui correspond à la fonction gee dans le code source.

Le dernier motif de code Jython correspond à l’implantation de l’appel des fonctions étrangères depuis la plateforme d’exécution Jython. Comme dans la plateforme Rhino, ce

7.4. EXPÉRIENCE ACQUISE AVEC LES RÈGLES DE REMPLACEMENT