A lot of people are having a hard time defining the
different pieces that make up .NET applications. The Common Language Runtime is
probably the most important part of the .NET framework. At the base level, it
is the infrastructure that executes applications, and allows them to interact
with the other parts of the Framework. It also provides important capabilities
in optimizing, securing, and providing many robust capabilities such as
application deployment and side-by-side execution. The CLR resides at the
bottom of the whole infrastructure and right above the operating system.
Where did the Kernel, User and GDI operating system modules
go? Nowhere, they are still there (for now), except that you, the programmer,
don't need to worry about them any more. The .NET framework encapsulates the
entire system in easy to use Object Hierarchy built in.
So calling an API function like SetBrush(...) at the GDI
level to set the Pen brush is now available as a function of an Object in a
specific namespace called System.Drawing, where PEN and BRUSH Objects exist
allowing the call to SetBrush on the BRUSH Object. Clean! VCL had that for
only 7 years now. The good news is that the Object mentality is now at the
bottom level of the system not at a wrapper level.
Lets take a look at a small piece of the CLR, the
startup". We will write 2 programs in C# and Delphi for .NET and see how
the CLR treats each one from the moment you try to run them till they actually
launch and run. You will be amazed on how much stuff goes on before the app
runs!
//C# code
using System.Windows.Forms;
namespace FalafelCode
{
public class HelloWorld
{
public static void Main()
{
MessageBox.Show("Falafel does .NET in C#!");
}
}
}
Save this snippet to a file called HelloWorld.cs
//The delphi equivalent
Program DHelloWorld;
uses
System.Windows.Forms;
begin
MessageBox.Show('Falafel does .NET in Delphi!');
end.
Save this snippet of code to a file called DHelloWorld.dpr
Compile the first program in C# above from the command line
by typing csc HelloWorld.cs.
Compile the second program in Delphi from the command line
by typing dccil DHelloWorld.dpr.
You can now run both programs from the command line by
typing the name of each EXE created on your drive. Once you run any of the
two, the CLR goes to work way before the application appears launched on the
screen.
First, the PE (Portable Executable) header is read to
identify that this executable is meant to run utilizing the .NET framework.
Use the Dumpbin or Tdump utilities from the MS SDK or
Borland tools to take a look at the PE headers of both executables created by
the C# and Delphi for .NET. Some very interesting things to look for:
* In the Optional Header Values section the "Number of
Directories" jump to 16 (10 Hex) a lot higher than normal Win32 apps.
* In the Raw Data #1 section, find the letters
"BSJB" the initials of the 4 architects that created the CLR, right
after that you will find the version of the framework that created the
executable then to the rest of the section is all the METADATA of the
application.
* Also notice the import section containing the name of the
magical DLL that will load the CLR and tells it where to start, as you can see
it is requesting the load of MSCOREE.DLL and will point to _CorExeMain. That
is the main reason MSCOREE.DLL exists.

Second, a manifest is read to
identify all external assemblies that need to be
loaded for executing this application (more about manifests in future
articles). An Assembly is a compiled and versioned collection of code and
metadata that forms an atomic functional unit. All Assemblies contain a
Manifest, which contains the Assembly name, version, and locale, has a list of
files that form the Assembly, what dependencies the Assembly has, and what
features are exported by the Assembly.
Third, the CLR reads the
metadata of the application to determine what it would take, memory wise, to
load the classes defined in the application (It does not allocate anything yet,
just running some algorithms). Metadata includes information such as a list of
types and resources visible outside the assembly. The manifest also includes
information about dependencies, such as the version of the assemblies used when
the assembly was built.
The CLR maintains an in-memory
representation similar to a v-table from the metadata. The metadata tells the
loader all the information it needs to know about a type and where to find it.
When the runtime loads a type, it replaces the address of each method in this
v-table like structure with a piece of stub code. When, and only when, the
method is called, the JIT compiler is invoked on the the JIT compiler is
invoked on the method, compiling the method's IL into native X86 assembly code
or whatever platform the CLR is running on. This code is cached in memory and
the CLR now changes the stub code to point to this native code. So, the next
time, the method is referenced, the calls to the method will not invoke the JIT
compiler and actually use the cached native code.
Folks, we are not done, remember
we don't even have a real executable yet to run on our Windows based machine.
We only have a manifest, a PE and some gibberish non-linked code called IL
(Intermediate Language) that contains the .NET instructions for the future
execution of the code. Now the CLR triggers it's magic weapon, the JITer (Just
in Time Assembly Linker) to start linking some of the IL compiled code in our
exe and convert it into native code based on the chip set and the OS that it is
running under.
Note: JITer links in the startup
code of the app but not all the code, the rest of the IL gets converted to
assembly on demand when the application starts using that code.
Ok, TIME OUT! I sense some
questions coming my way :) like this looks interpreted to me! Actually,
NOT. This is COMPILED code that is LINKED at runtime by the JITer.
With that said, remember that
having 15 or 20 languages out there running on .NET, they all COMPILE to .NET,
but they all share the same linker from the CLR.
Another question: Which HelloWorld
is faster (C# or Delphi)? Well, speed is not measured like before in the Win32
bit era. Now because the linker is the same, the execution time will be
extremely close between VB.NET, C#, Delphi for .NET etc.... it will slightly
vary based on the optimized IL that each compiler will produce, but no more 100
- 200 - 300 times faster benchmarks will be seen in the .NET world.
A third question: Why is this
faster than 32bit windows programming? I had the same question. Logic would
dictate that introducing a new layer between the OS and the programming
platform would slow down performance. Writing C++ or Delphi code in Win32 bit
world talking to Kernel, User or GDI takes x amount of time; introducing
mscorlib.dll (the main .NET assembly) in between these layers could only make
this operation slower (x + y). The truth of the matter is that Microsoft did
not fabricate the new .NET platform; it was built from the ground up based on a
better architecture, way fast linker technology and extremely efficient opcodes
that make the JITer perform in a highly efficient manner.
The JITer also has the advantage
of running on the machine where the code will be executed. This means that the
JITer can examine metrics like the processor speed and the amount of memory in
the machine, and use this to tune the native code. Native compilers do not have
this advantage, they must either create code for the general case or the
developer has to do a whole bunch of work to tune the compiler and produce
several versions.
Write to you later, till then,
have fun
About Falafel Software Inc:
Falafel Software is all about making the most of software development
technology in order to complete the project on time and on budget with best
possible user experience. Falafel Software offers a comprehensive suite of
software development solutions ranging from strategy to design to implementation
that businesses need in order to realize high returns on their investment.
Copyright ) 2003
Alain Tadros, Falafel Software Inc.
ALL RIGHTS RESERVED. NO PART OF THIS DOCUMENT CAN BE COPIED IN ANY FORM WITHOUT
THE EXPRESS, WRITTEN CONSENT OF THE AUTHOR.