Common Intermediate Language
Common Intermediate Language (CIL, vyslovováno jako "sil", případně "kil") (dříve Microsoft Intermediate Language nebo MSIL) je nejnižší člověkem čitelný programovací jazyk definovaný specifikací Common Language Infrastructure a používá .NET Framework a Mono. Jazyky, které se zaměřují na CLI kompatibilní prostředí, jsou sestavovány do byte kódu (Bytecode). CIL patří mezi objektově orientované jazyky výhradně zásobníkového typu (stack-based). Prováděn je prostřednictvím virtuálního stroje.
CIL byl původně znám jako Microsoft Intermediate Language (MSIL) během uvolňování beta .NET jazyků. Vzhledem ke standardizaci C# a Common Language Infrastructure je byte-kód oficiálně známý jako CIL. Na základě tohoto odkazu, je stále ještě CIL označován jako MSIL, především od dlouhodobých uživatelů .NET jazyků.
Základní informace
Při kompilování .NET programovacích jazyků, je zdrojový kód přeložen do CIL kódu, spíše než do platformy nebo do výpočetně-specifického objektového kódu. CIL je procesorově a zároveň platformě nezávislý soubor instrukcí, které mohou být realizovány v jakémkoli prostředí podporující Common Language Infrastructure (může se jednat buď o .NET runtime pro operační systém Microsoft Windows, nebo samostatně odvozené Mono, které pracuje pod operačními systémy jako Linux či Unix). CIL kód je ověřen z hlediska bezpečnosti „za běhu“, který poskytuje lepší zabezpečení a spolehlivost, než nativně kompilované binární soubory.
Proces spuštění vypadá takto:
1. Zdrojový kód je převeden do Common Intermediate Language, CLI ekvivalent k nižším programovacím jazykům pro CPU.
2. CIL je pak převeden do byte-kódu a je vytvořeno .NET assembly.
3. Po provedení .NET assembly, jeho byte kód projde skrz provozní JIT kompilátor, aby generoval nativní kód.
4. Nativní kód je zpracováván pomocí procesoru.
Instrukce
CIL bytecode má instrukce pro následující skupiny úloh:
- Načítání a ukládání
- Aritmetické
- Typ konverze
- Vytváření objektů a manipulaci s nimi
- Operand managementu zásobníku (push / pop)
- Kontrola převodu (větvení - Branching)
- Volání metod
- Vyhazování výjimky
- Synchronizace
Výpočetní model
Common Intermediate Language je považován za objektově orientovaný jazyk zásobníkového typu (stack-based). To znamená, že data jsou tlačena do zásobníku místo toho, aby byla vytahována z registrů, jako ve většině CPU architektur.
V architektuře x86 by to mohlo vypadat následovně:
add eax, edx
mov ecx, eax
Odpovídající kód v IL může být vyjádřen jako tento:
ldloc.0
ldloc.1
add
stloc.0 // a = a + b or a += b;
Zde jsou dvě lokálně proměnné, které se přesunou do fronty. Když je přidaná instrukce zavolána, operand je vyhozen a výsledek je posunut Zbývající hodnota je pak vyhozena a uložena jako první lokální proměnná.
Objektově-orientované koncepty
Toto se vztahuje rovněž na objektově-orientované koncepty. Můžete vytvářet objekty, volat metody a používat další typy členů, jako jsou například pole.
CIL je dizajnován jako objektově orientovaný a všechny metody (až na výjimky) musí být obsažené v příslušné třídě.
Příklad statické metody:
.class public Foo
{
.method public static int32 Add(int32, int32) cil managed
{
.maxstack 2
.locals init (
[0] int32 num1,
[1] int32 num2
)
ldloc.0
ldloc.1
add
stloc.0 // a = a + b or a += b;
ret // return a;
}
}
Tato metoda nevyžaduje žádnou deklaraci instance třídy Foo, protože je statická. To znamená ze náleží do třídy a může být následně použit jako v tomto případě v C#.
int r = Foo.Add(2, 3); //5
V CIL
ldc.i4.2
ldc.i4.3
call int32 Foo::Add(int32, int32)
stloc.0
Instance tříd
Instance třídy obsahuje nejméně jeden konstruktor a nějaké další členy. Tato třída má sadu metod reprezentujících akce objektu Car.
.class public Car
{
.method public specialname rtspecialname
instance void .ctor(int32, int32) cil managed
{
/* Constructor */
}
.method public void Move(int32) cil managed
{
/* Omitting implementation */
}
.method public void TurnRight() cil managed
{
/* Omitting implementation */
}
.method public void TurnLeft() cil managed
{
/* Omitting implementation */
}
.method public void Break() cil managed
{
/* Omitting implementation */
}
}
Vytváření objektů
Instance tříd v C# jsou vytvářeny následujícím způsobem:
Car myCar = new Car(1, 4);
Car yourCar = new Car(1, 3);
<source lang="csharp">
A ty to příkazy jsou přibližně stejné jako tyto instrukce:
<source lang="cil">
ldc.i4.1
ldc.i4.4
newobj instance void Car::.ctor(int, int)
stloc.0 // myCar = new Car(1, 4);
ldc.i4.1
ldc.i4.3
newobj instance void Car::.ctor(int, int)
stloc.1 // yourCar = new Car(1, 3);
Vyvolání metody instance
Například metody jsou volány následovně:
myCar.Move(3);
V CIL
ldloc.0 // Load the object "myCar" on the stack
ldc.i4.3
call instance void Car::Move(int32)
Metadata
.NET zaznamenává informace o kompilovaných třídách jako metadata. Proces čtení těchto metadat se nazývá zrcadlení (reflection).
Metadata mohou být data v podobě atributů. Ty mohou být volně rozšířeny o atributy třídy, čímž se stávají velmi silným nástrojem.
Příklad
Příklad níže je napsán v CIL a demonstruje kód „Hello, World“.
.assembly Hello {}
.assembly extern mscorlib {}
.method static void Main()
{
.entrypoint
.maxstack 1
ldstr "Hello, world!"
call void [mscorlib]System.Console::WriteLine(string)
ret
}
Tento kód může být porovnán s odpovídajícím kódem Java Bytecode.
static void Main(string[] args)
{
outer:
for (int i = 2; i < 1000; i++)
{
for (int j = 2; j < i; j++)
{
if (i % j == 0)
goto outer;
}
Console.WriteLine(i);
}
}
V CIL-syntaxi by zápis vypadal následovně:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 2
.locals init (int32 V_0,
int32 V_1)
IL_0000: ldc.i4.2
stloc.0
br.s IL_001f
IL_0004: ldc.i4.2
stloc.1
br.s IL_0011
IL_0008: ldloc.0
ldloc.1
rem
brfalse.s IL_0000
ldloc.1
ldc.i4.1
add
stloc.1
IL_0011: ldloc.1
ldloc.0
blt.s IL_0008
ldloc.0
call void [mscorlib]System.Console::WriteLine(int32)
ldloc.0
ldc.i4.1
add
stloc.0
IL_001f: ldloc.0
ldc.i4 0x3e8
blt.s IL_0004
ret
}
Toto je správná reprezentace toho, jak vypadá CIL blízko VM úrovně. Když jsou zkompilované metody uloženy v tabulkách a instrukce zase v bytech uvnitř assembly, který je přenosně spustitelným souborem (Portable Executable-file).
Vývoj
CIL assembly a instrukce jsou generovány buď kompilátorem nebo nástrojem zvaným jako IL Assembler (ILASM).
Složené IL může být také znovu rozloženo do kódu užitím IL Disassembler (ILDASM). Existují další nástroje jako .NET Reflektor, které umožní dekompilaci IL do jazyků vyšší úrovně (např. C#, Visual Basic). Tato vlastnost je sdílená s Java bytecode. Ale existují nástroje, které mohou zmást kód, a to tak, že vlastní kód nemůže být rozložen, ale přesto je spustitelný.
Vykonávání kompilace
Kompilování (just-in-time)
Just-in-time kompilace zahrnuje vrácení byte-kódu do kódu, který je okamžitě vykonatelný pomocí CPU. Konverze je prováděna postupně v průběhu vykonávání programu. JIT kompilace nabízí specifické optimalizace daného prostředí a ověření assembly. K dosažení tohoto, JIT kompilátor zkoumá nashromážděná metadata pro nezákonné přístupy a ovládá přiměřeně rušení.
Externí odkazy
- Common Language Infrastructure (Standard ECMA-335)
- “ECMA C# and Common Language Infrastructure Standards” on MSDN
- Hello world program in CIL
- Kenny Kerr's intro to CIL (called MSIL in the tutorial)
- Speed: NGen Revs Up Your Performance With Powerful New Features -- MSDN Magazine, April 2005
- http://en.csharp-online.net/CIL_Instruction_Set
V tomto článku byl použit překlad textu z článku Common_Intermediate_Language na anglické Wikipedii (číslo revize nebylo určeno).