发表于2009年1月的文章

Swig

发表于2009年1月19日

http://www.swig.org/Doc1.3/CSharp.html#CSharp

http://swig.svn.sourceforge.net/viewvc/swig/branches/gsoc2008-jezabek/Doc/Manual/COM.html

http://swig.svn.sourceforge.net/viewvc/swig/branches/gsoc2008-bhy/Doc/Manual/Python.html#Python_python3support

什么是PrivateImplementationDetails

发表于2009年1月18日

解析一个.NET程序集时发现了一段<PrivateImplementationDetails>{A_GUID}模样的代码,这是.NET编译器对某些指令做得优化,经分析会在如下情况下产生。

优化数组创建

var int1 = new[] { 1, 2, 3, 4, 5, 6 };

在解析上面的代码时,发现其产生了一些由编译器控制的IL代码

IL_0008:  ldc.i4.6
IL_0009:  newarr     [mscorlib]System.Int32
IL_000e:  dup
IL_000f:  ldtoken    field valuetype '<PrivateImplementationDetails>{393AE015-A550-4A61-9BFF-186AFB6A4D12}'/'__StaticArrayInitTypeSize=24' '<PrivateImplementationDetails>{393AE015-A550-4A61-9BFF-186AFB6A4D12}'::'$$method0x60000f8-1'
IL_0014:  call       void [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
IL_0019:  stloc.0

如果没有使用初始化器

var int1 = new int[6];

生成的IL代码如下

IL_0008:  ldc.i4.6
IL_0009:  newarr     [mscorlib]System.Int32
IL_000e:  stloc.0

上面是创建值类型数组的情况,如果是引用类型的数组呢?

var obj1 = new object[3];
var obj2 = new[] {new object(), "test", 1};

生成的IL代码如下

IL_0001:  ldc.i4.3
IL_0002:  newarr     [mscorlib]System.Object
IL_0007:  stloc.0
IL_0008:  ldc.i4.3
IL_0009:  newarr     [mscorlib]System.Object
IL_000e:  stloc.2
IL_000f:  ldloc.2
IL_0010:  ldc.i4.0
IL_0011:  newobj     instance void [mscorlib]System.Object::.ctor()
IL_0016:  stelem.ref
IL_0017:  ldloc.2
IL_0018:  ldc.i4.1
IL_0019:  ldstr      "test"
IL_001e:  stelem.ref
IL_001f:  ldloc.2
IL_0020:  ldc.i4.2
IL_0021:  ldc.i4.1
IL_0022:  box        [mscorlib]System.Int32
IL_0027:  stelem.ref
IL_0028:  ldloc.2
IL_0029:  stloc.1

从下图可以看到,在产生的.NET程序集中有一个<PrivateImplementationDetails>开头的Module

PrivateImplementationDetails

<PrivateImplementationDetails>{0BAF451E-34D3-4B3B-8567-B578D84A6965}是这个编译器产生的Module的名字,{0BAF451E-34D3-4B3B-8567-B578D84A6965}是这个dll的MVID(Module Version Identifier)。

那么为什么要通过调用System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray这个静态方法来初始化数组呢?通过这位同学试验可以得出结论这是为提高效率而做出的编译时优化。

那什么情况下.NET编译器会产生PrivateImplementationDetails这种机制呢,我还没找到一个完整的列表。除数组外我还发现大的switch表也会产生PrivateImplementationDetails,并简单的试出了启用这种机制的case数量的临界值。

优化case比较多的switch

在代码中加入两个方法SwitchWith6Cases()和SwitchWith7Cases()

public void SwitchWith6Cases()
{
    var param = "a";
    switch (param)
    {
        case "a": break;
        case "b": break;
        case "c": break;
        case "d": break;
        case "e": break;
        case "f": break;
    }
}
 
public void SwitchWith7Cases()
{
    var param = "a";
    switch (param)
    {
        case "a": break;
        case "b": break;
        case "c": break;
        case "d": break;
        case "e": break;
        case "f": break;
        case "g": break;
    }
}

前者生成的代码如下,基本符合C#代码的逻辑

.method public hidebysig instance void  SwitchWith6Cases() cil managed
{
  // Code size       105 (0x69)
  .maxstack  2
  .locals init ([0] string param,
           [1] string CS$4$0000)
  IL_0000:  nop
  IL_0001:  ldstr      "a"
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  stloc.1
  IL_0009:  ldloc.1
  IL_000a:  brfalse.s  IL_0068
  IL_000c:  ldloc.1
  IL_000d:  ldstr      "a"
  IL_0012:  call       bool [mscorlib]System.String::op_Equality(string, string)
  IL_0017:  brtrue.s   IL_005c
  IL_0019:  ldloc.1
  IL_001a:  ldstr      "b"
  IL_001f:  call       bool [mscorlib]System.String::op_Equality(string, string)
  IL_0024:  brtrue.s   IL_005e
  IL_0026:  ldloc.1
  IL_0027:  ldstr      "c"
  IL_002c:  call       bool [mscorlib]System.String::op_Equality(string, string)
  IL_0031:  brtrue.s   IL_0060
  IL_0033:  ldloc.1
  IL_0034:  ldstr      "d"
  IL_0039:  call       bool [mscorlib]System.String::op_Equality(string, string)
  IL_003e:  brtrue.s   IL_0062
  IL_0040:  ldloc.1
  IL_0041:  ldstr      "e"
  IL_0046:  call       bool [mscorlib]System.String::op_Equality(string, string)
  IL_004b:  brtrue.s   IL_0064
  IL_004d:  ldloc.1
  IL_004e:  ldstr      "f"
  IL_0053:  call       bool [mscorlib]System.String::op_Equality(string, string)
  IL_0058:  brtrue.s   IL_0066
  IL_005a:  br.s       IL_0068
  IL_005c:  br.s       IL_0068
  IL_005e:  br.s       IL_0068
  IL_0060:  br.s       IL_0068
  IL_0062:  br.s       IL_0068
  IL_0064:  br.s       IL_0068
  IL_0066:  br.s       IL_0068
  IL_0068:  ret
} // end of method SwitchSample::SwitchWith6Cases

而当switch有超过6个case的时候,所生成的IL代码如下。

.method public hidebysig instance void  SwitchWith7Cases() cil managed
{
  // Code size       189 (0xbd)
  .maxstack  4
  .locals init ([0] string param,
           [1] string CS$4$0000,
           [2] int32 CS$0$0001)
  IL_0000:  nop
  IL_0001:  ldstr      "a"
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  stloc.1
  IL_0009:  ldloc.1
  IL_000a:  brfalse    IL_00bc
  IL_000f:  volatile.
  IL_0011:  ldsfld     class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{E6F6F304-0E96-4AD2-AF7A-7D08372A387B}'::'$$method0x60000fd-1'
  IL_0016:  brtrue.s   IL_0079
  IL_0018:  ldc.i4.7
  IL_0019:  newobj     instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::.ctor(int32)
  IL_001e:  dup
  IL_001f:  ldstr      "a"
  IL_0024:  ldc.i4.0
  IL_0025:  call       instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::Add(!0, !1)
  IL_002a:  dup
  IL_002b:  ldstr      "b"
  IL_0030:  ldc.i4.1
  IL_0031:  call       instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::Add(!0, !1)
  IL_0036:  dup
  IL_0037:  ldstr      "c"
  IL_003c:  ldc.i4.2
  IL_003d:  call       instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::Add(!0, !1)
  IL_0042:  dup
  IL_0043:  ldstr      "d"
  IL_0048:  ldc.i4.3
  IL_0049:  call       instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::Add(!0, !1)
  IL_004e:  dup
  IL_004f:  ldstr      "e"
  IL_0054:  ldc.i4.4
  IL_0055:  call       instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::Add(!0, !1)
  IL_005a:  dup
  IL_005b:  ldstr      "f"
  IL_0060:  ldc.i4.5
  IL_0061:  call       instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::Add(!0, !1)
  IL_0066:  dup
  IL_0067:  ldstr      "g"
  IL_006c:  ldc.i4.6
  IL_006d:  call       instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::Add(!0, !1)
  IL_0072:  volatile.
  IL_0074:  stsfld     class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{E6F6F304-0E96-4AD2-AF7A-7D08372A387B}'::'$$method0x60000fd-1'
  IL_0079:  volatile.
  IL_007b:  ldsfld     class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>{E6F6F304-0E96-4AD2-AF7A-7D08372A387B}'::'$$method0x60000fd-1'
  IL_0080:  ldloc.1
  IL_0081:  ldloca.s   CS$0$0001
  IL_0083:  call       instance bool class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::TryGetValue(!0,
                                                                                                                        !1&)
  IL_0088:  brfalse.s  IL_00bc
  IL_008a:  ldloc.2
  IL_008b:  switch     ( 
                        IL_00ae,
                        IL_00b0,
                        IL_00b2,
                        IL_00b4,
                        IL_00b6,
                        IL_00b8,
                        IL_00ba)
  IL_00ac:  br.s       IL_00bc
  IL_00ae:  br.s       IL_00bc
  IL_00b0:  br.s       IL_00bc
  IL_00b2:  br.s       IL_00bc
  IL_00b4:  br.s       IL_00bc
  IL_00b6:  br.s       IL_00bc
  IL_00b8:  br.s       IL_00bc
  IL_00ba:  br.s       IL_00bc
  IL_00bc:  ret
} // end of method SwitchSample::SwitchWith7Cases

这时候在<PrivateImplementationDetails>*模块中会有如下的一个叫做$$method0x60000fd-1的静态字段,辅助switch的case匹配。

.field static assembly class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '$$method0x60000fd-1'

通过Dictionary<string,int32>::TryGetValue方法去查找匹配的case。O(1)的效率在case多的情况下比线性O(n)的查找快的多。

A Conversation with Anders Hejlsberg, by Bill Venners with Bruce Eckel(August 4, 2003)

发表于2009年1月5日


A Conversation with Anders Hejlsberg,
by Bill Venners with Bruce Eckel
August 4, 2003

These conversation includes 8 parts: