C#: .NET


Intermediate language: IL

Code exists on many levels. Abstraction is a ladder. At the highest levels of abstraction, we have C# code. At a lower level, we have an intermediate language. The IL has instructions (opcodes) that manipulate the stack.

And:These instructions, called intermediate language opcodes, reside in a relational data based called the metadata.

Activation Record


Compiler theory can be divided into two parts. Analysis is where the high-level source code is parsed and a symbol table is derived for further processing. Synthesis is where the object code is generated and written to an executable.

Analysis:Source code is parsed and a symbol table is derived. Analysis comes before synthesis.

Framework: NET

Synthesis:Object code is generated and written to an executable. Analysis and synthesis result in an intermediate form.


On execution of the intermediate form, another compiler, the JIT compiler, will be invoked and perform even more optimizations. In this example, we see a C# method and its compiled intermediate language form.

Example program: C#

using System;

class Program
    static void Main()
	int i = 0;
	while (i < 10)

Intermediate language for Main method: IL

.method private hidebysig static void Main() cil managed
    .maxstack 2
    .locals init (
	[0] int32 num)
    L_0000: ldc.i4.0
    L_0001: stloc.0
    L_0002: br.s L_000e
    L_0004: ldloc.0
    L_0005: call void [mscorlib]System.Console::WriteLine(int32)
    L_000a: ldloc.0
    L_000b: ldc.i4.1
    L_000c: add
    L_000d: stloc.0
    L_000e: ldloc.0
    L_000f: ldc.i4.s 10
    L_0011: blt.s L_0004
    L_0013: ret
Main method

IL for Main method. In the second part of the text, you can see the intermediate form of the Main method. You can see three flagged sections in the first part of the body of the method.

In the IL:The Main method is the entry point. The stack has a maximum size. There is one local variable.


Const keyword

At L_0000, you can see that the constant number zero is pushed onto the evaluation stack through the instruction ldc. Then, this constant is stored from the evaluation stack into the local variable.

ConstSquares: abstract

Branch. In the intermediate language,
when you see the instruction "br",
this indicates a branch. A branch instruction is a conditional instruction that will change what instruction is executed next based on the condition.

Tip:In the C# language, things such as goto, while, for, break, and return may be implemented with variants of the branch instruction.


Call method. Next, the method Console.WriteLine, which is implemented externally, is called. Before it is called, the location of the local variable we are writing is pushed to the evaluation stack and this is used as an argument.


Increment. In the intermediate language, an increment expression such as i++ is implemented by pushing a constant one to the evaluation stack, and then using the add arithmetic instruction to increment.

Increment IntDecrement Int

Loop instructions. The line L_0011 implements another instruction that returns control to the beginning of the loop if the condition is met. This is another form of a branch instruction.


Note:Branch instructions use labels in the intermediate language. Branches are basically goto statements at the lower level.

Also:All high-level loops, including for, while and foreach, can be translated into branches and labels.


IL Disassembler

Programming tip

To gain an understanding of the C# language, I recommend that you inspect the intermediate language for all the code you write. You only need to do this until you are comfortable with how it works.

Also, you can actually modify your code to see how the intermediate language is affected. There are many surprises in this process. This is a key to learning how the language itself is implemented.

Tip:IL Disassembler is provided with Visual Studio. We use it to look at the intermediate language.

IL Disassembler



Instructions (opcodes) in the intermediate language (IL) execute statements. These instructions act upon and manipulate the evaluation stack.
We cover some,
but not all,
of these instructions.



The intermediate language is not needed every day. It usually goes without notice. But it opens up a new way of understanding what C# code does. Scope, and all loops, are flattened into branches and labels.