views:

192

answers:

2

I'm trying to understand a method using the disassembly feature of Reflector. As anyone that's used this tool will know, certain code is displayed with C# labels that were (presumably) not used in the original source.

In the 110 line method I'm looking at there are 11 label statements. Random snippet examples:

Label_0076:
    if (enumerator.MoveNext())
    {
     goto Label_008F;
    }
    if (!base.IsValid)
    {
     return;
    }
    goto Label_0219;
Label_0087:
    num = 0;
    goto Label_01CB;
Label_01CB:
    if (num < entityArray.Length)
    {
     goto Label_0194;
    }
    goto Label_01AE;
Label_01F3:
    num++;
    goto Label_01CB;

What sort of code makes Reflector display these labels everywhere and why can't it disassemble them?

Is there a good technique for deciphering them?

+2  A: 

You're looking at code generated by the compiler. The compiler doesn't respect you. No, really. It doesn't respect me or anybody else, either. It looks at our code, scoffs at us, and rewrites it to run as efficiently as possible.

Nested if statements, recursion, "yield"s, case statements, and other code shortcuts will result in weird looking code. And if you're using lambdas with lots of enclosures, well, don't expect it to be pretty.

Any where, any chance the compiler can rewrite your code to make it run faster it will. So there isn't any one "sort of code" that will cause this. Reflector does its best to disassemble, but it can't divine the author's original code from its rewritten version. It does its best (which sometimes is even incorrect!) to translate IL into some form of acceptable code.

If you're having a hard time deciphering it, you could manually edit the code to inline goto's that only get called once and refactor goto's that are called more than once into method calls. Another alternative is to disassemble into another language. The code that translates IL into higher level languages isn't the same. The C++/CLI decompiler may do a better job for you and still be similar enough (find/replace -> with .) to be understandable.

There really isn't a silver bullet for this; at least not until somebody writes a better disassembler plugin.

Will
+6  A: 

Actually, the C# compiler doesn't do much of any optimization - it leaves that to the JIT compiler (or ngen). As such, the IL it generates is pretty consistent and predictable, which is why tools like Reflector are able to decompile IL so effectively. One situation where the compiler does transform your code is in an iterator method. The method you're looking at probably contained something along the lines of:

foreach(var x in something)
  if(x.IsValid)
    yield return x;

Since the iterator transformation can be pretty complex, Reflector can't really deal with it. To get familiar with what to look for, write your own iterator methods and run them through Reflector to see what kind of IL gets generated based on your C# code. Then you'll know what to look for.

Steve Dennis