December 2006 - Posts

Type Initialisers

Following my earlier post on instance constructors, I am going to cover the "Type Initialisers" this time.

Unlike instance constructors, which are created by the compiler if none is defined by the developer, types do not necessarily have an initialiser. Let's have a look at our first example. The following screenshot shows how the details of the ApplicationController class are displayed in Ildasm.

public class ApplicationController
{
    private static ApplicationController instance;
}

Type initialiser is mapped to the .cctor method (instance constructors are mapped to .ctor). Since the ApplicationController class does not have any type initialiser (inline static field initialiser or static constructor), .cctor is not generated. The compiler emits the .cctor only if there are any inline static field initialisers or if the developer has defined a static constructor for the class. 

public class ApplicationController
{
    private static ApplicationController instance = new ApplicationController
();
}

We have now added a static field initialiser to the ApplicationController class so Ildasm shows the .cctor statement, which represents the type initialiser.



And this is the generated IL code:

.method private hidebysig specialname rtspecialname static
        void .cctor() cil managed
{
    // Code size 11 (0xb)
    .maxstack 8
    IL_0000: newobj instance void StaticConstructorSample.ApplicationController::.ctor()
    IL_0005: stsfld class StaticConstructorSample.ApplicationController StaticConstructorSample.ApplicationController::'instance'
    IL_000a: ret
} // end of method ApplicationController::.cctor


As you may notice, static constructors are private (so that only CLR can call them) and you cannot specify any access modifier for the static constructor. Each type can have only one static constructor, which has to be parameter-less. It is good to know that both value types and reference types can have type initialisers.

Note: You can actually force the type initialiser for a specific type to be executed by calling the RunClassConstructor method on System.Runtime.CompilerServices.RuntimeHelpers.

If a type has both inline static field initialisers and a static constructor, the compiler will inject the inline static field initialisers (in the textual order in which they appear in the type declaration) at the beginning of the type initialiser. Inline static field initialisers can reference other static members (static properties, methods or fields). The compiler then emits the code for the static constructor as defined by the type author.

The following example shows how this works:

public class ApplicationController
{
    private static ApplicationController instance = new ApplicationController();
    private static Dictionary<string, object> cache = null;
   
    static ApplicationController()
    {
        Console.WriteLine("Type ApplicationController initialised.");
    }

------------------------
.method private hidebysig specialname rtspecialname static 
        void .cctor() cil managed
{
   
// Code size 30 (0x1e)
   
.maxstack 8
   
IL_0000: newobj instance void StaticConstructorSample.ApplicationController::.ctor()
   
IL_0005: stsfld class StaticConstructorSample.ApplicationController StaticConstructorSample.ApplicationController::'instance'
   
IL_000a: ldnull
   
IL_000b: stsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,object> StaticConstructorSample.ApplicationController::cache
   
IL_0010: nop
   
IL_0011: ldstr "Type ApplicationController initialised."
   
IL_0016: call void [mscorlib]System.Console::WriteLine(string)
   
IL_001b: nop
   
IL_001c: nop
    IL_001d: ret
} // end of method ApplicationController::.cctor

If a type does not have a static constructor, the compiler marks the type with "beforefieldinit". This allows the CLR to perform a lazy initialisation on that type. This means the CLR has the option of not running the type initialiser until the first access to any static field of the type. So accessing an instance member does not necessarily result in execution of the type initialiser (unless that instance member references a static field of that type).

Let's revisit our earlier example where we did not have a static constructor and see how the ApplicationController class is compiled to the IL code:

public class ApplicationController
{
   
private static ApplicationController instance = new ApplicationController();
}
------------------------
.class public auto ansi beforefieldinit StaticConstructorSample.ApplicationController
    extends [mscorlib]System.Object
{
} // end of class StaticConstructorSample.ApplicationController

However, if the type has a static constructor (even if it is empty), the compiler will not mark the class with "beforefieldinit". The impact is that the type initialiser will run just before the very first access to either instance or type members of the type. This means the CLR has to make sure the type initialiser is called before any access to the type in the current application domain.

public class ApplicationController
{
   
private static ApplicationController instance = new ApplicationController();

   
// This will prevent the compiler from emitting [beforefieldinit] for this class
   
static ApplicationController()
   {
   }
}
------------------------
.class public auto ansi StaticConstructorSample.ApplicationController
   
extends [mscorlib]System.Object
{
} // end of class StaticConstructorSample.ApplicationController

As you can see, "beforefieldinit" is missing from the IL code this time. There is currently no way for C# developers to specify whether "beforefieldinit" should be emitted for a specific type. The C# compiler just looks for the static constructor for the type and if it finds it, it does not mark the type as "beforefieldinit". Otherwise, it will mark the type as "beforefieldinit".

The Standard ECMA-335 [page 37] accurately defines the semantics for executing the type initialiser:


The semantics of when and what triggers execution of such type initialization methods, is as follows:
1. A type can have a type-initializer method, or not.
2. A type can be specified as having a relaxed semantic for its type-initializer method (for
convenience below, we call this relaxed semantic BeforeFieldInit).
3. If marked BeforeFieldInit then the type’s initializer method is executed at, or sometime before,
first access to any static field defined for that type.
4. If not marked BeforeFieldInit then that type’s initializer method is executed at (i.e., is triggered
by):
• first access to any static field of that type, or
• first invocation of any static method of that type or
• first invocation of any constructor for that type.
5. Execution of any type's initializer method will not trigger automatic execution of any initializer
methods defined by its base type, nor of any interfaces that the type implements


One may ask how the compiler knows whether the type initialiser is run in the current application domain already? Well, it doesn't because it can't. This is the responsibility of the JIT compiler to emit a call to the type initialiser if it is not executed in the current application domain. As you can imagine, this can be costly in terms of performance so if static field initialisers satisfy your requirements, do not create a static constructor for your type.

Since static constructors are visible to all threads in the current application domain, it is possible that code in more than one thread force the type to be initialised but CLR has to make sure the type initialiser is run only once. In order to do this, the calling thread acquires a synchronisation lock on that type and only the first call to the type constructor actually results in execution of the constructor. All other threads will notice that the constructor has already been executed. The way the CLR deals with concurrent access to the type initialiser provides an easy and safe way of implementing the Singleton pattern.

Posted by Mehran Nikoo | with no comments
Filed under: ,

Download Visual Studio 2005 SP1

The long-awaited SP1 for Visual Studio 2005 was released yesterday [Download].

This service pack is not just about bug fixes. It has more than 70 improvements/new features, some of which are listed below:

  • New processor support (e.g., Core Duo) for code generation and profiling
  • Performance and scale improvements in Team Foundation Server
  • Team Foundation Server integration with Excel 2007 and Project 2007
  • Tool support for occasionally connected devices and SQL Server Compact Edition
  • Additional support for project file based Web applications
  • Windows Embedded 6.0 platform and tools support

As expected all of the existing hotfixes for VS2005 were removed as part of the setup process as the service pack includes all those fixes.

The setup process took 27 minutes on Windows XP Pro running on a P4-2.8GHz machine with 2GB of memory. The CPU utilisation was relatively high (avg: 70%) and the memory usage was below 250MB. When completed, it asked me to restart the machine.

Early findings: It seems the IDE is more responsive in general and the forms are rendered much faster in the WinForms designer.

Leaving for lunch? It is a good idea to kick off the setup process just before you leave for lunch as it takes around half an hour. If you are planning to do so, then wait for 3-4 minutes so that you can confirm the installation and agree to the EULA!

Posted by Mehran Nikoo | with no comments
Filed under: