la machine virtuelle de.net:clr(common language runtime) pr zegour djamel eddine ecole supérieure...
TRANSCRIPT
La machine virtuelle de .NET:CLR(Common Language Runtime)
Pr ZEGOUR DJAMEL EDDINE
Ecole Supérieure d’Informatique (ESI)
www.zegour.uuuq.com
email: [email protected]
La machine virtuelle de .NET:CLR(Common Language Runtime)
Architecture
Organisation de la mémoire
Code IL et méta données générés
Ensemble des instructions de la CLR
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)
Architecture de la CLR: machine à pile
Exemple
instruction i = i + j * 5; Suppose les valeurs suivantes de i et j
Simulation
instructions pile
ldloc.0 Charger la variable se trouvant à l’adresse 0 (c.a.d. i)3
add Ajouter les 2 éléments en sommet de pile23
lldloc.1 Charger la variable se trouvant à l’adresse 1 (c.a.d. j)3 4
ldc.i4.5 Charger la constante 53 4 5
mul Multiplier les 2 éléments en sommet de pile3 20
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!
34 j
i01
locals
La machine virtuelle de .NET:CLR(Common Language Runtime)
Architecture
Organisation de la mémoire
Code IL et méta données générés
Ensemble des instructions de la CLR
Organisation de la mémoire
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 Tfld charge la valeur du champ référencé par Tfld 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’.
Organisation de la mémoire
É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éclarationsEx. 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
MSP
PMSP
Q
MSQ
MSP
R
MSQ
MSR
P appelle Q; Q appelle R
Organisation de la mémoire
Le tas (Heap)
• Contient les objets ‘classe’ et ‘tableau’
0heap
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’
Organisation de la mémoire
Les objets ‘class’
class X {int a, b;char c;
}
X obj = new X;
a
b
c
heapobj
• adressé par le champ relatif à obj
Les objets ‘array’
int[] a = new int[4];a[0]
a[1]
a[2]
heapa
• 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
Organisation de la mémoire
Le tas Heap
0
k
free
args
locals
estack
0 1 2
0 1 2 3
MSS
MSP
MSQ
MSR
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
La machine virtuelle de .NET:CLR(Common Language Runtime)
Architecture
Organisation de la mémoire
Code IL et méta données générés
Ensemble des instructions de la CLR
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 ?
Code IL à générerpublic 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 assemblystatic ModuleBuilder module; // metadata builder for the program modulestatic TypeBuilder program; // metadata builder for the main classstatic TypeBuilder inner; // metadata builder for the currently compiled inner class
internal static ILGenerator il; // IL stream of currently compiled method
//----- metadata generationinternal 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) {... }
… }
Code IL à générer
• Chaque méthode est composée d’un flot d’instructions CIL et de méta-donnéescomme .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 OpCodeLDARG0 = 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);
Code IL à générer : méthodes Emit
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[]);
...}
Meta-données à générer
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 assemblystatic ModuleBuilder module; // the program modulestatic TypeBuilder program; // the main classstatic TypeBuilder inner; // the currently compiled inner class
Décrivent les propriétés des composants d’un assemblage (types, champs, méthodes, ...).
Meta-données à générer
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;
...}
Exemple1 : pour un programme
La CLR gère les deux comme des champs (champ statique de la class ‘program’; champ dela 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 Symbolinternal 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;...
}
Meta-données à générer
Exemple2 : pour les variables globales et champs d’une structure
La machine virtuelle de .NET:CLR(Common Language Runtime)
Architecture
Organisation de la mémoire
Code IL et méta données générés
Ensemble des instructions de la CLR
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.0starg.1add
ldc.i4.3ldelem.i2stelem.ref
Typée
Format des instructions
Très simple comparé a Intel, PowerPC ou SPARC
Code = { Instruction }.Instruction = opcode [ operand ].
opcode ... 1 or 2 octetsoperand ... de type primitif ou unité metadata
Exemples
0 opérande add a 2 opérandes implicites sur la pile1 opérande ldc.i4.s 9
Ensemble des instructions de la CLRModes d’adressageComment 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’adressage exemple
Relatif
base addressesp
estack
Indexé
base address
esp
estack
index
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.s b ......, val
chargerpush(args[b]);
starg.s b ..., val...
Rangerargs[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.s b ..., val...
Rangerlocals[b] = pop();
ldloc.s b ......, val
chargerpush(locals[b]);
ldloc.n ......, val
charger (n = 0..3)push(locals[n]);
Chargement et rangement de variables locales
Ensemble des instructions de la CLR
Chargement et rangement de variables globales
stsfld Tfld ..., val...
Ranger une variable statiquestatics[Tfld] = pop();
ldsfld Tfld ......, val
Charger une variable statiquepush(statics[Tfld]);
Chargement et rangement d’objets champ
stfld Tfld ..., obj, val...
Ranger un objet champval = pop(); obj = pop();heap[obj+Tfld] = val;
ldfld Tfld ..., obj..., val
Charger un objet champobj = pop(); push(heap[obj+Tfld]); Tfld
estack
adr
estack
Heap
Ensemble des instructions de la CLR
Chargement de constantes
ldc.i4.n ......, n
Charge une constante (n = 0..8)push(n);
ldc.i4 i ......, i
Charge une constantepush(i);
ldc.i4.m1 ......, -1
Charge la constante -1push(-1);
ldnull ......, null
Charge la constante nullpush(null);
Exemples: chargement et rangement
ax = ay;
x0y1p2
xy
ldarg.1 1 aystarg.s 0 2 -
Code Octets estack
gx = gy; ldsfld Tfld_gy 5 gystsfld Tfld_gx 5 -
gxgy
staticslocals
p.x = p.y; ldloc.2 1 pldloc.2 1 p pldfld Tfld_y 5 p p.ystfld Tfld_x 5 -
axay
args
01
x = y; ldloc.1 1 ystloc.0 1 -
Ensemble des instructions de la CLRArithmétiques
sub ..., val1, val2..., val1-val2
Soustrairepush(-pop() + pop());
add ..., val1, val2..., val1+val2
Ajouterpush(pop() + pop());
div ..., val1, val2..., val1/val2
Diviserx = pop(); push(pop() / x);
mul ..., val1, val2..., val1*val2
Multiplierpush(pop() * pop());
neg ..., val..., -val
Négatifpush(-pop());
rem ..., val1, val2..., val1%val2
Restex = pop(); push(pop() % x);
Exemples: arithmétiques
x + y * 3 ldloc.0 1 xldloc.1 1 x yldc.i4.3 1 x y 3mul 1 x y*3add 1 x+y*3
Code Octets Pile
x++; ldloc.0 1 xldc.i4.1 1 x 1add 1 x+1stloc.0 1 -
x--; ldloc.0 1 xldc.i4.m1 1 x -1add 1 x-1stloc.0 1 -
p.x++ ldloc.2 1 pdup 1 p pldfld Tpx 5 p p.xldc.i4.1 1 p p.x 1add 1 p p.x+1stfld Tpx 5 -
x0y1p2
xy
locals
a3int[]t14
t25
Ensemble des instructions de la CLRCréation d‘objets
newarr TeType ..., n..., arr
Nouveau tableaucrée un tableau avec l’espace pour n élémentsde type spécifié par l’unité type
newobj Tctor ... [ arg0, ..., argN ]..., obj
Nouvel objetcrée un nouveau objet de type spécifié par
l’unité ’constructeur’ puis exécute le constructeur (les arguments sont dans la pile)
Exemples: création d’objets
Person p = new Person;
p0
a1
newobj TP() 5 p stloc.0 1 -
Code Octets Pile
int[] a = new int[5]; ldc.i4.5 1 5newarr Tint 5 astloc.1 1 -
locals
Ensemble des instructions de la CLRAccès aux tableaux
stelem.i2stelem.i4stelem.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.u2ldelem.i4ldelem.ref
..., adr, i
..., valCharger 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
ai
ldlen ..., adr..., len
Obtenir la longueur du tableau
Exemple1: accès aux tableaux
Code Octets Pile
locals
a[2]++ ldloc.0 1 aldc.i4.2 1 a 2stloc.s 2 2 astloc.s 1 2 -ldloc.s 1 2 aldloc.s 2 2 a 2ldloc.s 1 2 a 2 aldloc.s 2 2 a 2 a 2ldelem.i4 1 a 2 a[2]ldc.i4.1 1 a 2 a[2] 1add 1 a 2 a[2]+1stelem.i4 1 -
a0int[]t11
t22
Exemple2: accès aux tableaux
a[i] = b[i+1];
a0b1
ldloc.0 1 aldloc.2 1 a ildloc.1 1 a i bldloc.2 1 a i b ildc.i4.1 1 a i b i 1add 1 a i b i+1ldelem.i4 1 a i b[i+1]stelem.i4 1 -
Code Octets Pile
locals
i2 int[]
int[]
Ensemble des instructions de la CLRManipulation de la pile
pop ..., val...
Enlever l’élément au sommet de piledummy = pop();
dup ..., val..., val, val
Duplique l’élément au sommet de pile
x = pop(); push(x); push(x);Branchement
br i ......
Branchement inconditionnelpc = pc + i
pc désigne l’instructioncourante;i (distance du saut)relative par rapport à la prochaine instruction
b<cond> i ..., x, y...
Branchement conditionnel (<cond> = eq | ge | gt | le | lt | ne.un)
y = pop(); x = pop();if (x cond y) pc = pc + i;
Exemple: branchements
if (x > y) {...
}...
x0y1
ldloc.0 1 xldloc.1 1 x yble ... 5 -
Code Octets Pile
locals
Ensemble des instructions de la CLRAppel de méthode
call Tmeth... [ arg0, ...
argN ]... [ retVal ]
Appel de méthodedé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
Exemplevoid 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.01: ldloc.12: ble 7 (=14)7: ldloc.08: stloc.29: br 2 (=16)
14: ldloc.115: stloc.216: ldloc.017: ldc.i4.018: ble 15 (=38)23: ldloc.324: ldloc.025: ldloc.126: mul27: add28: stloc.329: ldloc.030: ldc.i4.131: sub32: stloc.033: br -22 (=16)38: return
adresses
a ... 0b ... 1max ...2sum ... 3