Module Initializer (a.k.a Module Constructor)

Module Initializer (a.k.a Module Constructor)

 

CLR v1.0/v1.1 supports Type Initializer. Here is a quote from ECMA-335: CLR Partition II Metadata and File Format:

 

1.1.1 Type initializer

A type (class, interface, or value type) can contain a special method called a type initializer, which is used to initialize the type itself. This method shall be static, take no parameters, return no value, be marked with rtspecialname and specialname, and be named .cctor.

Like instance constructors, type initializers can write into static fields of their type that are marked with the initonly attribute.

[Example: The following shows the definition of a type initializer:

.class public EngineeringData extends [mscorlib]System.Object
{
.field private static initonly float64[] coefficient
.method private specialname rtspecialname static void .cctor() cil managed
  {
.maxstack 1

  // allocate array of 4 Double
ldc.i4.4
newarr [mscorlib]System.Double
// point initonly field to new array
stsfld float64[] EngineeringData::coefficient
// code to initialize array elements goes here
ret
}
}

end example]

[Note: Type initializers are often simple methods that initialize the type’s static fields from stored constants or via simple computations. There are, however, no limitations on what code is permitted in a type initializer. end note]

1.1.1.1 Type initialization guarantees

The CLI shall provide the following guarantees regarding type initialization:

1. As to when type initializers are executed is specified in Partition I.

2. A type initializer shall be executed exactly once for any given type, unless explicitly called by user code.

3. No methods other than those called directly or indirectly from the type initializer are able to access members of a type before its initializer completes execution.

 

CLR v2.0 introduces Module Initializer. It is very similar to type initializer, with the difference that the module initializer is associated with a module, instead of a type. Since the module initializer is not associated with any type, it is a global function.

 

The following describes module initializer.

 

1.1.2 Module Initializer

Modules may contain special methods called module initializers to initialize the module itself.

All modules may have a module initializer. This method shall be static, a member of the module, take no parameters, return no value, be marked with rtspecialname and specialname, and be named .cctor.

There are no limitations on what code is permitted in a module initializer. Module initializers are permitted to run and call both managed and unmanaged code.

1.1.2.1 Module Initialization Guarantees

The CLI shall provide the following guarantees regarding module initialization:

1. The semantics of when, and what triggers execution of module initialization methods, is as follows:

   A. A module may have a module initializer method, or not.

   B. The module’s initializer method is executed at, or sometime before, first access to any types, methods, or data defined in the module

2. A module initializer shall run exactly once for any given module, unless explicitly called by user code

3. No method other than those called directly or indirectly from the module initializer will be able to access the types, methods, or data in a module before its initializer completes execution.

 

Since C# does not support global functions, C# does not support module initializer.

 

C++/CLI internally uses module initializer, as described in the MSDN VC++ chat script. (https://msdn.microsoft.com/chats/transcripts/vstudio/vstudio_091604.aspx)

 

The following is the ildasm output of the module initializer of msvcm80.dll.

 

.method assembly specialname rtspecialname static

        void .cctor() cil managed

{

  .custom instance void [mscorlib]System.Diagnostics.DebuggerStepThroughAttribute::.ctor() = ( 01 00 00 00 )

  // Code size 39 (0x27)

  .maxstack 2

  .locals ([0] valuetype '<CrtImplementationDetails>'.LanguageSupport languageSupport)

  IL_0000: ldloca.s languageSupport

  IL_0002: call valuetype '<CrtImplementationDetails>'.LanguageSupport* modopt([mscorlib]System.Runtime.CompilerServices.CallConvThiscall) '<CrtImplementationDetails>.LanguageSupport.{ctor}'(valuetype '<CrtImplementationDetails>'.LanguageSupport* modopt([mscorlib]System.Runtime.CompilerServices.IsConst) modopt([mscorlib]System.Runtime.CompilerServices.IsConst))

  IL_0007: pop

  .try

  {

    IL_0008: ldloca.s languageSupport

    IL_000a: call void modopt([mscorlib]System.Runtime.CompilerServices.CallConvThiscall) '<CrtImplementationDetails>.LanguageSupport.Initialize'(valuetype '<CrtImplementationDetails>'.LanguageSupport* modopt([mscorlib]System.Runtime.CompilerServices.IsConst) modopt([mscorlib]System.Runtime.CompilerServices.IsConst))

    IL_000f: leave.s IL_001f

  } // end .try

  fault

  {

    IL_0011: ldftn void modopt([mscorlib]System.Runtime.CompilerServices.CallConvThiscall) '<CrtImplementationDetails>.LanguageSupport.{dtor}'(valuetype '<CrtImplementationDetails>'.LanguageSupport* modopt([mscorlib]System.Runtime.CompilerServices.IsConst) modopt([mscorlib]System.Runtime.CompilerServices.IsConst))

    IL_0017: ldloca.s languageSupport

    IL_0019: call void ___CxxCallUnwindDtor(method void *(void*),

                                                   void*)

    IL_001e: endfinally

  } // end handler

  IL_001f: ldloca.s languageSupport

  IL_0021: call void modopt([mscorlib]System.Runtime.CompilerServices.CallConvThiscall) 'gcroot<System::String ^>.{dtor}'(valuetype 'gcroot<System::String ^>'* modopt([mscorlib]System.Runtime.CompilerServices.IsConst) modopt([mscorlib]System.Runtime.CompilerServices.IsConst))

  IL_0026: ret

} // end of method 'Global Functions'::.cctor