La présentation est en train de télécharger. S'il vous plaît, attendez

La présentation est en train de télécharger. S'il vous plaît, attendez

Génération de code Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure d’Informatique (ESI)

Présentations similaires


Présentation au sujet: "Génération de code Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure d’Informatique (ESI)"— Transcription de la présentation:

1 Génération de code Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure d’Informatique (ESI) http://zegour.esi.dz/ email: d_zegour@esi.dzd_zegour@esi.dz

2 Génération de code Généralités La machine virtuelle de.NET:CLR(Common Language Runtime) Éléments Expressions Affectations Saut et étiquette Structures de contrôle Méthodes

3 Rôles de la génération de code Génération des instructions machine Sélectionner les bonnes instructions Sélectionner les bons modes d’adressage Traduction des structures de contrôles (if, while,...) en branchement (sauts ) Allocation mémoire pour les variables locales Faire quelques optimisations Obtenir un fichier objet

4 Stratégie commune 1.Étudier la machine cible registres, formats des données, modes d’adressage, instructions, format des instructions,... 2.Concevoir les structures de données à l’exécution - pile d’exécution pour la gestion des procédures - zone de données pour les variables globales, mémoire pour l’allocation dynamique - zone pour les constantes, … 3.Implémenter le codage des instructions 4.Implémenter l’allocation des registres si nécessaire 5.Implémenter les routines de génération de code (dans l’ordre suivant) -charger les valeurs et les adresses dans les registres ( ou dans une pile) -traiter les formes x.y, a[i],... -traduire les expressions -gérer les sauts et les étiquettes -traduire les instructions -traduire les méthodes(procédures, fonctions) et le passage des paramètres

5 Langage Source Grammaires d’attributs Table des symboles Machine pivot: CLR Organisation mémoire Tables de compilation Langage pivot:CIL Langage d’assemblage Langage machine Forme interne Lexique Syntaxe Sémantique/ Génération de code Compilateur du langage Z Compilateur d’un langage objet.Net :Z# Exécution (CLR) Vérification avec un désassembleur IL (ildasm.exe ) Stratégie

6 Génération de code Généralités La machine virtuelle de.NET:CLR(Common Language Runtime) Éléments Expressions Affectations Saut et étiquette Structures de contrôle Méthodes

7 Architecture de la CLR C’est quoi une machine virtuelle (VM)? Un CPU implémenté sous forme d’un programme (software) Commandes seront interprétées / JIT-compiled Autres exemples: Java-VM, Smalltalk-VM, Pascal P-Code Le CLR est une machine à pile pas de registres à la place,il y a une pile d’expressions (dans laquelle les valeurs sont chargées) esp estack Taille maximale rangée dans les méta-données de chaque méthode esp... pointeur de la pile d’expressions La CLR exécute du bytecode JIT compilé Chaque méthode est compilée avant la première exécution (= just-in-time) Les opérandes sont adressées symboliquement en IL (information rangée dans les méta-données)

8 Comment fonctionne une machine à pile? Exemple instruction i = i + j * 5; Suppose les valeurs suivantes de i et j Simulation instructionspile ldloc.0 Charger la variable se trouvant à l’adresse 0 (c.a.d. i) 3 add Ajouter les 2 éléments en sommet de pile 23 lldloc.1 Charger la variable se trouvant à l’adresse 1 (c.a.d. j) 34 ldc.i4.5 Charger la constante 5 345 mul Multiplier les 2 éléments en sommet de pile 320 stloc.0 Ranger l’élément en sommet de pile à l’adresse 0 A la fin de chaque instruction la pile d’expression est vide! 3 4j i0 1 locals

9 Zones de données de la CLR Variables globales statics Représentent les champs statiques de la classe ‘program’ dans la CLR Les variables globales sont accessibles dans tout le programme Les variables globales sont adressées par des unités ‘medadata’ Ex. ldsfld T fld charge la valeur du champ référencé par T fld sur la pile estack Type de l’unité (1 Octet) index dans la table metadata (3 Octets) Les unités ‘Metadata’ sont des valeurs à 4 octets qui référencent des lignes dans les tables ‘metadata’.

10 Zones de données de la CLR État d‘une méthode La CLR gère des zones séparées pour Les arguments (args) Les variables locales (locals) La pile d‘expressions (estack) Chaque appel de méthode a son propre état (MS) Les états de méthodes sont gérés dans une pile Chaque paramètre et chaque variable locale occupent un espace qui dépend du type. Les adresses sont des numéros consécutifs reflétant l’ordre de déclarations Ex.ldarg.0 charge la valeur du premier argument de la méthode sur la pile estack ldloc.2 charge la valeur de la troisième variable locale sur la pile estack args locals estack 0 1 2 0 1 2 3 État de la méthode MS P P Q MS Q MS P R MS Q MS R P appelle Q; Q appelle R

11 Zones de données de la CLR Le tas (Heap) Contient les objets ‘classe’ et ‘tableau’ 0 heap k free Les nouveaux objets sont alloués à la position free (et free est incrémenté); Ceci est fait par les instructions CIL newobj et newarr Les objets sont libérés par le ‘garbage collector’

12 Zones de données de la CLR Les objets ‘class’ class X { int a, b; char c; } X obj = new X; a b c heap obj adressé par le champ relatif à obj Les objets ‘array’ int[] a = new int[4]; a[0] a[1] a[2] heap a adressé par la valeur d’indice relative à a a[3] Seuls les vecteurs peuvent être maniés par les directives CIL spéciales newarr, ldlen, ldelem, stelem

13 Zones de données de la CLR Le tas Heap 0 k free args locals estack 0 1 2 0 1 2 3 MS S MS P MS Q MS R Pile d’exécution Variable globales Statics Les différentes zones de données à un moment donné : Méthode P appelle Q; Q appelle R; R appelle S. Méthode S en cours d’exécution

