tags:

views:

1829

answers:

4
+5  Q: 

CLR vs JIT

What is the difference between the JIT compiler and CLR? If you compile your code to il and CLR runs that code then what is the JIT doing? How has JIT compilation changed with the addition of generics to the CLR?

+20  A: 

You compile your code to IL which gets executed and compiled to machine code during runtime, this is what's called JIT.

Edit, to flesh out the answer some more (still overly simplified):

When you compile your C# code in visual studio it gets turned into IL that the CLR understands, the IL is the same for all languages running on top of the CLR (which is what enables the .NET runtime to use several languages and inter-op between them easily).

During runtime the IL is interpreted into machine code (which is specific to the architecture you're on) and then it's executed. This process is called Just In Time compilation or JIT for short. Only the IL that is needed is transformed into machine code (and only once, it's "cached" once it's compiled into machinecode), just in time before it's executed, hence the name JIT.

This is what it would look like for C#

C# Code > C# Compiler > IL > .NET Runtime > JIT Compiler > Machinecode > Execution

And this is what it would look like for VB

VB Code > VB Compiler > IL > .NET Runtime > JIT Compiler > Machinecode > Execution

And as you can see only the two first steps are unique to each language, and everything after it's been turned into IL is the same which is, as I said before, the reason you can run several different languages on top of .NET

thr
+1 Good explanation.
Andrew Hare
-1 for referring to IL as bytecode, it's a Java semantic. IL (formerly MSIL) is the correct term don't confuse the two. Change that and you got my vote.
John Leidegren
@John Leidegren: Good point, changed it.
thr
Is it true that the JIT compiles the code to machine code the first time you run the program, and after that the compilation is skipped and the compiled code is used? If so it might be worth incorporating this into your answer.
Patrick McDonald
The JITTing currently happens on a per method basis. the code is self modifying. This is an implmentation detail they are free to change though
ShuggyCoUk
CIL IS a bytecode, I don't understand why do you thing it isn't, refer to the ECMA CLI spec (Partition II) for hex code for the CIL.
Jorge Córdoba
@fredrikholmstrom - Good, the size of IL instructions are 2 bytes and not single bytes. The term bytecode does not belong in the CLI. IL is just short of intermediate language and it's just that, intermediate.
John Leidegren
Correction, ECMA CLI spec (Partition III)
Jorge Córdoba
If you talk bytecode, I would presume you where talking about Java bytecode. If you say IL, I'll presume you are talking about the .NET platform. It's as simple as that. I want to maintain that distinction.
John Leidegren
Minor point - the size of IL instructions are variable, from 1 byte (e.g. Load integer constant 0), to 5 bytes (e.g. load large integer constant), and beyond - the 'switch' IL instruction is unbounded in how many bytes it can contain!
Chris
+7  A: 

The JIT is basically part of the CLR. The garbage collector is another. Quite where you put interop responsibilities etc is another matter, and one where I'm hugely underqualified to comment :)

Jon Skeet
+1 Why was this downvoted?
Andrew Hare
@Ted: Was this the sort of thing you were interested in? I didn't give a more detailed explanation (like Fredrik's) because I figured you already knew most of that sort of thing and were interested in the relationship between the CLR and the JIT.
Jon Skeet
If I've misinterpreted the question I'd be very happy to delete this answer.
Jon Skeet
No I never down voted it. I think all the answers are really good. I think I just should have asked the question differently. I was really interested in the relationship between the CLR and the JIT compiler and how it has changed with the addition of generics.
Ted Smith
@Ted: Sorry, I realised you hadn't downvoted it. I was just wondering whether it was actually a useful answer to you or not :) It's obviously a lot less detailed than the others.
Jon Skeet
More explanation please ..
Vadi
+14  A: 

As Jon Skeet says, JIT is part of the CLR. Basically this is what is happening under the hood:

  1. Your source code is compiled into a byte code know as the common intermediate language (CIL).
  2. Metadata from every class and every methods (and every other thing :O) is included in the PE header of the resulting executable (be it a dll or an exe).
  3. If you're producing an executable the PE Header also includes a conventional bootstrapper which is in charge of loading the CLR (Common language runtime) when you execute you executable.

