提交 d1237c0d 编写于 作者: N Neal Gafter

Improve dag construction to improve generated code.

上级 bfdde8d3
......@@ -524,13 +524,7 @@ DagState uniqifyState(DagState state)
}
else
{
BoundDagDecision selectDecision(DagState s)
{
// Our simple heuristic is to perform the first test of the first possible matched case
return s.Cases[0].Decisions[0];
}
switch (state.SelectedDecision = selectDecision(state))
switch (state.SelectedDecision = state.ComputeSelectedDecision())
{
case BoundDagEvaluation e:
state.TrueBranch = uniqifyState(RemoveEvaluation(state.Cases, e));
......@@ -643,6 +637,7 @@ BoundDecisionDag finalState(SyntaxNode syntax, LabelSymbol label, ImmutableArray
finalStates.Free();
Debug.Assert(initialState.Dag != null);
// Note: It is useful for debugging the dag state table construction to view `initialState.Dump()` here.
return initialState.Dag;
}
......@@ -775,6 +770,10 @@ BoundDecisionDag finalState(SyntaxNode syntax, LabelSymbol label, ImmutableArray
trueDecisionPermitsTrueOther = false; // if v!=null is true, then v==null cannot succeed
falseDecisionImpliesTrueOther = true; // if v!=null is false, then v==null has been proven true
break;
case BoundNonNullDecision n2:
trueDecisionImpliesTrueOther = true;
falseDecisionPermitsTrueOther = false;
break;
default:
// Once v!=null fails, it must fail a type test
falseDecisionPermitsTrueOther = false;
......@@ -885,6 +884,10 @@ private static PartialCaseDecision RemoveEvaluation(PartialCaseDecision c, Bound
Bindings: c.Bindings, WhenClause: c.WhenClause, CaseLabel: c.CaseLabel);
}
/// <summary>
/// The state at a given node of the decision acyclic graph. This is used during computation of the state machine,
/// and contains a representation of the meaning of the state.
/// </summary>
private class DagState
{
public readonly ImmutableArray<PartialCaseDecision> Cases;
......@@ -904,7 +907,134 @@ public DagState(ImmutableArray<PartialCaseDecision> cases)
// After the entire graph of DagState objects is complete, we translate each into its Dag.
public BoundDecisionDag Dag;
// Compute a decision to use at the root of the generated decision tree.
internal BoundDagDecision ComputeSelectedDecision()
{
// Our simple heuristic is to perform the first test of the first possible matched case
var choice = Cases[0].Decisions[0];
// But if that test is a null check, it would be redundant with a following
// type test. We apply this refinement only when there is exactly one case, because
// when there are multiple cases the null check is likely to be shared.
if (choice.Kind == BoundKind.NonNullDecision &&
Cases.Length == 1 &&
Cases[0].Decisions.Length > 1)
{
var choice2 = Cases[0].Decisions[1];
if (choice2.Kind == BoundKind.TypeDecision)
{
return choice2;
}
}
return choice;
}
#if DEBUG
/// <summary>
/// Starting with `this` state, produce a human-readable description of the state tables.
/// This is very useful for debugging and optimizing the dag state construction.
/// </summary>
internal string Dump()
{
var printed = PooledHashSet<DagState>.GetInstance();
int nextStateNumber = 0;
var workQueue = ArrayBuilder<DagState>.GetInstance();
var stateIdentifierMap = PooledDictionary<DagState, int>.GetInstance();
int stateIdentifier(DagState state)
{
if (stateIdentifierMap.TryGetValue(state, out int value))
{
return value;
}
else
{
value = stateIdentifierMap[state] = ++nextStateNumber;
workQueue.Push(state);
}
return value;
}
int nextTempNumber = 0;
var tempIdentifierMap = PooledDictionary<BoundDagEvaluation, int>.GetInstance();
int tempIdentifier(BoundDagEvaluation e)
{
return (e == null) ? 0 : tempIdentifierMap.TryGetValue(e, out int value) ? value : tempIdentifierMap[e] = ++nextTempNumber;
}
string tempName(BoundDagTemp t)
{
return $"t{tempIdentifier(t.Source)}{(t.Index != 0 ? $".{t.Index.ToString()}" : "")}";
}
var resultBuilder = PooledStringBuilder.GetInstance();
var result = resultBuilder.Builder;
stateIdentifier(this); // push the start node onto the work queue
while (workQueue.Count != 0)
{
var state = workQueue.Pop();
if (!printed.Add(state))
{
continue;
}
result.AppendLine($"State " + stateIdentifier(state));
foreach (PartialCaseDecision cd in state.Cases)
{
result.Append($" [{cd.Syntax}]");
foreach (BoundDagDecision d in cd.Decisions)
{
result.Append($" {dump(d)}");
}
result.AppendLine();
}
if (state.SelectedDecision != null)
{
result.AppendLine($" Decision: {dump(state.SelectedDecision)}");
}
if (state.TrueBranch != null)
{
result.AppendLine($" TrueBranch: {stateIdentifier(state.TrueBranch)}");
}
if (state.FalseBranch != null)
{
result.AppendLine($" FalseBranch: {stateIdentifier(state.FalseBranch)}");
}
}
workQueue.Free();
printed.Free();
stateIdentifierMap.Free();
tempIdentifierMap.Free();
return resultBuilder.ToStringAndFree();
string dump(BoundDagDecision d)
{
switch (d)
{
case BoundDagTypeEvaluation a:
return $"t{tempIdentifier(a)}={a.Kind}({a.Type.ToString()})";
case BoundDagEvaluation e:
return $"t{tempIdentifier(e)}={e.Kind}";
case BoundTypeDecision b:
return $"?{d.Kind}({b.Type.ToString()}, {tempName(d.Input)})";
case BoundNonNullValueDecision v:
return $"?{d.Kind}({v.Value.ToString()}, {tempName(d.Input)})";
default:
return $"?{d.Kind}({tempName(d.Input)})";
}
}
}
}
#endif
/// <summary>
/// An equivalence relation between dag states used to dedup the states during dag construction.
......
......@@ -149,6 +149,7 @@ private void LowerDecisionDag(ImmutableArray<BoundDecisionDag> sortedNodes)
/// <summary>
/// Translate the decision tree for node, given that it will be followed by the translation for nextNode.
/// This knowledge allows us to fall through to nextNode instead of producing a goto statement to get there.
/// </summary>
private void LowerDecisionDagNode(BoundDecisionDag node, BoundDecisionDag nextNode)
{
......
......@@ -203,7 +203,6 @@ protected BoundExpression LowerDecision(BoundDagDecision decision)
}
else
{
// PROTOTYPE(patterns2): combine null test and type test when possible for improved code
return _localRewriter.MakeNullCheck(d.Syntax, input, input.Type.IsNullableType() ? BinaryOperatorKind.NullableNullNotEqual : BinaryOperatorKind.NotEqual);
}
......@@ -211,6 +210,7 @@ protected BoundExpression LowerDecision(BoundDagDecision decision)
case BoundTypeDecision d:
{
// Note that this tests for non-null as a side-effect. We depend on that to sometimes avoid the null check.
return _factory.Is(input, d.Type);
}
......
......@@ -142,7 +142,6 @@ static void M1(int? x)
);
}
// PROTOTYPE(patterns2): code quality has regressed for this test because the lowering strategy reifies the boolean result of the if expression.
[Fact, WorkItem(17266, "https://github.com/dotnet/roslyn/issues/17266")]
public void DoubleEvaluation01()
{
......@@ -200,6 +199,28 @@ .maxstack 1
IL_002a: nop
IL_002b: ret
}");
compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
compilation.VerifyDiagnostics();
compVerifier = CompileAndVerify(compilation, expectedOutput: expectedOutput);
compVerifier.VerifyIL("C.Main",
@"{
// Code size 30 (0x1e)
.maxstack 1
.locals init (int V_0, //index
int? V_1)
IL_0000: call ""int? C.TryGet()""
IL_0005: stloc.1
IL_0006: ldloca.s V_1
IL_0008: call ""bool int?.HasValue.get""
IL_000d: brfalse.s IL_001d
IL_000f: ldloca.s V_1
IL_0011: call ""int int?.GetValueOrDefault()""
IL_0016: stloc.0
IL_0017: ldloc.0
IL_0018: call ""void System.Console.WriteLine(int)""
IL_001d: ret
}");
}
[Fact, WorkItem(19122, "https://github.com/dotnet/roslyn/issues/19122")]
......@@ -248,7 +269,7 @@ public Guid GetId(T t)
var compVerifier = CompileAndVerify(compilation);
compVerifier.VerifyIL("X<T>.Y<U>",
@"{
// Code size 71 (0x47)
// Code size 63 (0x3f)
.maxstack 3
.locals init (U V_0, //u
bool V_1,
......@@ -264,26 +285,23 @@ .maxstack 3
IL_0018: stloc.2
IL_0019: ldloc.2
IL_001a: box ""T""
IL_001f: brfalse.s IL_003f
IL_0021: ldloc.2
IL_0022: box ""T""
IL_0027: isinst ""U""
IL_002c: brfalse.s IL_003f
IL_002e: ldloc.2
IL_002f: box ""T""
IL_0034: unbox.any ""U""
IL_0039: stloc.3
IL_003a: ldloc.3
IL_003b: stloc.0
IL_003c: ldc.i4.1
IL_003d: br.s IL_0040
IL_003f: ldc.i4.0
IL_0040: stloc.1
IL_0041: ldloc.1
IL_0042: brfalse.s IL_0046
IL_0044: nop
IL_0045: nop
IL_0046: ret
IL_001f: isinst ""U""
IL_0024: brfalse.s IL_0037
IL_0026: ldloc.2
IL_0027: box ""T""
IL_002c: unbox.any ""U""
IL_0031: stloc.3
IL_0032: ldloc.3
IL_0033: stloc.0
IL_0034: ldc.i4.1
IL_0035: br.s IL_0038
IL_0037: ldc.i4.0
IL_0038: stloc.1
IL_0039: ldloc.1
IL_003a: brfalse.s IL_003e
IL_003c: nop
IL_003d: nop
IL_003e: ret
}");
}
......@@ -327,7 +345,7 @@ static void Main(string[] args)
var compVerifier = CompileAndVerify(compilation, expectedOutput: expectedOutput);
compVerifier.VerifyIL("Program.Main",
@"{
// Code size 113 (0x71)
// Code size 106 (0x6a)
.maxstack 2
.locals init (Base<object> V_0, //x
Derived V_1, //y
......@@ -346,47 +364,43 @@ .maxstack 2
IL_0010: call ""void System.Console.WriteLine(bool)""
IL_0015: nop
IL_0016: ldloc.0
IL_0017: brfalse.s IL_002d
IL_0019: ldloc.0
IL_001a: isinst ""Derived""
IL_001f: brfalse.s IL_002d
IL_0021: ldloc.0
IL_0022: castclass ""Derived""
IL_0027: stloc.2
IL_0028: ldloc.2
IL_0029: stloc.1
IL_002a: ldc.i4.1
IL_002b: br.s IL_002e
IL_002d: ldc.i4.0
IL_002e: call ""void System.Console.WriteLine(bool)""
IL_0033: nop
IL_0034: ldloc.0
IL_0035: stloc.s V_6
IL_0037: ldloc.s V_6
IL_0039: stloc.s V_4
IL_003b: ldloc.s V_4
IL_003d: brfalse.s IL_0061
IL_003f: ldloc.s V_4
IL_0041: isinst ""Derived""
IL_0046: brfalse.s IL_0061
IL_0048: ldloc.s V_4
IL_004a: castclass ""Derived""
IL_004f: stloc.s V_5
IL_0051: br.s IL_0053
IL_0053: ldloc.s V_5
IL_0055: stloc.3
IL_0056: br.s IL_0058
IL_0058: ldc.i4.1
IL_0059: call ""void System.Console.WriteLine(bool)""
IL_005e: nop
IL_005f: br.s IL_0061
IL_0061: ldloc.0
IL_0062: isinst ""Derived""
IL_0067: ldnull
IL_0068: cgt.un
IL_006a: call ""void System.Console.WriteLine(bool)""
IL_006f: nop
IL_0070: ret
IL_0017: isinst ""Derived""
IL_001c: brfalse.s IL_002a
IL_001e: ldloc.0
IL_001f: castclass ""Derived""
IL_0024: stloc.2
IL_0025: ldloc.2
IL_0026: stloc.1
IL_0027: ldc.i4.1
IL_0028: br.s IL_002b
IL_002a: ldc.i4.0
IL_002b: call ""void System.Console.WriteLine(bool)""
IL_0030: nop
IL_0031: ldloc.0
IL_0032: stloc.s V_6
IL_0034: ldloc.s V_6
IL_0036: stloc.s V_4
IL_0038: ldloc.s V_4
IL_003a: isinst ""Derived""
IL_003f: brfalse.s IL_005a
IL_0041: ldloc.s V_4
IL_0043: castclass ""Derived""
IL_0048: stloc.s V_5
IL_004a: br.s IL_004c
IL_004c: ldloc.s V_5
IL_004e: stloc.3
IL_004f: br.s IL_0051
IL_0051: ldc.i4.1
IL_0052: call ""void System.Console.WriteLine(bool)""
IL_0057: nop
IL_0058: br.s IL_005a
IL_005a: ldloc.0
IL_005b: isinst ""Derived""
IL_0060: ldnull
IL_0061: cgt.un
IL_0063: call ""void System.Console.WriteLine(bool)""
IL_0068: nop
IL_0069: ret
}");
}
......@@ -472,7 +486,7 @@ .maxstack 2
}");
compVerifier.VerifyIL("Program.P5",
@"{
// Code size 125 (0x7d)
// Code size 122 (0x7a)
.maxstack 2
.locals init (object V_0,
double V_1,
......@@ -485,7 +499,7 @@ .maxstack 2
IL_0003: ldloc.3
IL_0004: stloc.0
IL_0005: ldloc.0
IL_0006: brfalse.s IL_0075
IL_0006: brfalse.s IL_0072
IL_0008: ldloc.0
IL_0009: isinst ""double""
IL_000e: brfalse.s IL_0035
......@@ -494,49 +508,47 @@ .maxstack 2
IL_0016: stloc.1
IL_0017: ldloc.1
IL_0018: call ""bool double.IsNaN(double)""
IL_001d: brtrue.s IL_0061
IL_001d: brtrue.s IL_005e
IL_001f: ldloc.0
IL_0020: isinst ""double""
IL_0025: brfalse.s IL_0075
IL_0025: brfalse.s IL_0072
IL_0027: ldc.r8 3.14
IL_0030: ldloc.1
IL_0031: beq.s IL_006b
IL_0033: br.s IL_0075
IL_0031: beq.s IL_0068
IL_0033: br.s IL_0072
IL_0035: ldloc.0
IL_0036: brfalse.s IL_0075
IL_0038: ldloc.0
IL_0039: isinst ""float""
IL_003e: brfalse.s IL_0075
IL_0040: ldloc.0
IL_0041: unbox.any ""float""
IL_0046: stloc.2
IL_0047: ldloc.2
IL_0048: call ""bool float.IsNaN(float)""
IL_004d: brtrue.s IL_0066
IL_004f: ldloc.0
IL_0050: isinst ""float""
IL_0055: brfalse.s IL_0075
IL_0057: ldc.r4 3.14
IL_005c: ldloc.2
IL_005d: beq.s IL_0070
IL_005f: br.s IL_0075
IL_0061: ldc.i4.1
IL_0062: stloc.s V_4
IL_0064: br.s IL_007a
IL_0066: ldc.i4.1
IL_0067: stloc.s V_4
IL_0069: br.s IL_007a
IL_006b: ldc.i4.1
IL_006c: stloc.s V_4
IL_006e: br.s IL_007a
IL_0070: ldc.i4.1
IL_0071: stloc.s V_4
IL_0073: br.s IL_007a
IL_0075: ldc.i4.0
IL_0076: stloc.s V_4
IL_0078: br.s IL_007a
IL_007a: ldloc.s V_4
IL_007c: ret
IL_0036: isinst ""float""
IL_003b: brfalse.s IL_0072
IL_003d: ldloc.0
IL_003e: unbox.any ""float""
IL_0043: stloc.2
IL_0044: ldloc.2
IL_0045: call ""bool float.IsNaN(float)""
IL_004a: brtrue.s IL_0063
IL_004c: ldloc.0
IL_004d: isinst ""float""
IL_0052: brfalse.s IL_0072
IL_0054: ldc.r4 3.14
IL_0059: ldloc.2
IL_005a: beq.s IL_006d
IL_005c: br.s IL_0072
IL_005e: ldc.i4.1
IL_005f: stloc.s V_4
IL_0061: br.s IL_0077
IL_0063: ldc.i4.1
IL_0064: stloc.s V_4
IL_0066: br.s IL_0077
IL_0068: ldc.i4.1
IL_0069: stloc.s V_4
IL_006b: br.s IL_0077
IL_006d: ldc.i4.1
IL_006e: stloc.s V_4
IL_0070: br.s IL_0077
IL_0072: ldc.i4.0
IL_0073: stloc.s V_4
IL_0075: br.s IL_0077
IL_0077: ldloc.s V_4
IL_0079: ret
}");
}
}
......
......@@ -7585,7 +7585,7 @@ .maxstack 2
");
}
[Fact(Skip = "PROTOTYPE(patterns2): code quality")]
[Fact]
public void PatternVariable_TypeChange()
{
var source0 = MarkedSource(@"
......@@ -7617,19 +7617,19 @@ class C
v0.VerifyIL("C.F", @"
{
// Code size 37 (0x25)
.maxstack 2
.maxstack 1
.locals init (int V_0, //i
bool V_1,
object V_2,
int V_2,
int V_3)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: dup
IL_0003: stloc.2
IL_0004: isinst ""int""
IL_0009: brfalse.s IL_0015
IL_000b: ldloc.2
IL_000c: unbox.any ""int""
IL_0002: isinst ""int""
IL_0007: brfalse.s IL_0015
IL_0009: ldarg.0
IL_000a: unbox.any ""int""
IL_000f: stloc.2
IL_0010: ldloc.2
IL_0011: stloc.0
IL_0012: ldc.i4.1
IL_0013: br.s IL_0016
......@@ -7659,23 +7659,23 @@ .maxstack 2
diff1.VerifyIL("C.F", @"
{
// Code size 52 (0x34)
.maxstack 2
.maxstack 1
.locals init ([int] V_0,
[bool] V_1,
[object] V_2,
[int] V_2,
[int] V_3,
bool V_4, //i
bool V_5,
object V_6,
bool V_6,
int V_7)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: dup
IL_0003: stloc.s V_6
IL_0005: isinst ""bool""
IL_000a: brfalse.s IL_0018
IL_000c: ldloc.s V_6
IL_000e: unbox.any ""bool""
IL_0002: isinst ""bool""
IL_0007: brfalse.s IL_0018
IL_0009: ldarg.0
IL_000a: unbox.any ""bool""
IL_000f: stloc.s V_6
IL_0011: ldloc.s V_6
IL_0013: stloc.s V_4
IL_0015: ldc.i4.1
IL_0016: br.s IL_0019
......@@ -7706,27 +7706,27 @@ .maxstack 2
diff2.VerifyIL("C.F", @"
{
// Code size 46 (0x2e)
.maxstack 2
.maxstack 1
.locals init ([int] V_0,
[bool] V_1,
[object] V_2,
[int] V_2,
[int] V_3,
[bool] V_4,
[bool] V_5,
[object] V_6,
[bool] V_6,
[int] V_7,
int V_8, //j
bool V_9,
object V_10,
int V_10,
int V_11)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: dup
IL_0003: stloc.s V_10
IL_0005: isinst ""int""
IL_000a: brfalse.s IL_0018
IL_000c: ldloc.s V_10
IL_000e: unbox.any ""int""
IL_0002: isinst ""int""
IL_0007: brfalse.s IL_0018
IL_0009: ldarg.0
IL_000a: unbox.any ""int""
IL_000f: stloc.s V_10
IL_0011: ldloc.s V_10
IL_0013: stloc.s V_8
IL_0015: ldc.i4.1
IL_0016: br.s IL_0019
......@@ -7746,7 +7746,7 @@ .maxstack 2
}");
}
[Fact(Skip = "PROTOTYPE(patterns2): code quality")]
[Fact]
public void PatternVariable_DeleteInsert()
{
var source0 = MarkedSource(@"
......@@ -7778,19 +7778,19 @@ class C
v0.VerifyIL("C.F", @"
{
// Code size 37 (0x25)
.maxstack 2
.maxstack 1
.locals init (int V_0, //i
bool V_1,
object V_2,
int V_2,
int V_3)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: dup
IL_0003: stloc.2
IL_0004: isinst ""int""
IL_0009: brfalse.s IL_0015
IL_000b: ldloc.2
IL_000c: unbox.any ""int""
IL_0002: isinst ""int""
IL_0007: brfalse.s IL_0015
IL_0009: ldarg.0
IL_000a: unbox.any ""int""
IL_000f: stloc.2
IL_0010: ldloc.2
IL_0011: stloc.0
IL_0012: ldc.i4.1
IL_0013: br.s IL_0016
......@@ -7823,7 +7823,7 @@ .maxstack 2
.maxstack 2
.locals init ([int] V_0,
[bool] V_1,
[object] V_2,
[int] V_2,
[int] V_3,
bool V_4,
int V_5)
......@@ -7855,25 +7855,25 @@ .maxstack 2
diff2.VerifyIL("C.F", @"
{
// Code size 46 (0x2e)
.maxstack 2
.maxstack 1
.locals init ([int] V_0,
[bool] V_1,
[object] V_2,
[int] V_2,
[int] V_3,
[bool] V_4,
[int] V_5,
int V_6, //i
bool V_7,
object V_8,
int V_8,
int V_9)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: dup
IL_0003: stloc.s V_8
IL_0005: isinst ""int""
IL_000a: brfalse.s IL_0018
IL_000c: ldloc.s V_8
IL_000e: unbox.any ""int""
IL_0002: isinst ""int""
IL_0007: brfalse.s IL_0018
IL_0009: ldarg.0
IL_000a: unbox.any ""int""
IL_000f: stloc.s V_8
IL_0011: ldloc.s V_8
IL_0013: stloc.s V_6
IL_0015: ldc.i4.1
IL_0016: br.s IL_0019
......
......@@ -2364,7 +2364,7 @@ .locals init (int V_0)
}");
}
[Fact(Skip = "PROTOTYPE(patterns2): local slot mapping is not yet supported for new pattern switch")]
[Fact]
public void Switch_Patterns()
{
var source = @"
......@@ -2402,15 +2402,14 @@ static void M()
<customDebugInfo>
<forward declaringType=""C"" methodName=""F"" />
<encLocalSlotMap>
<slot kind=""35"" offset=""11"" />
<slot kind=""35"" offset=""11"" />
<slot kind=""35"" offset=""11"" />
<slot kind=""0"" offset=""106"" />
<slot kind=""0"" offset=""162"" />
<slot kind=""0"" offset=""273"" />
<slot kind=""0"" offset=""323"" />
<slot kind=""35"" offset=""19"" />
<slot kind=""35"" offset=""19"" />
<slot kind=""35"" offset=""19"" />
<slot kind=""1"" offset=""11"" />
<slot kind=""temp"" />
</encLocalSlotMap>
</customDebugInfo>
</method>
......@@ -2419,107 +2418,95 @@ static void M()
v0.VerifyIL("C.M", @"
{
// Code size 200 (0xc8)
// Code size 197 (0xc5)
.maxstack 2
.locals init (object V_0,
int V_1,
byte V_2,
byte V_3, //b
int V_4, //i
int V_5, //j
object V_6, //o
object V_7,
object V_8)
.locals init (byte V_0, //b
int V_1, //i
int V_2, //j
object V_3, //o
object V_4,
int V_5,
byte V_6,
object V_7)
IL_0000: nop
IL_0001: call ""object C.F()""
IL_0006: stloc.s V_7
IL_0008: ldloc.s V_7
IL_000a: stloc.0
IL_000b: ldloc.0
IL_000c: brtrue.s IL_0010
IL_000e: br.s IL_0063
IL_0010: ldloc.0
IL_0011: dup
IL_0012: stloc.s V_8
IL_0014: isinst ""int""
IL_0019: brfalse.s IL_002b
IL_001b: ldloc.s V_8
IL_001d: unbox.any ""int""
IL_0022: stloc.1
IL_0023: ldloc.1
IL_0024: ldc.i4.1
IL_0025: beq.s IL_0029
IL_0027: br.s IL_002b
IL_0029: br.s IL_0065
IL_002b: ldloc.0
IL_002c: dup
IL_002d: stloc.s V_8
IL_002f: isinst ""byte""
IL_0034: brfalse.s IL_0048
IL_0036: ldloc.s V_8
IL_0038: unbox.any ""byte""
IL_003d: stloc.2
IL_003e: br.s IL_0072
IL_0040: ldloc.2
IL_0041: ldc.i4.1
IL_0042: beq.s IL_0046
IL_0044: br.s IL_0048
IL_0046: br.s IL_009c
IL_0048: ldloc.0
IL_0049: dup
IL_004a: stloc.s V_8
IL_004c: isinst ""int""
IL_0051: brfalse.s IL_005f
IL_0053: ldloc.s V_8
IL_0055: unbox.any ""int""
IL_005a: stloc.1
IL_005b: br.s IL_0086
IL_005d: br.s IL_00a9
IL_005f: ldloc.0
IL_0060: stloc.0
IL_0061: br.s IL_00b8
IL_0063: br.s IL_00c7
IL_0065: ldstr ""int 1""
IL_006a: call ""void System.Console.WriteLine(string)""
IL_006f: nop
IL_0070: br.s IL_00c7
IL_0072: ldloc.2
IL_0073: stloc.3
IL_000a: stloc.s V_4
IL_000c: ldloc.s V_4
IL_000e: brfalse IL_00c4
IL_0013: ldloc.s V_4
IL_0015: isinst ""int""
IL_001a: brfalse.s IL_0040
IL_001c: ldloc.s V_4
IL_001e: unbox.any ""int""
IL_0023: stloc.s V_5
IL_0025: ldc.i4.1
IL_0026: ldloc.s V_5
IL_0028: beq.s IL_0064
IL_002a: ldloc.s V_4
IL_002c: isinst ""int""
IL_0031: brfalse.s IL_0062
IL_0033: br.s IL_0086
IL_0035: ldloc.s V_4
IL_0037: isinst ""int""
IL_003c: brfalse.s IL_0062
IL_003e: br.s IL_00a8
IL_0040: ldloc.s V_4
IL_0042: isinst ""byte""
IL_0047: brfalse.s IL_0062
IL_0049: ldloc.s V_4
IL_004b: unbox.any ""byte""
IL_0050: stloc.s V_6
IL_0052: br.s IL_0071
IL_0054: ldloc.s V_4
IL_0056: isinst ""byte""
IL_005b: brfalse.s IL_0062
IL_005d: ldc.i4.1
IL_005e: ldloc.s V_6
IL_0060: beq.s IL_009b
IL_0062: br.s IL_00b6
IL_0064: ldstr ""int 1""
IL_0069: call ""void System.Console.WriteLine(string)""
IL_006e: nop
IL_006f: br.s IL_00c4
IL_0071: ldloc.s V_6
IL_0073: stloc.0
IL_0074: call ""bool C.P()""
IL_0079: brtrue.s IL_007d
IL_007b: br.s IL_0040
IL_007d: ldloc.3
IL_007b: br.s IL_0054
IL_007d: ldloc.0
IL_007e: call ""void System.Console.WriteLine(int)""
IL_0083: nop
IL_0084: br.s IL_00c7
IL_0086: ldloc.1
IL_0087: stloc.s V_4
IL_0084: br.s IL_00c4
IL_0086: ldloc.s V_5
IL_0088: stloc.1
IL_0089: call ""bool C.P()""
IL_008e: brtrue.s IL_0092
IL_0090: br.s IL_005d
IL_0092: ldloc.s V_4
IL_0094: call ""void System.Console.WriteLine(int)""
IL_0099: nop
IL_009a: br.s IL_00c7
IL_009c: ldstr ""byte 1""
IL_00a1: call ""void System.Console.WriteLine(string)""
IL_00a6: nop
IL_00a7: br.s IL_00c7
IL_00a9: ldloc.1
IL_00aa: stloc.s V_5
IL_00ac: br.s IL_00ae
IL_00ae: ldloc.s V_5
IL_00b0: call ""void System.Console.WriteLine(int)""
IL_00b5: nop
IL_00b6: br.s IL_00c7
IL_00b8: ldloc.0
IL_00b9: stloc.s V_6
IL_00bb: br.s IL_00bd
IL_00bd: ldloc.s V_6
IL_00bf: call ""void System.Console.WriteLine(object)""
IL_00c4: nop
IL_00c5: br.s IL_00c7
IL_00c7: ret
IL_0090: br.s IL_0035
IL_0092: ldloc.1
IL_0093: call ""void System.Console.WriteLine(int)""
IL_0098: nop
IL_0099: br.s IL_00c4
IL_009b: ldstr ""byte 1""
IL_00a0: call ""void System.Console.WriteLine(string)""
IL_00a5: nop
IL_00a6: br.s IL_00c4
IL_00a8: ldloc.s V_5
IL_00aa: stloc.2
IL_00ab: br.s IL_00ad
IL_00ad: ldloc.2
IL_00ae: call ""void System.Console.WriteLine(int)""
IL_00b3: nop
IL_00b4: br.s IL_00c4
IL_00b6: ldloc.s V_4
IL_00b8: stloc.3
IL_00b9: br.s IL_00bb
IL_00bb: ldloc.3
IL_00bc: call ""void System.Console.WriteLine(object)""
IL_00c1: nop
IL_00c2: br.s IL_00c4
IL_00c4: ret
}");
var methodData0 = v0.TestData.GetMethodData("C.M");
var method0 = compilation0.GetMember<MethodSymbol>("C.M");
......@@ -2532,108 +2519,98 @@ .maxstack 2
diff1.VerifyIL("C.M", @"
{
// Code size 200 (0xc8)
// Code size 197 (0xc5)
.maxstack 2
.locals init (object V_0,
int V_1,
byte V_2,
byte V_3, //b
int V_4, //i
int V_5, //j
object V_6, //o
.locals init (byte V_0, //b
int V_1, //i
int V_2, //j
object V_3, //o
[object] V_4,
[int] V_5,
[unchanged] V_6,
object V_7,
[object] V_8,
object V_9)
object V_8,
int V_9,
byte V_10)
IL_0000: nop
IL_0001: call ""object C.F()""
IL_0006: stloc.s V_7
IL_0008: ldloc.s V_7
IL_000a: stloc.0
IL_000b: ldloc.0
IL_000c: brtrue.s IL_0010
IL_000e: br.s IL_0063
IL_0010: ldloc.0
IL_0011: dup
IL_0012: stloc.s V_9
IL_0014: isinst ""int""
IL_0019: brfalse.s IL_002b
IL_001b: ldloc.s V_9
IL_001d: unbox.any ""int""
IL_0022: stloc.1
IL_0023: ldloc.1
IL_0024: ldc.i4.1
IL_0025: beq.s IL_0029
IL_0027: br.s IL_002b
IL_0029: br.s IL_0065
IL_002b: ldloc.0
IL_002c: dup
IL_002d: stloc.s V_9
IL_002f: isinst ""byte""
IL_0034: brfalse.s IL_0048
IL_0036: ldloc.s V_9
IL_0038: unbox.any ""byte""
IL_003d: stloc.2
IL_003e: br.s IL_0072
IL_0040: ldloc.2
IL_0041: ldc.i4.1
IL_0042: beq.s IL_0046
IL_0044: br.s IL_0048
IL_0046: br.s IL_009c
IL_0048: ldloc.0
IL_0049: dup
IL_004a: stloc.s V_9
IL_004c: isinst ""int""
IL_0051: brfalse.s IL_005f
IL_0053: ldloc.s V_9
IL_0055: unbox.any ""int""
IL_005a: stloc.1
IL_005b: br.s IL_0086
IL_005d: br.s IL_00a9
IL_005f: ldloc.0
IL_0060: stloc.0
IL_0061: br.s IL_00b8
IL_0063: br.s IL_00c7
IL_0065: ldstr ""int 1""
IL_006a: call ""void System.Console.WriteLine(string)""
IL_006f: nop
IL_0070: br.s IL_00c7
IL_0072: ldloc.2
IL_0073: stloc.3
IL_000a: stloc.s V_8
IL_000c: ldloc.s V_8
IL_000e: brfalse IL_00c4
IL_0013: ldloc.s V_8
IL_0015: isinst ""int""
IL_001a: brfalse.s IL_0040
IL_001c: ldloc.s V_8
IL_001e: unbox.any ""int""
IL_0023: stloc.s V_9
IL_0025: ldc.i4.1
IL_0026: ldloc.s V_9
IL_0028: beq.s IL_0064
IL_002a: ldloc.s V_8
IL_002c: isinst ""int""
IL_0031: brfalse.s IL_0062
IL_0033: br.s IL_0086
IL_0035: ldloc.s V_8
IL_0037: isinst ""int""
IL_003c: brfalse.s IL_0062
IL_003e: br.s IL_00a8
IL_0040: ldloc.s V_8
IL_0042: isinst ""byte""
IL_0047: brfalse.s IL_0062
IL_0049: ldloc.s V_8
IL_004b: unbox.any ""byte""
IL_0050: stloc.s V_10
IL_0052: br.s IL_0071
IL_0054: ldloc.s V_8
IL_0056: isinst ""byte""
IL_005b: brfalse.s IL_0062
IL_005d: ldc.i4.1
IL_005e: ldloc.s V_10
IL_0060: beq.s IL_009b
IL_0062: br.s IL_00b6
IL_0064: ldstr ""int 1""
IL_0069: call ""void System.Console.WriteLine(string)""
IL_006e: nop
IL_006f: br.s IL_00c4
IL_0071: ldloc.s V_10
IL_0073: stloc.0
IL_0074: call ""bool C.P()""
IL_0079: brtrue.s IL_007d
IL_007b: br.s IL_0040
IL_007d: ldloc.3
IL_007b: br.s IL_0054
IL_007d: ldloc.0
IL_007e: call ""void System.Console.WriteLine(int)""
IL_0083: nop
IL_0084: br.s IL_00c7
IL_0086: ldloc.1
IL_0087: stloc.s V_4
IL_0084: br.s IL_00c4
IL_0086: ldloc.s V_9
IL_0088: stloc.1
IL_0089: call ""bool C.P()""
IL_008e: brtrue.s IL_0092
IL_0090: br.s IL_005d
IL_0092: ldloc.s V_4
IL_0094: call ""void System.Console.WriteLine(int)""
IL_0099: nop
IL_009a: br.s IL_00c7
IL_009c: ldstr ""byte 1""
IL_00a1: call ""void System.Console.WriteLine(string)""
IL_00a6: nop
IL_00a7: br.s IL_00c7
IL_00a9: ldloc.1
IL_00aa: stloc.s V_5
IL_00ac: br.s IL_00ae
IL_00ae: ldloc.s V_5
IL_00b0: call ""void System.Console.WriteLine(int)""
IL_00b5: nop
IL_00b6: br.s IL_00c7
IL_00b8: ldloc.0
IL_00b9: stloc.s V_6
IL_00bb: br.s IL_00bd
IL_00bd: ldloc.s V_6
IL_00bf: call ""void System.Console.WriteLine(object)""
IL_00c4: nop
IL_00c5: br.s IL_00c7
IL_00c7: ret
IL_0090: br.s IL_0035
IL_0092: ldloc.1
IL_0093: call ""void System.Console.WriteLine(int)""
IL_0098: nop
IL_0099: br.s IL_00c4
IL_009b: ldstr ""byte 1""
IL_00a0: call ""void System.Console.WriteLine(string)""
IL_00a5: nop
IL_00a6: br.s IL_00c4
IL_00a8: ldloc.s V_9
IL_00aa: stloc.2
IL_00ab: br.s IL_00ad
IL_00ad: ldloc.2
IL_00ae: call ""void System.Console.WriteLine(int)""
IL_00b3: nop
IL_00b4: br.s IL_00c4
IL_00b6: ldloc.s V_8
IL_00b8: stloc.3
IL_00b9: br.s IL_00bb
IL_00bb: ldloc.3
IL_00bc: call ""void System.Console.WriteLine(object)""
IL_00c1: nop
IL_00c2: br.s IL_00c4
IL_00c4: ret
}");
}
......@@ -3606,7 +3583,7 @@ .maxstack 2
", methodToken: diff1.UpdatedMethods.Single());
}
[Fact(Skip = "PROTOTYPE(patterns2): code quality")]
[Fact]
public void PatternVariable()
{
var source = @"
......@@ -3632,21 +3609,21 @@ class C
diff1.VerifyIL("C.F", @"
{
// Code size 42 (0x2a)
.maxstack 2
.maxstack 1
.locals init (int V_0, //i
bool V_1,
[object] V_2,
[int] V_2,
[int] V_3,
object V_4,
int V_4,
int V_5)
-IL_0000: nop
-IL_0001: ldarg.0
IL_0002: dup
IL_0003: stloc.s V_4
IL_0005: isinst ""int""
IL_000a: brfalse.s IL_0017
IL_000c: ldloc.s V_4
IL_000e: unbox.any ""int""
IL_0002: isinst ""int""
IL_0007: brfalse.s IL_0017
IL_0009: ldarg.0
IL_000a: unbox.any ""int""
IL_000f: stloc.s V_4
IL_0011: ldloc.s V_4
IL_0013: stloc.0
IL_0014: ldc.i4.1
IL_0015: br.s IL_0018
......@@ -3773,7 +3750,7 @@ .maxstack 2
", methodToken: diff1.UpdatedMethods.Single());
}
[Fact(Skip = "PROTOTYPE(patterns2): code quality")]
[Fact]
public void PatternMatching_Variable()
{
var source = @"
......@@ -3799,21 +3776,21 @@ class C
diff1.VerifyIL("C.F", @"
{
// Code size 42 (0x2a)
.maxstack 2
.maxstack 1
.locals init (int V_0, //i
bool V_1,
[object] V_2,
[int] V_2,
[int] V_3,
object V_4,
int V_4,
int V_5)
-IL_0000: nop
-IL_0001: ldarg.0
IL_0002: dup
IL_0003: stloc.s V_4
IL_0005: isinst ""int""
IL_000a: brfalse.s IL_0017
IL_000c: ldloc.s V_4
IL_000e: unbox.any ""int""
IL_0002: isinst ""int""
IL_0007: brfalse.s IL_0017
IL_0009: ldarg.0
IL_000a: unbox.any ""int""
IL_000f: stloc.s V_4
IL_0011: ldloc.s V_4
IL_0013: stloc.0
IL_0014: ldc.i4.1
IL_0015: br.s IL_0018
......@@ -3833,7 +3810,7 @@ .maxstack 2
}", methodToken: diff1.UpdatedMethods.Single());
}
[Fact(Skip = "PROTOTYPE(patterns2): code quality")]
[Fact]
public void PatternMatching_NoVariable()
{
var source = @"
......@@ -3858,33 +3835,42 @@ class C
diff1.VerifyIL("C.F", @"
{
// Code size 39 (0x27)
// Code size 52 (0x34)
.maxstack 2
.locals init (bool V_0,
[int] V_1,
int V_2)
[int] V_2,
int V_3,
int V_4)
-IL_0000: nop
-IL_0001: ldarg.0
IL_0002: isinst ""bool""
IL_0007: brtrue.s IL_0017
IL_0009: ldc.i4.0
IL_000a: box ""int""
IL_000f: ldarg.0
IL_0010: call ""bool object.Equals(object, object)""
IL_0015: br.s IL_0018
IL_0017: ldc.i4.1
IL_0018: stloc.0
~IL_0019: ldloc.0
IL_001a: brfalse.s IL_0021
-IL_001c: nop
-IL_001d: ldc.i4.0
IL_001e: stloc.2
IL_001f: br.s IL_0025
-IL_0021: ldc.i4.1
IL_0022: stloc.2
IL_0023: br.s IL_0025
-IL_0025: ldloc.2
IL_0026: ret
IL_0007: brtrue.s IL_0021
IL_0009: ldarg.0
IL_000a: isinst ""int""
IL_000f: brfalse.s IL_001e
IL_0011: ldarg.0
IL_0012: unbox.any ""int""
IL_0017: stloc.3
IL_0018: ldloc.3
IL_0019: ldc.i4.0
IL_001a: ceq
IL_001c: br.s IL_001f
IL_001e: ldc.i4.0
IL_001f: br.s IL_0022
IL_0021: ldc.i4.1
IL_0022: stloc.0
~IL_0023: ldloc.0
IL_0024: brfalse.s IL_002c
-IL_0026: nop
-IL_0027: ldc.i4.0
IL_0028: stloc.s V_4
IL_002a: br.s IL_0031
-IL_002c: ldc.i4.1
IL_002d: stloc.s V_4
IL_002f: br.s IL_0031
-IL_0031: ldloc.s V_4
IL_0033: ret
}
", methodToken: diff1.UpdatedMethods.Single());
}
......
......@@ -3358,7 +3358,7 @@ .maxstack 1
}");
}
[Fact(Skip = "PROTOTYPE(patterns2): This test is sensitive to the precise code generated, which is currently in flux.")]
[Fact]
[WorkItem(19734, "https://github.com/dotnet/roslyn/issues/19734")]
public void SwitchWithConstantGenericPattern_01()
{
......@@ -3408,125 +3408,99 @@ static void M2<T>()
c.VerifyDiagnostics();
var verifier = CompileAndVerify(c, expectedOutput: "1234");
// PROTOTYPE(patterns2): Need to restore code quality
verifier.VerifyIL(qualifiedMethodName: "Program.M1<T>", sequencePoints: "Program.M1", source: source,
expectedIL: @"{
// Code size 80 (0x50)
.maxstack 2
.locals init (T V_0,
int V_1,
T V_2, //t
int V_3, //i
int V_4,
object V_5,
T V_6)
// Code size 67 (0x43)
.maxstack 1
.locals init (T V_0, //t
int V_1, //i
int V_2,
T V_3,
int V_4)
// sequence point: {
IL_0000: nop
// sequence point: switch (1)
IL_0001: ldc.i4.1
IL_0002: stloc.s V_4
IL_0004: ldc.i4.1
IL_0005: box ""int""
IL_000a: stloc.s V_5
IL_000c: ldloc.s V_5
IL_000e: isinst ""T""
IL_0013: ldnull
IL_0014: cgt.un
IL_0016: dup
IL_0017: brtrue.s IL_0025
IL_0019: ldloca.s V_6
IL_001b: initobj ""T""
IL_0021: ldloc.s V_6
IL_0023: br.s IL_002c
IL_0025: ldloc.s V_5
IL_0027: unbox.any ""T""
IL_002c: stloc.0
IL_002d: brfalse.s IL_0031
IL_002f: br.s IL_0035
IL_0031: ldc.i4.1
IL_0032: stloc.1
IL_0005: stloc.2
IL_0006: ldloc.2
IL_0007: box ""int""
IL_000c: isinst ""T""
IL_0011: brfalse.s IL_0026
IL_0013: ldloc.2
IL_0014: box ""int""
IL_0019: isinst ""T""
IL_001e: unbox.any ""T""
IL_0023: stloc.3
IL_0024: br.s IL_0028
IL_0026: br.s IL_0035
IL_0028: ldloc.3
IL_0029: stloc.0
IL_002a: br.s IL_002c
// sequence point: Console.Write(1);
IL_002c: ldc.i4.1
IL_002d: call ""void System.Console.Write(int)""
IL_0032: nop
// sequence point: break;
IL_0033: br.s IL_0042
// sequence point: <hidden>
IL_0035: ldloc.0
IL_0036: stloc.2
IL_0035: ldloc.2
IL_0036: stloc.1
IL_0037: br.s IL_0039
// sequence point: Console.Write(1);
IL_0039: ldc.i4.1
// sequence point: Console.Write(2);
IL_0039: ldc.i4.2
IL_003a: call ""void System.Console.Write(int)""
IL_003f: nop
// sequence point: break;
IL_0040: br.s IL_004f
// sequence point: <hidden>
IL_0042: ldloc.1
IL_0043: stloc.3
IL_0044: br.s IL_0046
// sequence point: Console.Write(2);
IL_0046: ldc.i4.2
IL_0047: call ""void System.Console.Write(int)""
IL_004c: nop
// sequence point: break;
IL_004d: br.s IL_004f
IL_0040: br.s IL_0042
// sequence point: }
IL_004f: ret
IL_0042: ret
}");
verifier.VerifyIL(qualifiedMethodName: "Program.M2<T>", sequencePoints: "Program.M2", source: source,
expectedIL: @"{
// Code size 87 (0x57)
.maxstack 2
.locals init (T V_0,
string V_1,
T V_2, //t
string V_3, //s
string V_4,
object V_5,
T V_6)
// Code size 65 (0x41)
.maxstack 1
.locals init (T V_0, //t
string V_1, //s
string V_2,
T V_3,
string V_4)
// sequence point: {
IL_0000: nop
// sequence point: switch (nameof(M2))
IL_0001: ldstr ""M2""
IL_0006: stloc.s V_4
IL_0008: ldstr ""M2""
IL_000d: stloc.s V_5
IL_000f: ldloc.s V_5
IL_0011: isinst ""T""
IL_0016: ldnull
IL_0017: cgt.un
IL_0019: dup
IL_001a: brtrue.s IL_0028
IL_001c: ldloca.s V_6
IL_001e: initobj ""T""
IL_0024: ldloc.s V_6
IL_0026: br.s IL_002f
IL_0028: ldloc.s V_5
IL_002a: unbox.any ""T""
IL_002f: stloc.0
IL_0030: brfalse.s IL_0034
IL_0032: br.s IL_003c
IL_0034: ldstr ""M2""
IL_0039: stloc.1
IL_003a: br.s IL_0049
// sequence point: <hidden>
IL_003c: ldloc.0
IL_003d: stloc.2
IL_003e: br.s IL_0040
IL_000d: stloc.2
IL_000e: ldloc.2
IL_000f: isinst ""T""
IL_0014: brfalse.s IL_0024
IL_0016: ldloc.2
IL_0017: isinst ""T""
IL_001c: unbox.any ""T""
IL_0021: stloc.3
IL_0022: br.s IL_0026
IL_0024: br.s IL_0033
IL_0026: ldloc.3
IL_0027: stloc.0
IL_0028: br.s IL_002a
// sequence point: Console.Write(3);
IL_0040: ldc.i4.3
IL_0041: call ""void System.Console.Write(int)""
IL_0046: nop
IL_002a: ldc.i4.3
IL_002b: call ""void System.Console.Write(int)""
IL_0030: nop
// sequence point: break;
IL_0047: br.s IL_0056
// sequence point: <hidden>
IL_0049: ldloc.1
IL_004a: stloc.3
IL_004b: br.s IL_004d
IL_0031: br.s IL_0040
IL_0033: ldloc.2
IL_0034: stloc.1
IL_0035: br.s IL_0037
// sequence point: Console.Write(4);
IL_004d: ldc.i4.4
IL_004e: call ""void System.Console.Write(int)""
IL_0053: nop
IL_0037: ldc.i4.4
IL_0038: call ""void System.Console.Write(int)""
IL_003d: nop
// sequence point: break;
IL_0054: br.s IL_0056
IL_003e: br.s IL_0040
// sequence point: }
IL_0056: ret
IL_0040: ret
}");
// Check the release code generation too.
......@@ -3536,72 +3510,49 @@ .maxstack 2
verifier.VerifyIL("Program.M1<T>",
@"{
// Code size 57 (0x39)
.maxstack 2
.locals init (T V_0,
int V_1,
object V_2,
T V_3)
// Code size 46 (0x2e)
.maxstack 1
.locals init (int V_0,
T V_1)
IL_0000: ldc.i4.1
IL_0001: box ""int""
IL_0006: stloc.2
IL_0007: ldloc.2
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: box ""int""
IL_0008: isinst ""T""
IL_000d: ldnull
IL_000e: cgt.un
IL_0010: dup
IL_0011: brtrue.s IL_001e
IL_0013: ldloca.s V_3
IL_0015: initobj ""T""
IL_001b: ldloc.3
IL_001c: br.s IL_0024
IL_001e: ldloc.2
IL_001f: unbox.any ""T""
IL_0024: stloc.0
IL_0025: brtrue.s IL_002b
IL_0027: ldc.i4.1
IL_0028: stloc.1
IL_0029: br.s IL_0032
IL_002b: ldc.i4.1
IL_002c: call ""void System.Console.Write(int)""
IL_0031: ret
IL_0032: ldc.i4.2
IL_0033: call ""void System.Console.Write(int)""
IL_0038: ret
IL_000d: brfalse.s IL_0027
IL_000f: ldloc.0
IL_0010: box ""int""
IL_0015: isinst ""T""
IL_001a: unbox.any ""T""
IL_001f: stloc.1
IL_0020: ldc.i4.1
IL_0021: call ""void System.Console.Write(int)""
IL_0026: ret
IL_0027: ldc.i4.2
IL_0028: call ""void System.Console.Write(int)""
IL_002d: ret
}");
verifier.VerifyIL("Program.M2<T>",
@"{
// Code size 60 (0x3c)
.maxstack 2
.locals init (T V_0,
string V_1,
object V_2,
T V_3)
// Code size 40 (0x28)
.maxstack 1
.locals init (string V_0,
T V_1)
IL_0000: ldstr ""M2""
IL_0005: stloc.2
IL_0006: ldloc.2
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: isinst ""T""
IL_000c: ldnull
IL_000d: cgt.un
IL_000f: dup
IL_0010: brtrue.s IL_001d
IL_0012: ldloca.s V_3
IL_0014: initobj ""T""
IL_001a: ldloc.3
IL_001b: br.s IL_0023
IL_001d: ldloc.2
IL_001e: unbox.any ""T""
IL_0023: stloc.0
IL_0024: brtrue.s IL_002e
IL_0026: ldstr ""M2""
IL_002b: stloc.1
IL_002c: br.s IL_0035
IL_002e: ldc.i4.3
IL_002f: call ""void System.Console.Write(int)""
IL_0034: ret
IL_0035: ldc.i4.4
IL_0036: call ""void System.Console.Write(int)""
IL_003b: ret
IL_000c: brfalse.s IL_0021
IL_000e: ldloc.0
IL_000f: isinst ""T""
IL_0014: unbox.any ""T""
IL_0019: stloc.1
IL_001a: ldc.i4.3
IL_001b: call ""void System.Console.Write(int)""
IL_0020: ret
IL_0021: ldc.i4.4
IL_0022: call ""void System.Console.Write(int)""
IL_0027: ret
}");
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册