14 Code IL à générer Un programme.NET compilé est un assemblage (Assembly) Un assemblage est composé de modules. En général, un seul module (=programme) Le programme est un ensemble de types (classes) Chaque type est un ensemble de méthodes Une méthode contient du code machine pour la CLR (= Common Intermediate Language (CIL)) et des méta-données sous forme de tables. Nous utiliserons les classes du domaine ‘System.Reflection.Emit’ de la BCL (.NET Base Class Library) afin de - générer le IL - produire les méta-données dans le format adéquat. Structure du programme à obtenir Comment l’obtenir ?

15 Code IL à générer La table TypeDef Contient les informations sur tous les types définis dans le module. (Utilisation de la classe System.Reflection.Emit.TypeBuilder pour produire cette information dans le format correct) La table Field Contient les informations sur tous les champs définis dans le module. (Utilisation de la classe System.Reflection.Emit.FieldBuilder pour produire cette information dans le format correct) La table Method Contient les informations sur toutes les méthodes définies dans le module. (Utilisation de la classe System.Reflection.Emit.MethodBuilder pour produire cette information dans le format correct) Tables utilisées dans notre contexte

16 Code IL à générer public class Code { const FieldAttributes GLOBALATTR = FieldAttributes.Assembly | FieldAttributes.Static; const FieldAttributes FIELDATTR = FieldAttributes.Assembly; const MethodAttributes METHATTR = MethodAttributes.Assembly | MethodAttributes.Static; const TypeAttributes INNERATTR = TypeAttributes.Class | TypeAttributes.NotPublic; const TypeAttributes PROGATTR = TypeAttributes.Class | TypeAttributes.Public; //----- System.Reflection.Emit objects for metadata management static AssemblyBuilder assembly; // metadata builder for the program assembly static ModuleBuilder module; // metadata builder for the program module static TypeBuilder program; // metadata builder for the main class static TypeBuilder inner; // metadata builder for the currently compiled inner class internal static ILGenerator il; // IL stream of currently compiled method //----- metadata generation internal static void CreateMetadata (Symbol sym) {... } // ---------- instruction generation /* Load the operand x onto the expression stack. */ internal static void Load (Item x) {... } /* Generate an assignment x = y. */ internal static void Assign (Item x, Item y) {... } … }

17 Code IL à générer Chaque méthode est composée d’un flot d’instructions CIL et de méta-données comme.entrypoint,.locals,.maxstack, attributs d’accès,... La classe System.Reflection.Emit.ILGenerator gère le flot CIL. On peut accéder au flot IL de la méthode en cours de compilation via le champ statique internal static ILGenerator il; de la classe code class ILGenerator { /* overloaded (see next slide) */ virtual void Emit (OpCode op,...); /* for method calls */ void EmitCall ( OpCode op, MethodInfo meth, Type[] varArgs);... } Les instructions sont définies dans la class OpCodes. static readonly OpCode LDARG0= OpCodes.Ldarg_0,... LDARG= OpCodes.Ldarg_S,... LDC0= OpCodes.Ldc_I4_0,... ADD= OpCodes.Add,... BEQ= OpCodes.Beq,...... ; Ex.: pour générer ldloc.2 Code.il.Emit(LDLOC2);

18 Les méthodes Emit de ILGenerator class ILGenerator {// use for the following IL instructions: void Emit (OpCode);// ldarg.n, ldloc.n, stloc.n, ldnull, ldc.i4.n, ld.i4.m1 // add, sub, mul, div, rem, neg, // ldlen, ldelem..., stelem..., dup, pop, ret, throw void Emit (OpCode, byte);// ldarg.s, starg.s, ldloc.s, stloc.s void Emit (OpCode, int);// ldc.i4 void Emit (OpCode, FieldInfo);// ldsfld, stsfld, ldfld, stfld void Emit (OpCode, LocalBuilder);// ldloc.s, stloc.s void Emit (OpCode, ConstructorInfo);// newobj void Emit (OpCode, Type);// newarr void Emit (OpCode, Label);// br, beq, bge, bgt, ble, blt, bne.un /* for method calls */ void EmitCall (OpCode, MethodInfo, Type[]);... }

19 Meta-données à générer : programme internal static void CreateMetadata (Symbol sym) { switch (sym.kind) { case Symbol.Kinds.Prog: AssemblyName aName = new AssemblyName(); aName.Name = sym.name; assembly = AppDomain.CurrentDomain.DefineDynamicAssembly( aName, AssemblyBuilderAccess.Save); module = assembly.DefineDynamicModule(sym.name + "Module", sym.name + ".exe"); program = module.DefineType(sym.name, TypeAttributes.Class | TypeAttributes.Public); inner = null; break;... } La méthode CreateMetadata de la classe Code crée des objets méta-données à partir des nœuds de type Symbol (invoquée pour chaque symbole rajouté à la table des symboles)  La classe Code possède des champs pour gérer d’importants éléments de méta-données: static AssemblyBuilder assembly;// the program assembly static ModuleBuilder module;// the program module static TypeBuilder program;// the main class static TypeBuilder inner;// the currently compiled inner class  Décrivent les propriétés des composants d’un assemblage (types, champs, méthodes,...).

20 Champ additionnel dans les nœuds de type Struct (classe des types) internal Type sysType; pour créer les types CLR correspondants pour un nœud de type Symbol (classe des symboles) Meta-données à générer : variables locales La méthode DeclareLocal de ILGenerator construit les méta données pour les variables locales. internal static void CreateMetadata (Symbol sym) { switch (sym.kind) { case Symbol.Kinds.Local: il.DeclareLocal(sym.type.sysType); break;... }

21 Champ additionnel pour les nœuds de type Symbol (classe des symboles) internal ConstructorBuilder ctor; pour générer des invocations au constructeur quand on crée de nouveaux objets (newobj). zusätzliches Feld für Strukturknoten internal Type sysType; um den entsprechenden CLR-Typen für das Symbol anlegen zu können. Meta-données à générer : types La méthode DefineType de ModuleBuilder construit les méta données pour les types. internal static void CreateMetadata (Symbol sym) { switch (sym.kind) { case Symbol.Kinds.Type: inner = module.DefineType(sym.name, TypeAttributes.Class | TypeAttributes.NotPublic); sym.type.sysType = inner; // define default contructor (simply calls base constructor) sym.ctor = inner.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[0]); il = sym.ctor.GetILGenerator(); il.Emit(LDARG0); il.Emit(CALL, typeof(object).GetConstructor(new Type[0])); il.Emit(RET); break;... } no-arg constructor of System.Object

22 Meta-données à générer : variables globales & champs d’objets La CLR gère les deux comme des champs (champ statique de la class ‘program’; champ de la classe courante). La méthode DefineField de TypeBuilder génère les méta-données pour les champs. Champs additionnels pour les nœuds de type Symbol internal FieldBuilder fld; pour générer les accès aux champs (ldsfld, stsfld, ldfld, stfld). internal static void CreateMetadata (Symbol sym) { switch (sym.kind) { case Symbol.Kinds.Global: if (sym.type != Tab.noType) sym.fld = program.DefineField(sym.name, sym.type.sysType,FieldAttributes.Assembly | FieldAttributes.Static); break; case Symbol.Kinds.Field: if (sym.type != Tab.noType) sym.fld = inner.DefineField(sym.name, sym.type.sysType, FieldAttributes.Assembly); break;... }

23 Champ additionnel pour les nœuds de type Symbol internal MethodBuilder meth; pour générer des appels de méthodes (call). Meta-données à générer : méthodes & arguments La méthode DefineMethod de TypeBuilder génère les meta-données pour les méthodes et leurs arguments. internal static void CreateMetadata (Symbol sym) { switch (sym.kind) { case Symbol.Kinds.Meth: Type[] args = new Type[sym.nArgs]; Symbol arg; for (arg = sym.locals; arg != null && arg.kind == Symbol.Kinds.Arg; arg = arg.next) args[arg.adr] = arg.type.sysType; sym.meth = program.DefineMethod(sym.name,MethodAttributes.Static | MethodAttributes.Family, sym.type.sysType, args); il = sym.meth.GetILGenerator(); if (sym.name == "Main") assembly.SetEntryPoint(sym.meth); break;... }

24 Ensemble des instructions de la CLR Langage Intermédiaire (CIL) (un sous ensemble) Très compacte: instructions sur un octet (la plupart) La plupart non typée; indications de type fait référence au type du résultat Non typée ldloc.0 starg.1 add ldc.i4.3 ldelem.i2 stelem.ref Typée Format des instructions Très simple comparé a Intel, PowerPC ou SPARC Code= { Instruction }. Instruction= opcode [ operand ]. opcode...1 or 2 octets operand...de type primitif ou unité metadata Exemples 0 opérande add a 2 opérandes implicites sur la pile 1 opérande ldc.i4.s 9

25 Ensemble des instructions de la CLR Modes d’adressage Comment les opérandes sont accédés? Immédiat ldc.i4 123 pour les constantes Argument ldarg.s 5 pour les arguments de méthode Local ldlocs.s 12 pour les variable locales Statique ldsfld fld pour les champs statiques (fld = unité metadata ) Pile add pour les valeurs chargées dans la pile estack Relatif ldfld fld pour les objet champs (référence objet est dans estack) Indexé ldelem.i4 pour les éléments de tableau (référence tableau et indice sont dans estack) mode d’adressageexemple Relatif base address esp estack Indexé base address esp estack index

26 Ensemble des instructions de la CLR Chargement et rangement d’arguments de méthodes ldarg.n......, val charger (n = 0..3) push(args[n]); ldarg.sb......, val charger push(args[b]); starg.sb..., val... Ranger args[b] = pop(); Types d’opérandes b... Octet non signé i... Entier signé T... Unité metadata stloc.n..., val... Ranger (n = 0..3) locals[n] = pop(); stloc.sb..., val... Ranger locals[b] = pop(); ldloc.sb......, val charger push(locals[b]); ldloc.n......, val charger (n = 0..3) push(locals[n]); Chargement et rangement de variables locales

27 Ensemble des instructions de la CLR Chargement et rangement de variables globales stsfldT fld..., val... Ranger une variable statique statics[T fld ] = pop(); ldsfldT fld......, val Charger une variable statique push(statics[T fld ]); Chargement et rangement d’objets champ stfldT fld..., obj, val... Ranger un objet champ val = pop(); obj = pop(); heap[obj+T fld ] = val; ldfldT fld..., obj..., val Charger un objet champ obj = pop(); push(heap[obj+T fld ]); T fld estack adr estack Heap

28 Ensemble des instructions de la CLR Chargement de constantes ldc.i4.n......, n Charge une constante (n = 0..8) push(n); ldc.i4i......, i Charge une constante push(i); ldc.i4.m1......, -1 Charge la constante -1 push(-1); ldnull......, null Charge la constante null push(null);

29 Exemples: chargement et rangement ax = ay; x 0 y 1 p 2 x y ldarg.11ay starg.s 02- CodeOctetsestack gx = gy;ldsfld T fld_gy 5gy stsfld T fld_gx 5- gx gy statics locals p.x = p.y;ldloc.21p ldloc.21p p ldfld T fld_y 5p p.y stfld T fld_x 5- ax ay args 0 1 x = y;ldloc.11y stloc.01-

30 Ensemble des instructions de la CLR Arithmétiques sub..., val1, val2..., val1-val2 Soustraire push(-pop() + pop()); add..., val1, val2..., val1+val2 Ajouter push(pop() + pop()); div..., val1, val2..., val1/val2 Diviser x = pop(); push(pop() / x); mul..., val1, val2..., val1*val2 Multiplier push(pop() * pop()); neg..., val..., -val Négatif push(-pop()); rem..., val1, val2..., val1%val2 Reste x = pop(); push(pop() % x);

31 Exemples: arithmétiques x + y * 3ldloc.01x ldloc.11x y ldc.i4.31x y 3 mul1x y*3 add1x+y*3 CodeOctetsPile x++;ldloc.01x ldc.i4.11x 1 add1x+1 stloc.01- x--; ldloc.01x ldc.i4.m11x -1 add1x-1 stloc.01- p.x++ldloc.21p dup1p p ldfld T px 5p p.x ldc.i4.11p p.x 1 add1p p.x+1 stfld T px 5- x 0 y 1 p 2 x y locals a 3 int[] t1 4 t2 5

32 Ensemble des instructions de la CLR Création d‘objets newarrT eType..., n..., arr Nouveau tableau crée un tableau avec l’espace pour n éléments de type spécifié par l’unité type newobjT ctor... [ arg0,..., argN ]..., obj Nouvel objet crée un nouveau objet de type spécifié par l’unité ’constructeur’ puis exécute le constructeur (les arguments sont dans la pile)

33 Exemples: création d’objets Person p = new Person; p0 a1 newobj T P() 5p stloc.01- CodeOctetsPile int[] a = new int[5];ldc.i4.515 newarr T int 5a stloc.11- locals

34 Ensemble des instructions de la CLR Accès aux tableaux stelem.i2 stelem.i4 stelem.ref...,adr, i, val... Ranger un élément de tableau val=pop(); i=pop(); adr=pop()/4+1; heap[adr+i] = val; type de l’élément à ranger: char, int, référence objet ldelem.u2 ldelem.i4 ldelem.ref..., adr, i..., val Charger un élément de tableau i = pop(); adr = pop(); push(heap[adr+i]); type du résultat sur la pile estack: char, int, référence objet i estack adr estack a i ldlen..., adr..., len Obtenir la longueur du tableau

35 Exemple1: accès aux tableaux CodeOctetsPile locals a[2]++ldloc.01a ldc.i4.21a 2 stloc.s 22a stloc.s 12- ldloc.s 12a ldloc.s 22a 2 ldloc.s 12a 2 a ldloc.s 22a 2 a 2 ldelem.i41a 2 a[2] ldc.i4.11a 2 a[2] 1 add1a 2 a[2]+1 stelem.i41- a 0 int[] t1 1 t2 2

36 Exemple2: accès aux tableaux a[i] = b[i+1]; a 0 b 1 ldloc.01a ldloc.21a i ldloc.11a i b ldloc.21a i b i ldc.i4.11a i b i 1 add1a i b i+1 ldelem.i41a i b[i+1] stelem.i41- CodeOctetsPile locals i2 int[]

37 Ensemble des instructions de la CLR Manipulation de la pile pop..., val... Enlever l’élément au sommet de pile dummy = pop(); dup..., val..., val, val Duplique l’élément au sommet de pile x = pop(); push(x); push(x); Branchement bri... Branchement inconditionnel pc = pc + i pc désigne l’instruction courante; i (distance du saut) relative par rapport à la prochaine instruction b i..., x, y... Branchement conditionnel ( = eq | ge | gt | le | lt | ne.un) y = pop(); x = pop(); if (x cond y) pc = pc + i;

38 Exemple: branchements if (x > y) {... }... x 0 y 1 ldloc.01x ldloc.11x y ble...5- CodeOctetsPile locals

39 Ensemble des instructions de la CLR Appel de méthode callT meth... [ arg0,... argN ]... [ retVal ] Appel de méthode dépiler les arguments de la pile de l’appelant estack et les mettre dans args de l’appelée; Avant de faire le retour, dépiler la valeur retournée de la pile estack de l’appelé et l’ empiler dans la pile estack de l’appelant ret... Retour de la méthode Divers throw..., exc... Throw exception

40 Exemple void Main () int a, b, max, sum; { if (a > b) max = a; else max = b; while (a > 0) { sum = sum + a * b; a--; } static void Main () 0:ldloc.0 1:ldloc.1 2:ble 7 (=14) 7:ldloc.0 8:stloc.2 9:br 2 (=16) 14:ldloc.1 15:stloc.2 16:ldloc.0 17:ldc.i4.0 18:ble 15 (=38) 23:ldloc.3 24:ldloc.0 25:ldloc.1 26:mul 27:add 28:stloc.3 29:ldloc.0 30:ldc.i4.1 31:sub 32:stloc.0 33:br -22 (=16) 38:return adresses a...0 b...1 max...2 sum...3

41 Génération de code Généralités La machine virtuelle de.NET:CLR(Common Language Runtime) Éléments Expressions Affectations Saut et étiquette Structures de contrôle Méthodes

42 Les opérandes durant la génération de code Exemple Nous voulons ajouter 2 valeurs + ?? Modèle de code désiré load opérande 1 load opérande 2 add constante ldc.i4 x argument de méthode ldarg.s a variable locale ldloc.s a variable globale ldsfld T fld champ d’un objetldf ld T fld élément d’un tableau ldelem Valeur chargée sur la pile --- Selon le type de l’opérande nous devons générer différentes instructions de chargement Type d’opérandeinstruction à générer Nous avons besoin d’un descripteur, qui nous donne toutes les informations nécessaires au sujet des opérandes.

43 Les éléments Les descripteurs renferment les types et les adresses des opérandes. Après chargement de sa valeur avec ldloc.2, elle est dans la pile estack x esp estack kind adr... Stack ---... décrite par l’élément suivant Exemple variable locale x dans la zone ‘locals’ d’un état de méthode kind adr... Local 2... décrite par l’élément suivant x locals 0 1 2 3

44 Exemple: traitement des éléments La plupart des méthodes d’analyse syntaxique retourne des éléments (comme résultat de leur travail de traduction) Exemple: traduction d’une affectation x = y + z * 3;  Local 2  Con 3  Local 1  Local 0  Local 2   Stack  ldloc.2  Con 3   Stack  ldc.i4.3  Stack  mul   Stack  Local 1   Stack  ldloc.1   Stack  add  Stack  Local 0   stloc.0 Factor z3 * Term y + Expr Designator x = Statement x y z locals

45 Les sortes d’éléments Type opérandeType d’élément info sur les opérandes ConstanteConstValeur de la constante variable globaleStaticNœud de champ T fld statics valeur en pileStack--- estack esp Champ d’objetFieldNœud de champ estack esp adr T fld Élément de tableau Elem--- estack esp adr idx méthodeMethNœud de méthode argumentArgadresse adr args variable localeLocaladresse adr locals

46 La class Item (des éléments) class Item { enum Kinds { Const, Arg, Local, Static, Stack, Field, Elem, Meth } Kindskind; Structtype;// type of the operands intval;// Const: constant value intadr;// Arg, Local: address Symbolsym;// Field, Meth: Symbol node from symbol table } Constructeur pour la création des éléments public Item (Symbol sym) { type = sym.type; val = sym.val; adr = sym.adr; this.sym = sym; switch (sym.kind) { case Symbol.Kinds.Const: kind = Kinds.Const; break; case Symbol.Kinds.Arg: kind = Kinds.Arg; break; case Symbol.Kinds.Local: kind = Kinds.Local; break; case Symbol.Kinds.Global: kind = Kinds.Static; break; case Symbol.Kinds.Field: kind = Kinds.Field; break; case Symbol.Kinds.Meth: kind = Kinds.Meth; break; default: Parser.Error("cannot create Item"); } Crée un élément à partir d’un nœud de la table des symboles public Item (int val) { kind = Kinds.Const; type = Tab.intType; this.val = val; } Crée un élément à partir d’une constante

47 Chargement des valeurs (1) En entrée:une valeur décrite par un élément (Const, Arg, Local, Static,...) En sortie:charger la valeur dans la pile d’expressions Analyse des cas Selon le type de l’élément Nous générons différentes instructions de chargement public static void Load (Item x) { // method of class Code switch (x.kind) { case Item.Kinds.Const: if (x.type == Tab.nullType) il.Emit(LDNULL); else LoadConst(x.val); break; case Item.Kinds.Arg: switch (x.adr) { case 0: il.Emit(LDARG0); break;... default: il.Emit(LDARG, x.adr); break; } break; case Item.Kinds.Local: switch (x.adr) { case 0: il.Emit(LDLOC0); break;... default: il.Emit(LDLOC, x.adr); break; } break;...

48 Chargement des valeurs (2) public static void Load (Item x) { // cont.... case Item.Static: if (x.sym.fld != null) il.Emit(LDSFLD, x.sym.fld); break; case Item.Stack: break; // nothing to do (already loaded) case Item.Field: // assert: object base address is on stack if (x.sym.fld != null) il.Emit(LDFLD, x.sym.fld); break; case Item.Elem: // assert: array base address and index are on stack if (x.type == Tab.charType) il.Emit(LDELEMCHR); else if (x.type == Tab.intType) il.Emit(LDELEMINT); else if (x.type.kind == Struct.Kinds.Class) il.Emit(LDELEMREF); else Parser.Error("invalid array element type"); break; default: Error("cannot load this value"); } x.kind = Item.Kinds.Stack; } internal static void LoadConst (int n) { // method of class Code switch (n) { case -1: il.Emit(LDCM1); break; case 0: il.Emit(LDC0); break;... default: il.Emit(LDC, n); break; } L’élément résultant est toujours du type Stack

49 Exemple: chargement d’une constante Factor =number(.x = new Item(token.val);// x.kind = Const Code.Load(x);// x.kind = Stack.) Description par une ATG Visualisation val 17 kind val... Const 17... x = new Item(token.val); x esp 17 estack Stack ---... Code.Load(x); x sortie ldc.i4 17 Les modules de l’analyse syntaxique (Scan, check, etc..) ne sont pas montrés

50 Exemple: chargement d’un argument Designator =ident(.Symbol sym = Tab.Find(token.str);// sym.kind = Const | Arg | Local | Global x = new Item(sym);// x.kind = Const | Arg | Local | Static Code.Load(x);// x.kind = Stack.). kind name adr... Arg "abc" 2... sym = Tab.Find(token.str); sym kind adr... Arg 2... x = new Item(sym); x esp abc estack Description par une ATG 0 1 2 3 abc args Visualisation Stack ---... Code.Load(x); x sortie ldarg.2

51 Exemple: chargement d’une variable locale Description par une ATG Designator =ident(.Symbol sym = Tab.Find(token.str);// sym.kind = Const | Arg | Local | Global Item x = new Item(sym);// x.kind = Const | Arg | Local | Static Code.Load(x);// x.kind = Stack.). kind name adr... Local "xyz" 1... sym = Tab.Find(token.str); sym kind adr... Local 1... x = new Item(sym); x Stack ---... Code.Load(x); x sortie ldloc.1 0 1 2 3 xyz locals Visualisation esp xyz estack

52 Designator (.string name;.) =ident(.name = token.str; Item x = new Item(Tab.Find(name));.) { "." ident(.if (x.type.kind == Struct.Kinds.Class) { Code.Load(x); x.sym = Tab.FindField(token.str, x.type); x.type = x.sym.type; } else Error(name + " is not an object"); x.kind = Item.Kinds.Field;.) |... }. Chargement des champs d’objet var.f Conditions de contexte ( faire les vérifications nécessaires) Designator = ident "." ident. Le type de ident doit être une classe. ident doit être un champ du Designator. Description par une ATG Chercher token.str dans La liste de champs de x.type Crée un élément de type Field Consiste à mettre l’objet dans la pile et la création d’un item de type Field

53 Exemple: chargement d’un champ d’objet ident. Designator  x.sym  Field   Créer à partir de x et x.sym un élément de type Field kind type adr Field 0 x Int esp var f estack  Stack   Code.Load(x); kind type adr Stack --- Class - x Field "f" 0 Int esp var f estack x.sym sortie ldloc.1  Local 1   Item x = new Item(Tab.Find(name)); kind type adr Local 1 Class - x Field "f" - Int var f locals

54 Designator (.string name; Item x, y;.) =ident(.name = token.str; x = new Item(Tab.find(name));.) {... |"["(.Code.Load(x);.) Expr (.if (x.type.kind == Struct.Arr) { if (y.type != Tab.intType) Error("index must be of type int"); Code.Load(y); x.type = x.type.elemType; } else Error(name + " is not an array"); x.kind = Item.Elem;.) "]" }. Chargement des éléments d’un tableau a[i] Conditions de contexte Designator = ident "[" Expr "]". Le type de ident doit être un tableau. Le type de Expr doit être int. Description par une ATG La vérification de l’indice est faite dans la CLR crée un élément de type Elem Consiste à mettre le tableau et l’indice dans la pile et la création d’un item de type Elem

55 Exemple: chargement d’un élément de tableau identExpr[ Designator  Local 1   Item x = new Item(Tab.Find(name)); kind type adr Local 1 Arr x Int  Elem   Créer à partir de x un élément de type Elem kind type adr Elem --- x Int ]  Local 0   y = Expr(); kind type adr Local 0 y Int  Stack   Code.Load(y); kind type adr Stack --- y ldloc.0 Int a i estack  Stack   Code.Load(x); kind type adr Stack --- x Arr Int ldloc.1 a estack a i locals

56 Génération de code Généralités La machine virtuelle de.NET:CLR(Common Language Runtime) Éléments Expressions Affectations Saut et étiquette Structures de contrôle Méthodes

57 Compilation des expressions (Expr) Schéma pour x + y + z load x load y add load z add Description par une ATG Expr (.Item y; OpCode op;.) =("-" Term (.if (x.type != Tab.intType) Error("operand must be of type int"); if (x.kind == Item.Kinds.Const) x.val = -x.val; else { Code.Load(x); Code.il.Emit(Code.NEG); }.) |Term ) {( "+"(. op = Code.ADD;.) | "-"(. op = Code.SUB;.) )(.Code.Load(x);.) Term (.Code.Load(y); if (x.type != Tab.intType || y.type != Tab.intType) Error("operands must be of type int"); Code.il.Emit(op);.) }. conditions de contexte Expr = "-" Term. Term doit être de type int. Expr = Expr Addop Term. Expr et Term doivent être de type int.

58 Compilation des termes (Term) Term = Term Mulop Factor. Term et Factor doivent être de type int. Term (.Item y; OpCode op;.) =Factor {( "*"(.op = Code.mul;.) | "/"(.op = Code.div;.) | "%"(.op = Code.rem;.) )(.Code.Load(x);.) Factor (.Code.Load(y); if (x.type != Tab.intType || y.type != Tab.intType) Error("operands must be of type int"); Code.il.Emit(op);.) }.

59 Compilation des facteurs (Factor) Factor = "new" ident. ident doit être une une classe. Factor = "new" ident "[" Expr "]". ident doit dénoter un type. Le type de Expr doit être int. Factor =Designator // functions calls see later |number(.x = new Item(token.val);.) |charConst(.x = new Item(token.val); x.type = Tab.charType;.) |"(" Expr ")" |"new" ident(.Symbol sym = Tab.find(token.str); if (sym.kind != Symbol.Kinds.Type) Error("type expected"); Struct type = sym.type;.) ( "[" Expr "]"(.if (x.type != Tab.intType) Error("array size must be of type int"); Code.Load(x); Code.il.Emit(Code.NEWARR, type.sysType); type = new Struct(Struct.Kinds.Arr, type);.) |(.if (type.kind == Struct.Kinds.Class) Code.il.Emit(Code.NEWOBJ, sym.ctor); else { Error("class type expected"); type = Tab.noType; }.) )(.x = new Item(Item.Kinds.Stack); x.type = type;.).

60 Exemple var.f + 2 * var.g var  Local 0.f Designator var  Local 0.g Designator  Field g Factor  Field g 2 Factor  Const 2 * Term  Stack Term Factor  Field f + Expr  Stack   ldloc.0   Stack  ldfld T fld_f    Stack ldc.i4.2    Stack ldloc.0   Stack  ldfld T fld_g   Stack  mul   Stack  add var locals f g

61 Génération de code Généralités La machine virtuelle de.NET:CLR(Common Language Runtime) Éléments Expressions Affectations Saut et étiquette Structures de contrôle Méthodes

62 Modèles de code pour les affectations 5 cas selon le type du membre gauche de l’affectation localVar = expr;... load expr... stloc localVar globalVar = expr;... load expr... stsfld T globalVar obj.f = expr; ldloc obj... load expr... stfld T f instructions en bleu sont générées par Designator! arg = expr;... load expr... starg arg a[i] = expr; ldloc a ldloc i... load expr... stelem.i2 i4 ref Selon le type de l’élément (char, int, référence objet)

63 Compilation des affectations Condition de contexte Statement = Designator "=" Expr ";". Designator doit dénoter une variable, un élément de tableau ou un champ d’un objet. Le type de Expr doit être compatible avec le type de Designator. Description par une ATG Assignment(.Item x, y;.) =Designator // this call may already generate code "=" Expr (.Code.Load(y); if (y.type.AssignableTo(x.type)) Code.Assign(x, y); // x: Arg | Local | Static | Field | Elem else Error("incompatible types in assignment");.) ";". Compatibilité de l’affectation y est compatible avec x, si x et y ont le même type (x.type == y.type), ou x et y sont des tableaux de même de type, ou x a un type de référence (classe ou tableau) et y est null

64 Génération de code Généralités La machine virtuelle de.NET:CLR(Common Language Runtime) Éléments Expressions Affectations Saut et étiquette Structures de contrôle Méthodes

65 Saut conditionnel et inconditionnel Saut inconditionnel br offset Saut conditionnel... load operand1...... load operand2... beq offset si (opérande1 == opérande2) saut vers offset beq bge bgt ble blt bne.un Saut si = Saut si >= Saut si > Saut si <= Saut si < Saut si #

66 Sauts en avant et arrière Saut arrière (backward) Distance du saut Utilise 4 octets (CIL a aussi une forme courte avec un seul octet) relatif au début de la prochaine instruction (= fin de l’instruction de saut) L’adresse cible (étiquette) est déjà connue (car l’instruction à cet endroit a déjà été générée) br -7 instr Saut en avant (Forward) L’adresse cible (étiquette) n’est pas encore connue  la laisser à vide  la mettre à jour par la suite br ? La mise à jour est faite quand l’adresse devient connue br 2 instr

67 Utilisation de méthodes de ILgenerator Représentation des étiquettes de saut struct Label {... } Utilisation Label label = Code.il.DefineLabel();... Code.il.Emit(Code.BR, label);// jump to the yet undefined label (forward jump).. Code.il.MarkLabel(label);// now the branch to label leads here Les étiquettes sont gérées par ILGenerator. class ILGenerator {... Label DefineLabel ();// create a yet undefined jump label void MarkLabel (Label);// define the label at the current position in the IL stream }

68 Conditions if ( a > b )... Condition Modèle de code load a load b ble... Condition retourne l’opérateur de comparaison; la comparaison est faite dans l’instruction de saut Saut-si-vrai et Saut-si-faux Saut-si-vraiSaut si la condition est vraie Saut-si-fauxSaut si la condition est fausse Conditions L’élément Cond Condition retourne un élément avec un nouveau type Item.Kinds.Cond avec: Code de l’unité correspondant à l’opérateur de comparaison : public int relop; // Token.EQ,.GE,.GT,.LE,.LT,.NE Étiquettes spéciales de sauts : - public Label tLabel : pour les saut-si-vrai - public Label fLabel : pour les saut-si-faux nécessaire pour les conditions qui contiennent les opérateurs && et ||

69 L’élément Cond class Item { public enum Kinds { Const, Arg, Local, Static, Field, Stack, Elem, Meth, Cond } Kindskind; Structtype;// type of the operand intval;// Const: constant value intadr;// Arg, Local: address intrelop;// Cond: token code of the operator LabeltLabel;// jump label for true jumps LabelfLabel;// jump label for false jumps Symbolsym;// Field, Meth: symbol table node } Nouveau constructeur (pour les éléments Cond ) public Item (int relop, Struct type) { this.kind = Kinds.Cond; this.type = type; this.relop = relop; tLabel = Code.il.DefineLabel(); fLabel = Code.il.DefineLabel(); }

70 Génération de saut conditionnel Avec les méthodes de la classe Code Utilisation "if" "(" Condition ")"(. Code.FJump(x);.) class Code { static readonly OpCode[] brTrue = { BEQ, BGE, BGT, BLE, BLT, BNE }; static readonly OpCode[] brFalse = { BNE, BLT, BLE, BGT, BGE, BEQ };... internal static void TJump (Item x) { il.Emit(brTrue[x.relop - Token.EQ], x.tLabel); } internal static void FJump (Item x) { il.Emit(brFalse[x.relop - Token.EQ], x.fLabel); }... }

71 Génération de saut inconditionnel Avec une méthode de la classe Code class Code {... internal static void Jump (Label lab) { il.Emit(BR, lab); }... } Utilisation Label label = Code.il.DefineLabel();... Code.Jump(label);

72 Génération de code Généralités La machine virtuelle de.NET:CLR(Common Language Runtime) Éléments Expressions Affectations Saut et étiquette Structures de contrôle Méthodes

73 L’instruction while Modèle de code désiré whiletop: (Condition)... code for Condition... FJump end Statement... code for Statement... br top end:... Description par une ATG WhileStatement(.Item x;.) ="while"(.Label top = Code.il.DefineLabel(); top.here();.) "(" Condition ")"(.Code.FJump(x);.) Statement(.Code.Jump(top); Code.il.MarkLabel(x.fLabel);.). Exemple while (a > b) a = a - 2; 10ldloc.0 11ldloc.1 top 12ble 17ldloc.0 18ldc.i4.2 19sub 20stloc.0 21br -16 (=10) x.fLabel 26... 9 (=26)

74 L’instruction if Modèle de code désiré if (Condition)... Condition... FJump end Statement... Statement... end:... Description par une ATG IfStatement(.Item x; Label end;.) ="if" "(" Condition ")"(.Code.FJump(x);.) Statement ("else"(.end = Code.il.DefineLabel(); Code.Jump(end); Code.il.MarkLabel(x.fLabel);.) Statement(.Code.il.MarkLabel(end);.) |(.Code.il.MarkLabel(x.fLabel);.) ). Exemple if (a > b) max = a; else max = b; if (Condition)... Condition... FJump else Statement... Statement... br end elseelse: Statement... Statement... end:... 7 (=24) x.fLabel 17ldloc.0 18stloc.2 24ldloc.1 25stloc.2 10ldloc.0 11ldloc.1 12ble 19br2 (=26) 26... end

75 Fonctionne aussi pour les if emboîtés IfStatement(.Item x; Label end;.) ="if" "(" Condition ")"(.Code.FJump(x);.) Statement ("else"(.end = Code.il.DefineLabel(); Code.Jump(end); Code.il.MarkLabel(x.fLabel);.) Statement(.Code.il.MarkLabel(end);.) |(.Code.il.MarkLabel(x.fLabel);.) ).... stat... stat if (c1)... c1... FJump... elsebr... if (c2)... c2... FJump... s1... s1... elsebr... s2... s2... if (c3)... c3... FJump... s3... s3... elsebr... s4... s4...

76 Génération de code Généralités La machine virtuelle de.NET:CLR(Common Language Runtime) Éléments Expressions Affectations Saut et étiquette Structures de contrôle Méthodes

77 Appel de Procédure M(a, b); Ldloc.s a Ldloc.s b call T meth Les paramètres sont passés dans la pile estack Modèle du code Statement(.Item x, y;....) =Designator (ActPars (.Code.il.EmitCall(Code.CALL, x.sym.meth, null); if (x.type != Tab.noType) Code.il.Emit(Code.POP);.) |"=" Expr ";"(.....) ) |.... Description par une ATG

78 Appel de fonction c = M(a, b); ldloc.s a ldloc.s b call T meth stloc.s c La value de la fonction est retournée dans la estack Les paramètres sont passés dans la pile estack Modèle de code Factor =Designator [ActPars (.if (x.type == Tab.noType) Error("procedure called as a function"); if (x.sym == Tab.ordSym || x.sym == Tab.chrSym) ; // nothing to do else if (x.sym == Tab.lenSym) // array length Code.il.Emit(Code.LDLEN); else if (x.kind == Item.Kinds.Meth) Code.il.Emit(Code.CALL, x.sym.meth, null); x.kind = Item.Stack;.) ] |.... Description par une ATG

79 Déclaration de méthode MethodDecl(.Struct type; int n;.) =(Type |"void"(.type = Tab.noType;.) ) ident(.curMethod = Tab.Insert(Symbol.Kinds.Meth, token.str, type); Tab.openScope();.) "(" [ FormPars ] ")"(.curMethod.nArgs = Tab.topScope.nArgs; curMethod.locals = Tab.topScope.locals; Code.CreateMetadata(curMethod); if (curMethod.name == "Main") { if (curMethod.type != Tab.noType) Error("method Main must be void"); if (curMethod.nArgs != 0) Error("method Main must not have parameters"); }.) { VarDecl }(.curMethod.nLocs = Tab.topScope.nLocs; curMethod.locals = Tab.topScope.locals;.) Block (.if (curMethod.type == Tab.noType) Code.il.Emit(Code.RET); else { // end of function reached without a return statement Code.il.Emit(Code.NEWOBJ, Code.eeexCtor); Code.il.Emit(Code.THROW); } Tab.closeScope();.). Variable globale

80 Les paramètres formels Sont entrés dans la table des symboles (comme des symboles Arg de la portée de la méthode) La portée de la méthode compte leur nombre (dans nArgs) FormPars = FormPar { "," FormPar }. FormPar(.Struct type;.) =Type ident(.Tab.Insert(Symbol.Kinds.Arg, token.str, type);.).

81 Les paramètres réels Les charger dans la pile estack Vérifier la compatibilité des types entre les paramètres formels et réels Vérifier si le nombre de paramètres réels est égal au nombre de paramètres formels ActPars (.Item ap; int aPars = 0, fPars = 0;.) ="("(.if (m.kind != Item.Kinds.Meth) { Error("not a method"); m.sym = Tab.noSym; }.) fPars = m.sym.nArgs; Sym fp= m.sym.locals;.) [Expr (.Code.Load(ap); aPars++; if (fp != null && fp.kind == Symbol.Kinds.Arg) { if (!ap.type.AssignableTo(fp.type)) Error("parameter type mismatch"); fp = fp.next; }.) { "," Expr (.Code.Load(ap); aPars++; if (fp != null && fp.kind == Symbol.Kinds.Arg) { if (!ap.type.AssignableTo(fp.type)) Error("parameter type mismatch"); fp = fp.next; }.) } ](.if (aPars > fPars) Error("more actual than formal parameters"); else if (aPars < fPars) Error("less actual than formal parameters");.) ")".

82 L’instruction return Statement =... |"return" ((.if (curMethod.type == Tab.noType) Error("void method must not return a value");.) Expr (.Code.Load(x); if (x.type.AssignableTo(curMethod.type)) Error("type of return value must be assignable to method type");.) |(.if (curMethod.type != Tab.noType) Error("return value expected");.) )(.Code.il.Emit(Code.RET);.) ";".


Télécharger ppt "Génération de code Pr ZEGOUR DJAMEL EDDINE Ecole Supérieure d’Informatique (ESI)"

Présentations similaires


Annonces Google