1

I am trying to generate a dynamic assembly using Reflection & Emit in .NET. I am getting an error, "Common Language Runtime detected an invalid program." I created another program which has the functionality I want using hard-coded types. The functionality I am trying to write will ultimately use dynamic types, but I can use ILDasm to see the IL I need to generate. I am comparing the IL I am generating with the IL which the compiler generates. In the .locals init declaration of one method I see there is an extra item in the compiler-generated code,

compiler-generated:

.locals init ([0] class [System.Core]System.Linq.Expressions.ParameterExpression CS$0$0000,
           [1] class [System.Core]System.Linq.Expressions.ParameterExpression[] CS$0$0001)

mine:

.locals init (class [System.Core]System.Linq.Expressions.ParameterExpression V_0,  
       class [System.Core]System.Linq.Expressions.ParameterExpression[] V_1)

I don't understand the significance of the "[0]" and "[1]" in the compiler-generated code. Can anyone tell me what it means?

As a more general question, I can follow most ILDasm output without too much trouble. But every so often I run across a problematic expression. For instance, in this line from ILDasm

callvirt   instance class [EntityFramework]System.Data.Entity.ModelConfiguration.EntityTypeConfiguration`1<!!0> [EntityFramework]System.Data.Entity.DbModelBuilder::Entity<class DynamicEdmxTrial.HardFooAsset>()

the "!!0" probably refers to the generic type of the Entity<>, but I don't know for sure, and I wonder if there is a key to ILDasm output that would explain its more obscure output to me.

svick
  • 236,525
  • 50
  • 385
  • 514
jrv
  • 496
  • 4
  • 8
  • 2
    “I am getting an error, "Common Language Runtime detected an invalid program."” Have you tried running PEVerify on your assembly? – svick Sep 23 '13 at 19:37
  • Also, how exactly are you getting those `.locals`? Are both from ILDasm? – svick Sep 23 '13 at 19:39
  • The "invalid program" I am not so concerned about. I think I have found that. Both .local declarations were from ILDasm. It obviously found some difference between the C# code and my Reflection.Emit. – jrv Sep 23 '13 at 20:41
  • Considering that the ILDasm output contains variable names (which are not represented in IL), maybe the numbers are somehow related to debugging information? – svick Sep 24 '13 at 00:49
  • For those of you who seek closure on this sort of thing, the invalid program thing was unrelated to the "[0]". I was calling a base constructor that took a parameter without pushing one on the stack. I had changed my mind about which constructor I needed to call, but forgot to add the parameter. – jrv Sep 24 '13 at 18:08

1 Answers1

1

The specification is freely available here. It takes a little getting used to, but most details are easily found once you figure out the structure.

!! is listed in II.7.1 Types:

Type ::=       | Description                             | Clause
  ‘!’ Int32    | Generic parameter in a type definition, | §II.9.1
               | accessed by index from 0                |
| ‘!!’ Int32   | Generic parameter in a method           | §II.9.2
               | definition, accessed by index from 0    |
...

In other words, inside a method that C# would call f<T, U>(), !!0 would be T, and !!1 would be U.

However, the [0] is a good question. The spec does not seem to address it. The .locals directive is described in II.15.4.1.3 The .locals directive, which lists the syntax as

MethodBodyItem ::= ...
 | .locals [ init ] ‘(’ LocalsSignature ‘)’
LocalsSignature ::= Local [ ‘,’ Local ]*
Local ::= Type [ Id ]

There is nothing that seems to allow [0] there unless it is part of a Type, and Type does not allow anything starting with [ either. My guess is that this is an undocumented peculiarity specific to Microsoft's implementation, intended to help the human reader see that location 0 is local variable CS$0$0000, for when the generated instructions access local variables by index.

Experimenting with ILAsm shows that this is exactly what it means. Taking a simple C# program:

static class Program {
    static void Main() {
        int i = 0, j = 1;
    }
}

and compiling and then disassembling it (csc test.cs && ildasm /text test.exe >test.il) shows:

....
.locals init (int32 V_0,
         int32 V_1)
IL_0000:  nop
IL_0001:  ldc.i4.0
IL_0002:  stloc.0
IL_0003:  ldc.i4.1
IL_0004:  stloc.1
IL_0005:  ret
....

Modifying the .locals to

.locals init ([0] int32 V_0, [0] int32 V_1)

gives a useful warning message:

test.il(41) : warning : Local var slot 0 is in use

And indeed, declaring variables of different types, then reordering them using [2], [1], [0], assembling and immediately disassembling the result, shows that the variables got reordered.

  • I have the specification, but as you say it did not seem to explain the "[0]", so I didn't try the "!!". – jrv Sep 23 '13 at 18:56
  • Am I correct that the [0] describes what local slot the variable is in, which would be important for the ldloc & stloc instructions? As long as the ldloc & stloc instructions load and store to the correct variable slot, the [0] and [1] are nice but unnecessary? – jrv Sep 23 '13 at 19:53
  • 1
    @jrv Pretty much. If `[0]` is used to make it the slot explicit that it would already implicitly have, it doesn't add anything (other than clarity). –  Sep 23 '13 at 20:14
  • I went through the spec. In the full language spec (in the back) each param in the .locals is a "sigArg", which will consist of a "paramAttr type". One type of paramAttr is "'[' int32 ']'", which is exactly what I am seeing. I don't see any way in the LocalBuilder to add this parameter attribute, but it is nice to see that the language spec includes it. – jrv Sep 24 '13 at 17:19
  • @jrv Nice find. VI.C.3 starts off as "This grammar provides a number of ease-of-use features not provided in the grammar of Partition II, as well as supporting some features which are not portable across implementations and hence are not part of this standard." though. As for when you're using LocalBuilder, the slot will be based on the order in which you add the locals, so just add them in the order you want :) –  Sep 24 '13 at 17:43