I am using Mono.Cecil.dll to decompile a VS 2015 app. During decompilation I noticed that there are 2 instructions (stloc.0 & ldloc.0) that are missing. This did not happen when I decompiled a VS 2013 application.
Is there a problem with the decompiler or Visual Studio 2015 complier has changed?
Update:
I have decompiled the code using ILDasm. Here is what can be found in 2015 and 2013 in Initialize component. The problem still appears:
2015
.method private hidebysig instance void InitializeComponent() cil managed
{
// Code size 125 (0x7d)
.maxstack 4
IL_0000: ldtoken VS2015DotNet4test.Form1
IL_0005: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_000a: newobj instance void [System]System.ComponentModel.ComponentResourceManager::.ctor(class [mscorlib]System.Type)
IL_000f: ldarg.0
IL_0010: newobj instance void [System.Windows.Forms]System.Windows.Forms.Label::.ctor()
IL_0015: stfld class [System.Windows.Forms]System.Windows.Forms.Label VS2015DotNet4test.Form1::label1
IL_001a: ldarg.0
IL_001b: call instance void [System.Windows.Forms]System.Windows.Forms.Control::SuspendLayout()
IL_0020: dup
IL_0021: ldarg.0
IL_0022: ldfld class [System.Windows.Forms]System.Windows.Forms.Label VS2015DotNet4test.Form1::label1
IL_0027: ldstr "label1"
IL_002c: callvirt instance void [System]System.ComponentModel.ComponentResourceManager::ApplyResources(object,
string)
IL_0031: ldarg.0
IL_0032: ldfld class [System.Windows.Forms]System.Windows.Forms.Label VS2015DotNet4test.Form1::label1
IL_0037: ldstr "label1"
IL_003c: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Control::set_Name(string)
IL_0041: ldarg.0
IL_0042: ldstr "$this"
IL_0047: callvirt instance void [System]System.ComponentModel.ComponentResourceManager::ApplyResources(object,
string)
IL_004c: ldarg.0
IL_004d: ldc.i4.1
IL_004e: call instance void [System.Windows.Forms]System.Windows.Forms.ContainerControl::set_AutoScaleMode(valuetype [System.Windows.Forms]System.Windows.Forms.AutoScaleMode)
IL_0053: ldarg.0
IL_0054: call instance class [System.Windows.Forms]System.Windows.Forms.Control/ControlCollection [System.Windows.Forms]System.Windows.Forms.Control::get_Controls()
IL_0059: ldarg.0
IL_005a: ldfld class [System.Windows.Forms]System.Windows.Forms.Label VS2015DotNet4test.Form1::label1
IL_005f: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Control/ControlCollection::Add(class [System.Windows.Forms]System.Windows.Forms.Control)
IL_0064: ldarg.0
IL_0065: ldstr "Form1"
IL_006a: call instance void [System.Windows.Forms]System.Windows.Forms.Control::set_Name(string)
IL_006f: ldarg.0
IL_0070: ldc.i4.0
IL_0071: call instance void [System.Windows.Forms]System.Windows.Forms.Control::ResumeLayout(bool)
IL_0076: ldarg.0
IL_0077: call instance void [System.Windows.Forms]System.Windows.Forms.Control::PerformLayout()
IL_007c: ret
} // end of method Form1::InitializeComponent
2013
.method private hidebysig instance void InitializeComponent() cil managed
{
// Code size 127 (0x7f)
.maxstack 3
.locals init (class [System]System.ComponentModel.ComponentResourceManager V_0)
IL_0000: ldtoken VS2013DotNet4test.Form1
IL_0005: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_000a: newobj instance void [System]System.ComponentModel.ComponentResourceManager::.ctor(class [mscorlib]System.Type)
IL_000f: stloc.0
IL_0010: ldarg.0
IL_0011: newobj instance void [System.Windows.Forms]System.Windows.Forms.Label::.ctor()
IL_0016: stfld class [System.Windows.Forms]System.Windows.Forms.Label VS2013DotNet4test.Form1::label1
IL_001b: ldarg.0
IL_001c: call instance void [System.Windows.Forms]System.Windows.Forms.Control::SuspendLayout()
IL_0021: ldloc.0
IL_0022: ldarg.0
IL_0023: ldfld class [System.Windows.Forms]System.Windows.Forms.Label VS2013DotNet4test.Form1::label1
IL_0028: ldstr "label1"
IL_002d: callvirt instance void [System]System.ComponentModel.ComponentResourceManager::ApplyResources(object,
string)
IL_0032: ldarg.0
IL_0033: ldfld class [System.Windows.Forms]System.Windows.Forms.Label VS2013DotNet4test.Form1::label1
IL_0038: ldstr "label1"
IL_003d: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Control::set_Name(string)
IL_0042: ldloc.0
IL_0043: ldarg.0
IL_0044: ldstr "$this"
IL_0049: callvirt instance void [System]System.ComponentModel.ComponentResourceManager::ApplyResources(object,
string)
IL_004e: ldarg.0
IL_004f: ldc.i4.1
IL_0050: call instance void [System.Windows.Forms]System.Windows.Forms.ContainerControl::set_AutoScaleMode(valuetype [System.Windows.Forms]System.Windows.Forms.AutoScaleMode)
IL_0055: ldarg.0
IL_0056: call instance class [System.Windows.Forms]System.Windows.Forms.Control/ControlCollection [System.Windows.Forms]System.Windows.Forms.Control::get_Controls()
IL_005b: ldarg.0
IL_005c: ldfld class [System.Windows.Forms]System.Windows.Forms.Label VS2013DotNet4test.Form1::label1
IL_0061: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Control/ControlCollection::Add(class [System.Windows.Forms]System.Windows.Forms.Control)
IL_0066: ldarg.0
IL_0067: ldstr "Form1"
IL_006c: call instance void [System.Windows.Forms]System.Windows.Forms.Control::set_Name(string)
IL_0071: ldarg.0
IL_0072: ldc.i4.0
IL_0073: call instance void [System.Windows.Forms]System.Windows.Forms.Control::ResumeLayout(bool)
IL_0078: ldarg.0
IL_0079: call instance void [System.Windows.Forms]System.Windows.Forms.Control::PerformLayout()
IL_007e: ret
} // end of method Form1::InitializeComponent
From what I see, this shouldn't make any observable difference - it's likely simply the result of Roslyn being a smarter compiler. The value is still on the virtual stack, ready to be used when needed. There's no need to store it in a (virtual) local.
The VS2015 compiler is completely new, built from scratch, so some differences are to be expected.
Note how the VS2013 version has .maxstack of 3, compared to 4 in VS2015 - this is the reason. VS2013's compiler simply saved one stack slot, while VS2015 saved one local slot (and a few instructions).
The value is used twice in the code, each of the compilations dealing with that in a different way: VS2013 saved the value in a local, to be retrieved when needed. VS2015 simply let the value stay on stack, and just before it's used for the first time, dupped it.
It might be interesting to have a look at the resulting x86 assembly from the JIT compilation - the two might even produce identical code, since most of the optimizations happen on the JIT level, not the C# compilation itself.
EDIT:
Okay, let's have a closer look at the virtual stack in the VS2015 code (I'm simplifying for clarity):
Form as a RuntimeHandle, pop it and push the Type (== typeof(Form))Type, push new ResourceManager (takes the Type argument)this, push new Label, pop both to store the label in the field this.label1ResourceManagerthis again, and use it to call Control.SuspendLayout (== this.SuspendLayout)dup the last value on stack (the ResourceManager instance)this, push this.label1 (popping this), push "label1"ResourceManager, ResourceManager, this.label1, "label1"ApplyResources (which takes three arguments, so pop the last three)After all this, we still have the ResourceManager on stack, without using any local.