Now, when you execute:

  1. The bootstraper initializes the CLR (mainly by loading the mscorlib assembly) and instructs it to execute your assembly.
  2. The CLR executes your main entry.
  3. Now, classes have a vector table which hold the addresses of the method functions, so that when you call MyMethod, this table is searched and then a corresponding call to the address is made. Upon start ALL entries for all tables have the address of the JIT compiler.
  4. When a call to one of such method is made, the JIT is invoked instead of the actual method and takes control. The JIT then compiles the CIL code into actual assembly code for the appropiate architecture.
  5. Once the code is compiled the JIT goes into the method vector table and replaces the address with the one of the compiled code, so that every subsequent call no longer invokes the JIT.
  6. Finally, the JIT handles the execution to the compiled code.
  7. If you call another method which haven't yet being compiled then go back to 4... and so on...
Jorge Córdoba
+1 more technical but less abstraction explanation than mine, read both!
thr
Dammit! Stop calling it bytecode, it's IL, an intermediate language representation. As the size of IL instructions are 16-bit words.
John Leidegren
I fear you are fighting a losing battle on this one John :) I think "Intermediate code" is reasonable general term where you want to include java's, 'net's, LLVM's etc. but dammit if bytecode isn't snappy...
ShuggyCoUk
If you talk bytecode, I would presume you where talking about Java bytecode. If you say IL, I'll presume you are talking about the .NET platform. It's as simple as that. I want to keep that distinction alive.
John Leidegren
As I said before, CIL is bytecode as I understand it... even the CLI spec refers to it as so... I don't understand why do you state it isn't
Jorge Córdoba
Bytecode is a generic term for an intermediate language based on byte values to describe operations and though it's true it usually refering to a single byte for the "code", it isn't completely needed nor is it exclusively used in java.
Jorge Córdoba
http://en.wikipedia.org/wiki/Bytecode
Jon Skeet
I always thought the JIT operated on a per-class basis, now you're suggesting that it's working on a per-method basis. Did they change this behaviour? Or am I mistaken?
Konrad Rudolph
+1 Very nice answer.
Andrew Hare
Konrad - it is an implementation *detail* whichever it uses. The JIT uses a sort of trampolining to achieve this on a per method basis last time I looked.
ShuggyCoUk
IIRC it's per method in the desktop CLR and per class in the Compact Framework.
Jon Skeet
+6  A: 

The JIT is one aspect of the CLR.

Specifically it is the part responsible for changing CIL/MSIL (hereafter called IL) produced by the original language's compiler (csc.exe for Microsoft c# for example) into machine code native to the current processor (and architecture that it exposes in the current process, for example 32/64bit). If the assembly in question was ngen'd then the the JIT process is completely unnecessary and the CLR will run this code just fine without it.

Before a method is used which has not yet been converted from the intermediate representation it is the JIT's responsibility to convert it.
Exactly when the JIT will kick in is implementation specific, and subject to change. However the CLR design mandates that the JIT happens before the relevant code executes, JVM's in contrast would be free to interpret the code for a while while a separate thread creates a machine code representation.
The 'normal' CLR uses a pre-JIT stub approach where by methods are JIT compiled only as they are used. This involves having the initial native method stub be an indirection to instruct the JIT to compile the method then modify the original call to skip past the initial stub. The current compact edition instead compiles all methods on a type when it is loaded.

To address the addition of Generics.

This was the last major change to the IL specification and JIT in terms of its semantics as opposed to its internal implementation details.

Several new IL instructions were added, and more meta data options were provided for instrumenting types and members. Constraints were added at the IL level as well.

When the JIT compiles a method which has generic arguments (either explicitly or implicitly through the containing class) it may set up different code paths (machine code instructions) for each type used. In practice the JIT uses a shared implementation for all reference types since variables for these will exhibit the same semantics and occupy the same space (IntPtr.Size).

Each value type will get specific code generated for it, dealing with the reduced / increased size of the variables on the stack/heap is a major reason for this. Also by emitting the constrained opcode before method calls many invocations on non reference types need not box the value to call the method (this optimization is used in non generic cases as well). This also allows the default<T> behaviour to be correctly handled and for comparisons to null to be stripped out as no ops (always false) when a non Nullable value type is used.

If an attempt is made at runtime to create an instance of a generic type via reflection then the type parameters will be validated by the runtime to ensure they pass any constraints. This does not directly affect the JIT unless this is used within the type system (unlikely though possible).

ShuggyCoUk
Oh wow, I guess your question was really more interested in the Generics aspect than I thought. I'll flesh the answer out to include aspects of the other ones to put it in better context
ShuggyCoUk