提交 b0961273 编写于 作者: V VSadov

Merge pull request #5560 from VSadov/structCtor

Fixes incorrect codegen where locals could be optimized across implicit branches
......@@ -135,6 +135,8 @@ private static void RemoveIntersectingLocals(Dictionary<LocalSymbol, LocalDefUse
}
}
var dummyCnt = defs.Count;
//TODO: perf. This can be simplified to not use a query.
// order definitions by increasing size
......@@ -177,16 +179,30 @@ private static void RemoveIntersectingLocals(Dictionary<LocalSymbol, LocalDefUse
else
{
intersects = false;
for (int i = 0; i < cnt; i++)
for (int i = 0; i < dummyCnt; i++)
{
var def = defs[i];
if (newDef.ConflictsWith(def))
if (newDef.ConflictsWithDummy(def))
{
intersects = true;
break;
}
}
if (!intersects)
{
for (int i = dummyCnt; i < cnt; i++)
{
var def = defs[i];
if (newDef.ConflictsWith(def))
{
intersects = true;
break;
}
}
}
}
if (intersects)
......@@ -271,36 +287,40 @@ public override string ToString()
/// when current and other use spans are regular spans we can have only 2 conflict cases:
/// [1, 3) conflicts with [0, 2)
/// [1, 3) conflicts with [2, 4)
/// specifically:
/// [1, 3) does not conflict with [0, 1)
///
/// NOTE: with regular spans, it is not possible
/// to have start1 == start2 or end1 == end
/// since at the same node we can access only one real local.
/// NOTE: with regular spans, it is not possible for two spans to share an edge point
/// unless they belong to the same local. (because we cannot aceess two real locals at the same time)
///
/// However at the same node we can access one or more dummy locals.
/// So we can have start1 == start2 and end1 == end2 scenarios, but only if
/// other span is a span of a dummy.
///
/// In such cases we consider
/// start2 == span1.start ==> start2 IS included in span1
/// end2 == span1.end ==> end2 IS NOT included in span1
/// specifically:
/// [1, 3) does not conflict with [0, 1) since such spans would need to belong to the same local
/// </summary>
public bool ConflictsWith(LocalDefUseSpan other)
{
var containsStart = other.ContainsStart(this.start);
var containsEnd = other.ContainsEnd(this.end);
return containsStart ^ containsEnd;
return Contains(other.start) ^ Contains(other.end);
}
private bool Contains(int val)
{
return this.start < val && this.end > val;
}
private bool ContainsStart(int otherStart)
/// <summary>
/// Dummy locals represent implicit control flow
/// It is not allowed for a regular local span to cross into or
/// be immediately adjacent to a dummy span.
///
/// specifically:
/// [1, 3) does conflict with [0, 1) since that would imply a value flowing into or out of a span surrounded by a branch/label
///
/// </summary>
public bool ConflictsWithDummy(LocalDefUseSpan dummy)
{
return this.start <= otherStart && this.end > otherStart;
return Includes(dummy.start) ^ Includes(dummy.end);
}
private bool ContainsEnd(int otherEnd)
private bool Includes(int val)
{
return this.start < otherEnd && this.end > otherEnd;
return this.start <= val && this.end >= val;
}
}
......@@ -358,7 +378,7 @@ internal class StackOptimizerPass1 : BoundTreeRewriter
// this is the top of eval stack
DeclareLocal(empty, 0);
RecordVarWrite(empty);
RecordDummyWrite(empty);
}
public static BoundNode Analyze(
......@@ -808,16 +828,23 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
// Such call will push the receiver ref before the arguments
// so we need to ensure that arguments cannot use stack temps
BoundExpression right = node.Right;
object rhsCookie = null;
if (right.Kind == BoundKind.ObjectCreationExpression &&
bool mayPushReceiver = (right.Kind == BoundKind.ObjectCreationExpression &&
right.Type.IsVerifierValue() &&
((BoundObjectCreationExpression)right).Constructor.ParameterCount != 0)
((BoundObjectCreationExpression)right).Constructor.ParameterCount != 0);
if (mayPushReceiver)
{
rhsCookie = this.GetStackStateCookie();
// push unknown value just to prevent access to stack locals.
PushEvalStack(null, ExprContext.Address);
}
right = VisitExpression(node.Right, rhsContext);
if (mayPushReceiver)
{
PopEvalStack();
}
// if assigning to a local, now it is the time to record the Write
if (assignmentLocal != null)
{
......@@ -847,13 +874,6 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
assignmentLocal = null;
}
if (rhsCookie != null)
{
// we currently have the rhs on stack, adjust for that.
PopEvalStack();
this.EnsureStackState(rhsCookie);
}
return node.Update(left, right, node.RefKind, node.Type);
}
......@@ -1422,7 +1442,7 @@ private object GetStackStateCookie()
var dummy = new DummyLocal();
_dummyVariables.Add(dummy, dummy);
_locals.Add(dummy, new LocalDefUseInfo(StackDepth()));
RecordVarWrite(dummy);
RecordDummyWrite(dummy);
return dummy;
}
......@@ -1446,7 +1466,7 @@ private void RecordBranch(LabelSymbol label)
dummy = new DummyLocal();
_dummyVariables.Add(label, dummy);
_locals.Add(dummy, new LocalDefUseInfo(StackDepth()));
RecordVarWrite(dummy);
RecordDummyWrite(dummy);
}
}
......@@ -1543,8 +1563,23 @@ private bool EvalStackHasLocal(LocalSymbol local)
((BoundLocal)top.Item1).LocalSymbol == local;
}
private void RecordDummyWrite(LocalSymbol local)
{
Debug.Assert(local.SynthesizedKind == SynthesizedLocalKind.OptimizerTemp);
var locInfo = _locals[local];
// dummy must be accessed on same stack.
Debug.Assert(local == empty || locInfo.stackAtDeclaration == StackDepth());
var locDef = new LocalDefUseSpan(_counter);
locInfo.LocalDefs.Add(locDef);
}
private void RecordVarWrite(LocalSymbol local)
{
Debug.Assert(local.SynthesizedKind != SynthesizedLocalKind.OptimizerTemp);
if (!CanScheduleToStack(local))
{
return;
......@@ -1556,23 +1591,15 @@ private void RecordVarWrite(LocalSymbol local)
return;
}
// if accessing real val, check stack
if (local.SynthesizedKind != SynthesizedLocalKind.OptimizerTemp)
{
// -1 because real assignment "consumes, assigns, and then pushes back" the value.
var evalStack = StackDepth() - 1;
// check stack
// -1 because real assignment "consumes, assigns, and then pushes back" the value.
var evalStack = StackDepth() - 1;
if (locInfo.stackAtDeclaration != evalStack)
{
//writing at different eval stack.
locInfo.ShouldNotSchedule();
return;
}
}
else
if (locInfo.stackAtDeclaration != evalStack)
{
// dummy must be accessed on same stack.
Debug.Assert(local == empty || locInfo.stackAtDeclaration == StackDepth());
//writing at different eval stack.
locInfo.ShouldNotSchedule();
return;
}
var locDef = new LocalDefUseSpan(_counter);
......
......@@ -14434,5 +14434,155 @@ .maxstack 2
IL_000b: ret
}");
}
[Fact]
public void InplaceCtorUsesLocal()
{
string source = @"
class Program
{
private static S1[] arr = new S1[1];
struct S1
{
public int a, b;
public S1(int a, int b)
{
this.a = a;
this.b = b;
}
}
static void Main(string[] args)
{
var arg = System.Math.Max(1, 2);
var val = new S1(arg, arg);
arr[0] = val;
System.Console.WriteLine(arr[0].a);
}
}
";
var compilation = CompileAndVerify(source, expectedOutput: "2");
compilation.VerifyIL("Program.Main",
@"
{
// Code size 51 (0x33)
.maxstack 3
.locals init (int V_0, //arg
Program.S1 V_1) //val
IL_0000: ldc.i4.1
IL_0001: ldc.i4.2
IL_0002: call ""int System.Math.Max(int, int)""
IL_0007: stloc.0
IL_0008: ldloca.s V_1
IL_000a: ldloc.0
IL_000b: ldloc.0
IL_000c: call ""Program.S1..ctor(int, int)""
IL_0011: ldsfld ""Program.S1[] Program.arr""
IL_0016: ldc.i4.0
IL_0017: ldloc.1
IL_0018: stelem ""Program.S1""
IL_001d: ldsfld ""Program.S1[] Program.arr""
IL_0022: ldc.i4.0
IL_0023: ldelema ""Program.S1""
IL_0028: ldfld ""int Program.S1.a""
IL_002d: call ""void System.Console.WriteLine(int)""
IL_0032: ret
}
");
}
[Fact]
public void TernaryConsequenceUsesLocal()
{
string source = @"
class Program
{
static bool foo()
{
return true;
}
static void Main(string[] args)
{
bool arg;
var val = (arg = foo())? arg & arg : false;
System.Console.WriteLine(val);
}
}
";
var compilation = CompileAndVerify(source, expectedOutput: "True");
compilation.VerifyIL("Program.Main",
@"
{
// Code size 21 (0x15)
.maxstack 2
.locals init (bool V_0) //arg
IL_0000: call ""bool Program.foo()""
IL_0005: dup
IL_0006: stloc.0
IL_0007: brtrue.s IL_000c
IL_0009: ldc.i4.0
IL_000a: br.s IL_000f
IL_000c: ldloc.0
IL_000d: ldloc.0
IL_000e: and
IL_000f: call ""void System.Console.WriteLine(bool)""
IL_0014: ret
}
");
}
[Fact]
public void CoalesceUsesLocal()
{
string source = @"
class Program
{
static string foo()
{
return ""hi"";
}
static void Main(string[] args)
{
string str;
var val = (str = foo()) ?? str + ""aa"";
System.Console.WriteLine(val);
}
}
";
var compilation = CompileAndVerify(source, expectedOutput: "hi");
compilation.VerifyIL("Program.Main",
@"
{
// Code size 28 (0x1c)
.maxstack 2
.locals init (string V_0) //str
IL_0000: call ""string Program.foo()""
IL_0005: dup
IL_0006: stloc.0
IL_0007: dup
IL_0008: brtrue.s IL_0016
IL_000a: pop
IL_000b: ldloc.0
IL_000c: ldstr ""aa""
IL_0011: call ""string string.Concat(string, string)""
IL_0016: call ""void System.Console.WriteLine(string)""
IL_001b: ret
}
");
}
}
}
......@@ -240,75 +240,72 @@ static void Main()
// in different branches
verifier.VerifyIL("Program.Main", @"
{
// Code size 136 (0x88)
.maxstack 2
.locals init (bool V_0, //testFlag
D<Base> V_1, //baseDelegate
D<Derived> V_2, //derivedDelegate
System.Collections.Generic.IEnumerable<Base> V_3, //baseSequence
System.Collections.Generic.List<Derived> V_4, //derivedList
D<Base> V_5)
// Code size 133 (0x85)
.maxstack 3
.locals init (D<Base> V_0, //baseDelegate
D<Derived> V_1, //derivedDelegate
System.Collections.Generic.IEnumerable<Base> V_2, //baseSequence
System.Collections.Generic.List<Derived> V_3, //derivedList
D<Base> V_4)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldsfld ""D<Base> Program.<>c.<>9__0_0""
IL_0007: dup
IL_0008: brtrue.s IL_0021
IL_000a: pop
IL_000b: ldsfld ""Program.<>c Program.<>c.<>9""
IL_0010: ldftn ""void Program.<>c.<Main>b__0_0()""
IL_0016: newobj ""D<Base>..ctor(object, System.IntPtr)""
IL_001b: dup
IL_001c: stsfld ""D<Base> Program.<>c.<>9__0_0""
IL_0021: stloc.1
IL_0022: ldsfld ""D<Derived> Program.<>c.<>9__0_1""
IL_0027: dup
IL_0028: brtrue.s IL_0041
IL_002a: pop
IL_002b: ldsfld ""Program.<>c Program.<>c.<>9""
IL_0030: ldftn ""void Program.<>c.<Main>b__0_1()""
IL_0036: newobj ""D<Derived>..ctor(object, System.IntPtr)""
IL_003b: dup
IL_003c: stsfld ""D<Derived> Program.<>c.<>9__0_1""
IL_0041: stloc.2
IL_0042: ldloc.0
IL_0043: brtrue.s IL_004c
IL_0045: ldloc.2
IL_0046: stloc.s V_5
IL_0048: ldloc.s V_5
IL_004a: br.s IL_004d
IL_004c: ldloc.1
IL_004d: callvirt ""void D<Base>.Invoke()""
IL_0052: ldloc.0
IL_0053: brtrue.s IL_0058
IL_0055: ldloc.1
IL_0056: br.s IL_005d
IL_0058: ldloc.2
IL_0059: stloc.s V_5
IL_005b: ldloc.s V_5
IL_005d: callvirt ""void D<Base>.Invoke()""
IL_0062: ldloc.1
IL_0063: dup
IL_0064: brtrue.s IL_006c
IL_0066: pop
IL_0067: ldloc.2
IL_0068: stloc.s V_5
IL_006a: ldloc.s V_5
IL_006c: callvirt ""void D<Base>.Invoke()""
IL_0071: ldloc.2
IL_0072: stloc.s V_5
IL_0074: ldloc.s V_5
IL_0076: dup
IL_0077: brtrue.s IL_007b
IL_0079: pop
IL_007a: ldloc.1
IL_007b: callvirt ""void D<Base>.Invoke()""
IL_0080: ldnull
IL_0081: stloc.3
IL_0082: ldnull
IL_0083: stloc.s V_4
IL_0085: ldloc.0
IL_0086: pop
IL_0087: ret
IL_0001: ldsfld ""D<Base> Program.<>c.<>9__0_0""
IL_0006: dup
IL_0007: brtrue.s IL_0020
IL_0009: pop
IL_000a: ldsfld ""Program.<>c Program.<>c.<>9""
IL_000f: ldftn ""void Program.<>c.<Main>b__0_0()""
IL_0015: newobj ""D<Base>..ctor(object, System.IntPtr)""
IL_001a: dup
IL_001b: stsfld ""D<Base> Program.<>c.<>9__0_0""
IL_0020: stloc.0
IL_0021: ldsfld ""D<Derived> Program.<>c.<>9__0_1""
IL_0026: dup
IL_0027: brtrue.s IL_0040
IL_0029: pop
IL_002a: ldsfld ""Program.<>c Program.<>c.<>9""
IL_002f: ldftn ""void Program.<>c.<Main>b__0_1()""
IL_0035: newobj ""D<Derived>..ctor(object, System.IntPtr)""
IL_003a: dup
IL_003b: stsfld ""D<Derived> Program.<>c.<>9__0_1""
IL_0040: stloc.1
IL_0041: dup
IL_0042: brtrue.s IL_004b
IL_0044: ldloc.1
IL_0045: stloc.s V_4
IL_0047: ldloc.s V_4
IL_0049: br.s IL_004c
IL_004b: ldloc.0
IL_004c: callvirt ""void D<Base>.Invoke()""
IL_0051: dup
IL_0052: brtrue.s IL_0057
IL_0054: ldloc.0
IL_0055: br.s IL_005c
IL_0057: ldloc.1
IL_0058: stloc.s V_4
IL_005a: ldloc.s V_4
IL_005c: callvirt ""void D<Base>.Invoke()""
IL_0061: ldloc.0
IL_0062: dup
IL_0063: brtrue.s IL_006b
IL_0065: pop
IL_0066: ldloc.1
IL_0067: stloc.s V_4
IL_0069: ldloc.s V_4
IL_006b: callvirt ""void D<Base>.Invoke()""
IL_0070: ldloc.1
IL_0071: stloc.s V_4
IL_0073: ldloc.s V_4
IL_0075: dup
IL_0076: brtrue.s IL_007a
IL_0078: pop
IL_0079: ldloc.0
IL_007a: callvirt ""void D<Base>.Invoke()""
IL_007f: ldnull
IL_0080: stloc.2
IL_0081: ldnull
IL_0082: stloc.3
IL_0083: pop
IL_0084: ret
}");
}
......@@ -352,67 +349,64 @@ static void Main()
var verifier = CompileAndVerify(source, expectedOutput: @"BDBD");
verifier.VerifyIL("Program.Main", @"
{
// Code size 121 (0x79)
.maxstack 2
.locals init (bool V_0, //testFlag
D<Base> V_1, //baseDelegate
D<Derived> V_2, //derivedDelegate
D<Derived> V_3)
// Code size 119 (0x77)
.maxstack 3
.locals init (D<Base> V_0, //baseDelegate
D<Derived> V_1, //derivedDelegate
D<Derived> V_2)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldsfld ""D<Base> Program.<>c.<>9__0_0""
IL_0007: dup
IL_0008: brtrue.s IL_0021
IL_000a: pop
IL_000b: ldsfld ""Program.<>c Program.<>c.<>9""
IL_0010: ldftn ""void Program.<>c.<Main>b__0_0()""
IL_0016: newobj ""D<Base>..ctor(object, System.IntPtr)""
IL_001b: dup
IL_001c: stsfld ""D<Base> Program.<>c.<>9__0_0""
IL_0021: stloc.1
IL_0022: ldsfld ""D<Derived> Program.<>c.<>9__0_1""
IL_0027: dup
IL_0028: brtrue.s IL_0041
IL_002a: pop
IL_002b: ldsfld ""Program.<>c Program.<>c.<>9""
IL_0030: ldftn ""void Program.<>c.<Main>b__0_1()""
IL_0036: newobj ""D<Derived>..ctor(object, System.IntPtr)""
IL_003b: dup
IL_003c: stsfld ""D<Derived> Program.<>c.<>9__0_1""
IL_0041: stloc.2
IL_0042: ldloc.0
IL_0043: brtrue.s IL_0048
IL_0045: ldloc.2
IL_0046: br.s IL_004b
IL_0048: ldloc.1
IL_0049: stloc.3
IL_004a: ldloc.3
IL_004b: callvirt ""void D<Derived>.Invoke()""
IL_0050: ldloc.0
IL_0051: brtrue.s IL_0058
IL_0053: ldloc.1
IL_0054: stloc.3
IL_0055: ldloc.3
IL_0056: br.s IL_0059
IL_0058: ldloc.2
IL_0059: callvirt ""void D<Derived>.Invoke()""
IL_005e: ldloc.1
IL_005f: stloc.3
IL_0060: ldloc.3
IL_0061: dup
IL_0062: brtrue.s IL_0066
IL_0064: pop
IL_0065: ldloc.2
IL_0066: callvirt ""void D<Derived>.Invoke()""
IL_006b: ldloc.2
IL_006c: dup
IL_006d: brtrue.s IL_0073
IL_006f: pop
IL_0070: ldloc.1
IL_0071: stloc.3
IL_0072: ldloc.3
IL_0073: callvirt ""void D<Derived>.Invoke()""
IL_0078: ret
IL_0001: ldsfld ""D<Base> Program.<>c.<>9__0_0""
IL_0006: dup
IL_0007: brtrue.s IL_0020
IL_0009: pop
IL_000a: ldsfld ""Program.<>c Program.<>c.<>9""
IL_000f: ldftn ""void Program.<>c.<Main>b__0_0()""
IL_0015: newobj ""D<Base>..ctor(object, System.IntPtr)""
IL_001a: dup
IL_001b: stsfld ""D<Base> Program.<>c.<>9__0_0""
IL_0020: stloc.0
IL_0021: ldsfld ""D<Derived> Program.<>c.<>9__0_1""
IL_0026: dup
IL_0027: brtrue.s IL_0040
IL_0029: pop
IL_002a: ldsfld ""Program.<>c Program.<>c.<>9""
IL_002f: ldftn ""void Program.<>c.<Main>b__0_1()""
IL_0035: newobj ""D<Derived>..ctor(object, System.IntPtr)""
IL_003a: dup
IL_003b: stsfld ""D<Derived> Program.<>c.<>9__0_1""
IL_0040: stloc.1
IL_0041: dup
IL_0042: brtrue.s IL_0047
IL_0044: ldloc.1
IL_0045: br.s IL_004a
IL_0047: ldloc.0
IL_0048: stloc.2
IL_0049: ldloc.2
IL_004a: callvirt ""void D<Derived>.Invoke()""
IL_004f: brtrue.s IL_0056
IL_0051: ldloc.0
IL_0052: stloc.2
IL_0053: ldloc.2
IL_0054: br.s IL_0057
IL_0056: ldloc.1
IL_0057: callvirt ""void D<Derived>.Invoke()""
IL_005c: ldloc.0
IL_005d: stloc.2
IL_005e: ldloc.2
IL_005f: dup
IL_0060: brtrue.s IL_0064
IL_0062: pop
IL_0063: ldloc.1
IL_0064: callvirt ""void D<Derived>.Invoke()""
IL_0069: ldloc.1
IL_006a: dup
IL_006b: brtrue.s IL_0071
IL_006d: pop
IL_006e: ldloc.0
IL_006f: stloc.2
IL_0070: ldloc.2
IL_0071: callvirt ""void D<Derived>.Invoke()""
IL_0076: ret
}");
}
......@@ -458,59 +452,56 @@ static void Main()
";
string expectedIL = @"
{
// Code size 109 (0x6d)
// Code size 107 (0x6b)
.maxstack 2
.locals init (bool V_0, //testFlag
I<Base> V_1, //baseInstance
I<Derived> V_2, //derivedInstance
I<Base> V_3)
.locals init (I<Base> V_0, //baseInstance
I<Derived> V_1, //derivedInstance
I<Base> V_2)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: newobj ""B..ctor()""
IL_0007: stloc.1
IL_0008: newobj ""D..ctor()""
IL_000d: stloc.2
IL_000e: ldloc.0
IL_000f: brtrue.s IL_0016
IL_0011: ldloc.2
IL_0012: stloc.3
IL_0013: ldloc.3
IL_0014: br.s IL_0017
IL_0016: ldloc.1
IL_0017: callvirt ""System.Type object.GetType()""
IL_001c: callvirt ""string System.Reflection.MemberInfo.Name.get""
IL_0021: call ""void System.Console.Write(string)""
IL_0026: ldloc.0
IL_0027: brtrue.s IL_002c
IL_0029: ldloc.1
IL_002a: br.s IL_002f
IL_0001: newobj ""B..ctor()""
IL_0006: stloc.0
IL_0007: newobj ""D..ctor()""
IL_000c: stloc.1
IL_000d: dup
IL_000e: brtrue.s IL_0015
IL_0010: ldloc.1
IL_0011: stloc.2
IL_0012: ldloc.2
IL_0013: br.s IL_0016
IL_0015: ldloc.0
IL_0016: callvirt ""System.Type object.GetType()""
IL_001b: callvirt ""string System.Reflection.MemberInfo.Name.get""
IL_0020: call ""void System.Console.Write(string)""
IL_0025: brtrue.s IL_002a
IL_0027: ldloc.0
IL_0028: br.s IL_002d
IL_002a: ldloc.1
IL_002b: stloc.2
IL_002c: ldloc.2
IL_002d: stloc.3
IL_002e: ldloc.3
IL_002f: callvirt ""System.Type object.GetType()""
IL_0034: callvirt ""string System.Reflection.MemberInfo.Name.get""
IL_0039: call ""void System.Console.Write(string)""
IL_003e: ldloc.1
IL_003f: dup
IL_0040: brtrue.s IL_0046
IL_0042: pop
IL_002d: callvirt ""System.Type object.GetType()""
IL_0032: callvirt ""string System.Reflection.MemberInfo.Name.get""
IL_0037: call ""void System.Console.Write(string)""
IL_003c: ldloc.0
IL_003d: dup
IL_003e: brtrue.s IL_0044
IL_0040: pop
IL_0041: ldloc.1
IL_0042: stloc.2
IL_0043: ldloc.2
IL_0044: stloc.3
IL_0045: ldloc.3
IL_0046: callvirt ""System.Type object.GetType()""
IL_004b: callvirt ""string System.Reflection.MemberInfo.Name.get""
IL_0050: call ""void System.Console.Write(string)""
IL_0044: callvirt ""System.Type object.GetType()""
IL_0049: callvirt ""string System.Reflection.MemberInfo.Name.get""
IL_004e: call ""void System.Console.Write(string)""
IL_0053: ldloc.1
IL_0054: stloc.2
IL_0055: ldloc.2
IL_0056: stloc.3
IL_0057: ldloc.3
IL_0058: dup
IL_0059: brtrue.s IL_005d
IL_005b: pop
IL_005c: ldloc.1
IL_005d: callvirt ""System.Type object.GetType()""
IL_0062: callvirt ""string System.Reflection.MemberInfo.Name.get""
IL_0067: call ""void System.Console.Write(string)""
IL_006c: ret
IL_0056: dup
IL_0057: brtrue.s IL_005b
IL_0059: pop
IL_005a: ldloc.0
IL_005b: callvirt ""System.Type object.GetType()""
IL_0060: callvirt ""string System.Reflection.MemberInfo.Name.get""
IL_0065: call ""void System.Console.Write(string)""
IL_006a: ret
}
";
......@@ -560,59 +551,56 @@ static void Main()
";
string expectedIL = @"
{
// Code size 109 (0x6d)
// Code size 107 (0x6b)
.maxstack 2
.locals init (bool V_0, //testFlag
I<Base> V_1, //baseInstance
I<Derived> V_2, //derivedInstance
I<Derived> V_3)
.locals init (I<Base> V_0, //baseInstance
I<Derived> V_1, //derivedInstance
I<Derived> V_2)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: newobj ""B..ctor()""
IL_0007: stloc.1
IL_0008: newobj ""D..ctor()""
IL_000d: stloc.2
IL_000e: ldloc.0
IL_000f: brtrue.s IL_0014
IL_0011: ldloc.2
IL_0012: br.s IL_0017
IL_0014: ldloc.1
IL_0015: stloc.3
IL_0016: ldloc.3
IL_0017: callvirt ""System.Type object.GetType()""
IL_001c: callvirt ""string System.Reflection.MemberInfo.Name.get""
IL_0021: call ""void System.Console.Write(string)""
IL_0026: ldloc.0
IL_0027: brtrue.s IL_002e
IL_0029: ldloc.1
IL_002a: stloc.3
IL_002b: ldloc.3
IL_002c: br.s IL_002f
IL_002e: ldloc.2
IL_002f: callvirt ""System.Type object.GetType()""
IL_0034: callvirt ""string System.Reflection.MemberInfo.Name.get""
IL_0039: call ""void System.Console.Write(string)""
IL_003e: ldloc.1
IL_003f: stloc.3
IL_0040: ldloc.3
IL_0041: dup
IL_0042: brtrue.s IL_0046
IL_0044: pop
IL_0045: ldloc.2
IL_0046: callvirt ""System.Type object.GetType()""
IL_004b: callvirt ""string System.Reflection.MemberInfo.Name.get""
IL_0050: call ""void System.Console.Write(string)""
IL_0055: ldloc.2
IL_0056: dup
IL_0057: brtrue.s IL_005d
IL_0059: pop
IL_005a: ldloc.1
IL_005b: stloc.3
IL_005c: ldloc.3
IL_005d: callvirt ""System.Type object.GetType()""
IL_0062: callvirt ""string System.Reflection.MemberInfo.Name.get""
IL_0067: call ""void System.Console.Write(string)""
IL_006c: ret
IL_0001: newobj ""B..ctor()""
IL_0006: stloc.0
IL_0007: newobj ""D..ctor()""
IL_000c: stloc.1
IL_000d: dup
IL_000e: brtrue.s IL_0013
IL_0010: ldloc.1
IL_0011: br.s IL_0016
IL_0013: ldloc.0
IL_0014: stloc.2
IL_0015: ldloc.2
IL_0016: callvirt ""System.Type object.GetType()""
IL_001b: callvirt ""string System.Reflection.MemberInfo.Name.get""
IL_0020: call ""void System.Console.Write(string)""
IL_0025: brtrue.s IL_002c
IL_0027: ldloc.0
IL_0028: stloc.2
IL_0029: ldloc.2
IL_002a: br.s IL_002d
IL_002c: ldloc.1
IL_002d: callvirt ""System.Type object.GetType()""
IL_0032: callvirt ""string System.Reflection.MemberInfo.Name.get""
IL_0037: call ""void System.Console.Write(string)""
IL_003c: ldloc.0
IL_003d: stloc.2
IL_003e: ldloc.2
IL_003f: dup
IL_0040: brtrue.s IL_0044
IL_0042: pop
IL_0043: ldloc.1
IL_0044: callvirt ""System.Type object.GetType()""
IL_0049: callvirt ""string System.Reflection.MemberInfo.Name.get""
IL_004e: call ""void System.Console.Write(string)""
IL_0053: ldloc.1
IL_0054: dup
IL_0055: brtrue.s IL_005b
IL_0057: pop
IL_0058: ldloc.0
IL_0059: stloc.2
IL_005a: ldloc.2
IL_005b: callvirt ""System.Type object.GetType()""
IL_0060: callvirt ""string System.Reflection.MemberInfo.Name.get""
IL_0065: call ""void System.Console.Write(string)""
IL_006a: ret
}
";
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册