Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
8b8bc93a
R
roslyn
项目概览
lwm1986
/
roslyn
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
roslyn
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
8b8bc93a
编写于
4月 04, 2018
作者:
N
Neal Gafter
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Optimize switch on a tuple literal
Fixes #20641
上级
662deba9
变更
7
显示空白变更内容
内联
并排
Showing
7 changed file
with
358 addition
and
139 deletion
+358
-139
src/Compilers/CSharp/Portable/Binder/DecisionDagBuilder.cs
src/Compilers/CSharp/Portable/Binder/DecisionDagBuilder.cs
+6
-1
src/Compilers/CSharp/Portable/BoundTree/BoundDagEvaluation.cs
...Compilers/CSharp/Portable/BoundTree/BoundDagEvaluation.cs
+1
-1
src/Compilers/CSharp/Portable/BoundTree/BoundDagTemp.cs
src/Compilers/CSharp/Portable/BoundTree/BoundDagTemp.cs
+3
-0
src/Compilers/CSharp/Portable/BoundTree/BoundDecisionDag.cs
src/Compilers/CSharp/Portable/BoundTree/BoundDecisionDag.cs
+95
-1
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BasePatternSwitchLocalRewriter.cs
...lRewriter/LocalRewriter_BasePatternSwitchLocalRewriter.cs
+43
-5
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Patterns.cs
...Portable/Lowering/LocalRewriter/LocalRewriter_Patterns.cs
+94
-7
src/Compilers/CSharp/Test/Emit/CodeGen/PatternTests.cs
src/Compilers/CSharp/Test/Emit/CodeGen/PatternTests.cs
+116
-124
未找到文件。
src/Compilers/CSharp/Portable/Binder/DecisionDagBuilder.cs
浏览文件 @
8b8bc93a
...
...
@@ -1214,8 +1214,13 @@ private static bool SameTest(BoundDagTest x, BoundDagTest y)
case
BoundKind
.
DagValueTest
:
return
((
BoundDagValueTest
)
x
).
Value
==
((
BoundDagValueTest
)
y
).
Value
;
default
:
case
BoundKind
.
DagNullTest
:
case
BoundKind
.
DagNonNullTest
:
return
true
;
default
:
// For an evaluation, we defer to its .Equals
return
x
.
Equals
(
y
);
}
}
...
...
src/Compilers/CSharp/Portable/BoundTree/BoundDagEvaluation.cs
浏览文件 @
8b8bc93a
...
...
@@ -17,7 +17,7 @@ private Symbol Symbol
{
switch
(
this
)
{
case
BoundDagFieldEvaluation
e
:
return
e
.
Field
;
case
BoundDagFieldEvaluation
e
:
return
e
.
Field
.
CorrespondingTupleField
??
e
.
Field
;
case
BoundDagPropertyEvaluation
e
:
return
e
.
Property
;
case
BoundDagTypeEvaluation
e
:
return
e
.
Type
;
case
BoundDagDeconstructEvaluation
e
:
return
e
.
DeconstructMethod
;
...
...
src/Compilers/CSharp/Portable/BoundTree/BoundDagTemp.cs
浏览文件 @
8b8bc93a
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using
Microsoft.CodeAnalysis.CSharp.Symbols
;
using
Roslyn.Utilities
;
namespace
Microsoft.CodeAnalysis.CSharp
...
...
@@ -11,6 +12,8 @@ partial class BoundDagTemp
/// </summary>
public
bool
IsOriginalInput
=>
this
.
Source
==
null
;
public
static
BoundDagTemp
ForOriginalInput
(
SyntaxNode
syntax
,
TypeSymbol
type
)
=>
new
BoundDagTemp
(
syntax
,
type
,
null
,
0
);
public
override
bool
Equals
(
object
obj
)
=>
obj
is
BoundDagTemp
other
&&
this
.
Equals
(
other
);
public
bool
Equals
(
BoundDagTemp
other
)
{
...
...
src/Compilers/CSharp/Portable/BoundTree/BoundDecisionDag.cs
浏览文件 @
8b8bc93a
...
...
@@ -116,7 +116,7 @@ public BoundDecisionDag Rewrite(Func<BoundDecisionDagNode, Func<BoundDecisionDag
/// <param name="dag"></param>
/// <param name="replacement"></param>
/// <returns></returns>
public
BoundDecisionDagNode
TrivialReplacement
(
BoundDecisionDagNode
dag
,
Func
<
BoundDecisionDagNode
,
BoundDecisionDagNode
>
replacement
)
public
static
BoundDecisionDagNode
TrivialReplacement
(
BoundDecisionDagNode
dag
,
Func
<
BoundDecisionDagNode
,
BoundDecisionDagNode
>
replacement
)
{
switch
(
dag
)
{
...
...
@@ -192,5 +192,99 @@ BoundDecisionDagNode makeReplacement(BoundDecisionDagNode dag, Func<BoundDecisio
}
}
}
#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
new
string
Dump
()
{
var
allStates
=
this
.
TopologicallySortedNodes
;
var
stateIdentifierMap
=
PooledDictionary
<
BoundDecisionDagNode
,
int
>.
GetInstance
();
for
(
int
i
=
0
;
i
<
allStates
.
Length
;
i
++)
{
stateIdentifierMap
.
Add
(
allStates
[
i
],
i
);
}
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
;
foreach
(
var
state
in
allStates
)
{
result
.
AppendLine
(
$"State "
+
stateIdentifierMap
[
state
]);
switch
(
state
)
{
case
BoundTestDecisionDagNode
node
:
result
.
AppendLine
(
$" Test:
{
dump
(
node
.
Test
)}
"
);
if
(
node
.
WhenTrue
!=
null
)
{
result
.
AppendLine
(
$" WhenTrue:
{
stateIdentifierMap
[
node
.
WhenTrue
]}
"
);
}
if
(
node
.
WhenFalse
!=
null
)
{
result
.
AppendLine
(
$" WhenFalse:
{
stateIdentifierMap
[
node
.
WhenFalse
]}
"
);
}
break
;
case
BoundEvaluationDecisionDagNode
node
:
result
.
AppendLine
(
$" Test:
{
dump
(
node
.
Evaluation
)}
"
);
if
(
node
.
Next
!=
null
)
{
result
.
AppendLine
(
$" Next:
{
stateIdentifierMap
[
node
.
Next
]}
"
);
}
break
;
case
BoundWhenDecisionDagNode
node
:
result
.
AppendLine
(
$" WhenClause: "
+
node
.
WhenExpression
.
Syntax
);
if
(
node
.
WhenTrue
!=
null
)
{
result
.
AppendLine
(
$" WhenTrue:
{
stateIdentifierMap
[
node
.
WhenTrue
]}
"
);
}
if
(
node
.
WhenFalse
!=
null
)
{
result
.
AppendLine
(
$" WhenFalse:
{
stateIdentifierMap
[
node
.
WhenFalse
]}
"
);
}
break
;
case
BoundLeafDecisionDagNode
node
:
result
.
AppendLine
(
$" Case: "
+
node
.
Syntax
);
break
;
}
}
stateIdentifierMap
.
Free
();
tempIdentifierMap
.
Free
();
return
resultBuilder
.
ToStringAndFree
();
string
dump
(
BoundDagTest
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
BoundDagTypeTest
b
:
return
$"?
{
d
.
Kind
}
(
{
b
.
Type
.
ToString
()}
,
{
tempName
(
d
.
Input
)}
)"
;
case
BoundDagValueTest
v
:
return
$"?
{
d
.
Kind
}
(
{
v
.
Value
.
ToString
()}
,
{
tempName
(
d
.
Input
)}
)"
;
default
:
return
$"?
{
d
.
Kind
}
(
{
tempName
(
d
.
Input
)}
)"
;
}
}
}
#endif
}
}
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BasePatternSwitchLocalRewriter.cs
浏览文件 @
8b8bc93a
...
...
@@ -145,6 +145,18 @@ public bool MightAssignSomething(BoundExpression expr)
return
this
.
_mightAssignSomething
;
}
public
override
BoundNode
VisitReturnStatement
(
BoundReturnStatement
node
)
{
if
(
node
.
RefKind
!=
RefKind
.
None
)
{
// might be taking a ref to a variable in a lambda that the caller assigns.
this
.
_mightAssignSomething
=
true
;
return
null
;
}
return
base
.
VisitReturnStatement
(
node
);
}
public
override
BoundNode
VisitCall
(
BoundCall
node
)
{
_mightAssignSomething
=
...
...
@@ -173,12 +185,43 @@ public override BoundNode VisitDeconstructionAssignmentOperator(BoundDeconstruct
return
null
;
}
public
override
BoundNode
VisitDynamicInvocation
(
BoundDynamicInvocation
node
)
{
// perhaps we are passing a variable by ref and mutating it that way
_mightAssignSomething
=
!
node
.
ArgumentRefKindsOpt
.
IsDefault
;
return
base
.
VisitDynamicInvocation
(
node
);
}
public
override
BoundNode
VisitObjectCreationExpression
(
BoundObjectCreationExpression
node
)
{
// perhaps we are passing a variable by ref and mutating it that way
_mightAssignSomething
=
!
node
.
ArgumentRefKindsOpt
.
IsDefault
;
return
base
.
VisitObjectCreationExpression
(
node
);
}
public
override
BoundNode
VisitDynamicObjectCreationExpression
(
BoundDynamicObjectCreationExpression
node
)
{
_mightAssignSomething
=
!
node
.
ArgumentRefKindsOpt
.
IsDefault
;
return
base
.
VisitDynamicObjectCreationExpression
(
node
);
}
public
override
BoundNode
VisitObjectInitializerMember
(
BoundObjectInitializerMember
node
)
{
_mightAssignSomething
=
!
node
.
ArgumentRefKindsOpt
.
IsDefault
;
return
base
.
VisitObjectInitializerMember
(
node
);
}
public
override
BoundNode
VisitIndexerAccess
(
BoundIndexerAccess
node
)
{
_mightAssignSomething
=
!
node
.
ArgumentRefKindsOpt
.
IsDefault
;
return
base
.
VisitIndexerAccess
(
node
);
}
public
override
BoundNode
VisitDynamicIndexerAccess
(
BoundDynamicIndexerAccess
node
)
{
_mightAssignSomething
=
!
node
.
ArgumentRefKindsOpt
.
IsDefault
;
return
base
.
VisitDynamicIndexerAccess
(
node
);
}
}
protected
BoundDecisionDag
ShareTempsIfPossibleAndEvaluateInput
(
BoundDecisionDag
decisionDag
,
...
...
@@ -398,11 +441,6 @@ private bool GenerateSwitchDispatch(BoundDecisionDagNode node, HashSet<BoundDeci
stringEquality
=
_localRewriter
.
UnsafeGetSpecialTypeMethod
(
node
.
Syntax
,
SpecialMember
.
System_String__op_Equality
);
}
if
(
_dagNodeLabels
.
TryGetValue
(
node
,
out
LabelSymbol
nodeLabel
))
{
_loweredDecisionDag
.
Add
(
_factory
.
Label
(
nodeLabel
));
}
LabelSymbol
defaultLabel
=
GetDagNodeLabel
(
previous
.
WhenFalse
);
var
dispatch
=
new
BoundSwitchDispatch
(
node
.
Syntax
,
_tempAllocator
.
GetTemp
(
firstTest
.
Input
),
cases
.
ToImmutableAndFree
(),
defaultLabel
,
stringEquality
);
...
...
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Patterns.cs
浏览文件 @
8b8bc93a
...
...
@@ -55,6 +55,25 @@ public void Free()
_map
.
Free
();
}
#if DEBUG
public
string
Dump
()
{
var
poolElemenet
=
PooledStringBuilder
.
GetInstance
();
var
builder
=
poolElemenet
.
Builder
;
foreach
(
var
kv
in
_map
)
{
builder
.
Append
(
"Key: "
);
builder
.
AppendLine
(
kv
.
Key
.
Dump
());
builder
.
Append
(
"Value: "
);
builder
.
AppendLine
(
kv
.
Value
.
Dump
());
}
var
result
=
builder
.
ToString
();
poolElemenet
.
Free
();
return
result
;
}
#endif
public
BoundExpression
GetTemp
(
BoundDagTemp
dagTemp
)
{
if
(!
_map
.
TryGetValue
(
dagTemp
,
out
BoundExpression
result
))
...
...
@@ -365,15 +384,16 @@ private BoundExpression MakeEqual(BoundExpression loweredLiteral, BoundExpressio
}
}
if
(
loweredInput
.
Kind
==
BoundKind
.
TupleLiteral
&&
!
decisionDag
.
TopologicallySortedNodes
.
Any
(
n
=>
!
usesOriginalInput
(
n
))
&&
false
)
if
(
loweredInput
.
Type
.
IsTupleType
&&
loweredInput
.
Syntax
.
Kind
()
==
SyntaxKind
.
TupleExpression
&&
loweredInput
is
BoundObjectCreationExpression
expr
&&
!
decisionDag
.
TopologicallySortedNodes
.
Any
(
n
=>
usesOriginalInput
(
n
)))
{
// If the switch governing expression is a tuple literal
that
is not used anywhere,
// If the switch governing expression is a tuple literal
whose whole value
is not used anywhere,
// (though perhaps its component parts are used), then we can save the component parts
// and assign them into temps (or perhaps user variables) to avoid the creation of
// the tuple altogether.
decisionDag
=
RewriteTupleInput
(
decisionDag
,
(
BoundTupleLiteral
)
loweredInput
,
addCode
);
decisionDag
=
RewriteTupleInput
(
decisionDag
,
expr
,
addCode
);
}
else
{
...
...
@@ -418,10 +438,77 @@ bool usesOriginalInput(BoundDecisionDagNode node)
/// <returns>A new decision dag that does not reference the input directly</returns>
private
BoundDecisionDag
RewriteTupleInput
(
BoundDecisionDag
decisionDag
,
Bound
TupleLiteral
loweredInput
,
Bound
ObjectCreationExpression
loweredInput
,
Action
<
BoundExpression
>
addCode
)
{
throw
new
NotImplementedException
();
int
count
=
loweredInput
.
Arguments
.
Length
;
var
tupleElementEvaluated
=
new
bool
[
count
];
var
rewrittenDag
=
decisionDag
.
Rewrite
(
makeReplacement
);
// If any remaining input elements remain unevaluated, evaluate them now
var
originalInput
=
BoundDagTemp
.
ForOriginalInput
(
loweredInput
.
Syntax
,
loweredInput
.
Type
);
for
(
int
i
=
0
;
i
<
count
;
i
++)
{
if
(!
tupleElementEvaluated
[
i
])
{
var
expr
=
loweredInput
.
Arguments
[
i
];
var
field
=
loweredInput
.
Type
.
TupleElements
[
i
].
CorrespondingTupleField
;
Debug
.
Assert
(
field
!=
null
);
var
fieldFetchEvaluation
=
new
BoundDagFieldEvaluation
(
expr
.
Syntax
,
field
,
originalInput
);
var
temp
=
new
BoundDagTemp
(
expr
.
Syntax
,
expr
.
Type
,
fieldFetchEvaluation
,
0
);
storeToTemp
(
temp
,
expr
);
}
}
return
rewrittenDag
;
void
storeToTemp
(
BoundDagTemp
temp
,
BoundExpression
expr
)
{
if
((
expr
.
Kind
==
BoundKind
.
Parameter
||
expr
.
Kind
==
BoundKind
.
Local
)
&&
_tempAllocator
.
TrySetTemp
(
temp
,
expr
))
{
// we've arranged to use the input value from the variable it is already stored in
}
else
{
var
tempToHoldInput
=
_tempAllocator
.
GetTemp
(
temp
);
addCode
(
_factory
.
AssignmentExpression
(
tempToHoldInput
,
expr
));
}
}
BoundDecisionDagNode
makeReplacement
(
BoundDecisionDagNode
node
,
Func
<
BoundDecisionDagNode
,
BoundDecisionDagNode
>
replacement
)
{
switch
(
node
)
{
case
BoundEvaluationDecisionDagNode
evalNode
:
if
(
evalNode
.
Evaluation
is
BoundDagFieldEvaluation
eval
&&
eval
.
Input
.
IsOriginalInput
&&
eval
.
Field
is
var
field
&&
field
.
IsTupleField
&&
field
.
CorrespondingTupleField
!=
null
&&
field
.
TupleElementIndex
is
int
i
)
{
if
(!
tupleElementEvaluated
[
i
])
{
// Store the value in the right temp
var
temp
=
new
BoundDagTemp
(
eval
.
Syntax
,
field
.
Type
,
eval
,
0
);
BoundExpression
expr
=
loweredInput
.
Arguments
[
i
];
storeToTemp
(
temp
,
expr
);
tupleElementEvaluated
[
i
]
=
true
;
}
return
replacement
(
evalNode
.
Next
);
}
Debug
.
Assert
(!
evalNode
.
Evaluation
.
Input
.
IsOriginalInput
);
break
;
case
BoundTestDecisionDagNode
testNode
:
Debug
.
Assert
(!
testNode
.
Test
.
Input
.
IsOriginalInput
);
break
;
}
return
BoundDecisionDag
.
TrivialReplacement
(
node
,
replacement
);
}
}
}
}
...
...
src/Compilers/CSharp/Test/Emit/CodeGen/PatternTests.cs
浏览文件 @
8b8bc93a
...
...
@@ -1121,7 +1121,9 @@ .maxstack 2
}"
);
}
[
Fact
,
WorkItem
(
20641
,
"https://github.com/dotnet/roslyn/issues/20641"
)]
[
Fact
]
[
WorkItem
(
20641
,
"https://github.com/dotnet/roslyn/issues/20641"
)]
[
WorkItem
(
1395
,
"https://github.com/dotnet/csharplang/issues/1395"
)]
public
void
TupleSwitch01
()
{
var
source
=
@"using System;
...
...
@@ -1134,13 +1136,20 @@ public enum DoorState { Opened, Closed, Locked }
public enum Action { Open, Close, Lock, Unlock }
public void Act(Action action, bool haveKey = false)
public void Act
0
(Action action, bool haveKey = false)
{
Console.Write($""{State} {action}{(haveKey ? "" withKey"" : null)}"");
State = ChangeState0(State, action, haveKey);
Console.WriteLine($"" -> {State}"");
}
public void Act1(Action action, bool haveKey = false)
{
Console.Write($""{State} {action}{(haveKey ? "" withKey"" : null)}"");
State = ChangeState1(State, action, haveKey);
Console.WriteLine($"" -> {State}"");
}
public static DoorState ChangeState0(DoorState state, Action action, bool haveKey = false)
{
switch ((state, action))
...
...
@@ -1172,13 +1181,23 @@ class Program
static void Main(string[] args)
{
var door = new Door();
door.Act(Door.Action.Close);
door.Act(Door.Action.Lock);
door.Act(Door.Action.Lock, true);
door.Act(Door.Action.Open);
door.Act(Door.Action.Unlock);
door.Act(Door.Action.Unlock, true);
door.Act(Door.Action.Open);
door.Act0(Door.Action.Close);
door.Act0(Door.Action.Lock);
door.Act0(Door.Action.Lock, true);
door.Act0(Door.Action.Open);
door.Act0(Door.Action.Unlock);
door.Act0(Door.Action.Unlock, true);
door.Act0(Door.Action.Open);
Console.WriteLine();
door = new Door();
door.Act1(Door.Action.Close);
door.Act1(Door.Action.Lock);
door.Act1(Door.Action.Lock, true);
door.Act1(Door.Action.Open);
door.Act1(Door.Action.Unlock);
door.Act1(Door.Action.Unlock, true);
door.Act1(Door.Action.Open);
}
}"
;
var
expectedOutput
=
...
...
@@ -1189,132 +1208,105 @@ static void Main(string[] args)
Locked Unlock -> Locked
Locked Unlock withKey -> Closed
Closed Open -> Opened
Opened Close -> Closed
Closed Lock -> Closed
Closed Lock withKey -> Locked
Locked Open -> Locked
Locked Unlock -> Locked
Locked Unlock withKey -> Closed
Closed Open -> Opened
"
;
var
compilation
=
CreateCompilation
(
source
,
options
:
TestOptions
.
ReleaseExe
,
parseOptions
:
TestOptions
.
Regular
.
WithRecursivePatterns
());
compilation
.
VerifyDiagnostics
();
var
compVerifier
=
CompileAndVerify
(
compilation
,
expectedOutput
:
expectedOutput
);
compVerifier
.
VerifyIL
(
"Door.ChangeState0"
,
@"{
// Code size 94 (0x5e)
.maxstack 3
.locals init (Door.DoorState V_0, //oldState
System.ValueTuple<Door.DoorState, Door.Action> V_1,
Door.Action V_2)
IL_0000: ldloca.s V_1
IL_0002: ldarg.0
IL_0003: ldarg.1
IL_0004: call ""System.ValueTuple<Door.DoorState, Door.Action>..ctor(Door.DoorState, Door.Action)""
IL_0009: ldloc.1
IL_000a: ldfld ""Door.DoorState System.ValueTuple<Door.DoorState, Door.Action>.Item1""
IL_000f: stloc.0
IL_0010: ldloc.0
IL_0011: switch (
IL_0024,
IL_0031,
IL_0041)
IL_0022: br.s IL_005c
IL_0024: ldloc.1
IL_0025: ldfld ""Door.Action System.ValueTuple<Door.DoorState, Door.Action>.Item2""
IL_002a: stloc.2
// Code size 59 (0x3b)
.maxstack 2
.locals init (Door.DoorState V_0) //oldState
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: switch (
IL_0016,
IL_001c,
IL_0025)
IL_0014: br.s IL_0039
IL_0016: ldc.i4.1
IL_0017: ldarg.1
IL_0018: beq.s IL_002b
IL_001a: br.s IL_0039
IL_001c: ldarg.1
IL_001d: brfalse.s IL_002d
IL_001f: ldarg.1
IL_0020: ldc.i4.2
IL_0021: beq.s IL_002f
IL_0023: br.s IL_0039
IL_0025: ldc.i4.3
IL_0026: ldarg.1
IL_0027: beq.s IL_0034
IL_0029: br.s IL_0039
IL_002b: ldc.i4.1
IL_002c: ldloc.2
IL_002d: beq.s IL_004e
IL_002f: br.s IL_005c
IL_0031: ldloc.1
IL_0032: ldfld ""Door.Action System.ValueTuple<Door.DoorState, Door.Action>.Item2""
IL_0037: stloc.2
IL_0038: ldloc.2
IL_0039: brfalse.s IL_0050
IL_003b: ldloc.2
IL_003c: ldc.i4.2
IL_003d: beq.s IL_0052
IL_003f: br.s IL_005c
IL_0041: ldloc.1
IL_0042: ldfld ""Door.Action System.ValueTuple<Door.DoorState, Door.Action>.Item2""
IL_0047: stloc.2
IL_0048: ldc.i4.3
IL_0049: ldloc.2
IL_004a: beq.s IL_0057
IL_004c: br.s IL_005c
IL_004e: ldc.i4.1
IL_004f: ret
IL_0050: ldc.i4.0
IL_0051: ret
IL_0052: ldarg.2
IL_0053: brfalse.s IL_005c
IL_0055: ldc.i4.2
IL_0056: ret
IL_0057: ldarg.2
IL_0058: brfalse.s IL_005c
IL_005a: ldc.i4.1
IL_005b: ret
IL_005c: ldloc.0
IL_005d: ret
IL_002c: ret
IL_002d: ldc.i4.0
IL_002e: ret
IL_002f: ldarg.2
IL_0030: brfalse.s IL_0039
IL_0032: ldc.i4.2
IL_0033: ret
IL_0034: ldarg.2
IL_0035: brfalse.s IL_0039
IL_0037: ldc.i4.1
IL_0038: ret
IL_0039: ldloc.0
IL_003a: ret
}"
);
compVerifier
.
VerifyIL
(
"Door.ChangeState1"
,
@"{
// Code size 104 (0x68)
.maxstack 3
.locals init (System.ValueTuple<Door.DoorState, Door.Action> V_0,
Door.DoorState V_1,
Door.Action V_2,
Door.DoorState V_3)
IL_0000: ldloca.s V_0
IL_0002: ldarg.0
IL_0003: ldarg.1
IL_0004: call ""System.ValueTuple<Door.DoorState, Door.Action>..ctor(Door.DoorState, Door.Action)""
IL_0009: ldloc.0
IL_000a: ldfld ""Door.DoorState System.ValueTuple<Door.DoorState, Door.Action>.Item1""
IL_000f: stloc.1
IL_0010: ldloc.1
IL_0011: switch (
IL_0024,
IL_0031,
IL_0041)
IL_0022: br.s IL_0064
IL_0024: ldloc.0
IL_0025: ldfld ""Door.Action System.ValueTuple<Door.DoorState, Door.Action>.Item2""
IL_002a: stloc.2
IL_002b: ldc.i4.1
IL_002c: ldloc.2
IL_002d: beq.s IL_004e
IL_002f: br.s IL_0064
IL_0031: ldloc.0
IL_0032: ldfld ""Door.Action System.ValueTuple<Door.DoorState, Door.Action>.Item2""
IL_0037: stloc.2
IL_0038: ldloc.2
IL_0039: brfalse.s IL_0052
IL_003b: ldloc.2
IL_003c: ldc.i4.2
IL_003d: beq.s IL_0056
IL_003f: br.s IL_0064
// Code size 67 (0x43)
.maxstack 2
.locals init (Door.DoorState V_0)
IL_0000: ldarg.0
IL_0001: switch (
IL_0014,
IL_001a,
IL_0023)
IL_0012: br.s IL_003f
IL_0014: ldc.i4.1
IL_0015: ldarg.1
IL_0016: beq.s IL_0029
IL_0018: br.s IL_003f
IL_001a: ldarg.1
IL_001b: brfalse.s IL_002d
IL_001d: ldarg.1
IL_001e: ldc.i4.2
IL_001f: beq.s IL_0031
IL_0021: br.s IL_003f
IL_0023: ldc.i4.3
IL_0024: ldarg.1
IL_0025: beq.s IL_0038
IL_0027: br.s IL_003f
IL_0029: ldc.i4.1
IL_002a: stloc.0
IL_002b: br.s IL_0041
IL_002d: ldc.i4.0
IL_002e: stloc.0
IL_002f: br.s IL_0041
IL_0031: ldarg.2
IL_0032: brfalse.s IL_003f
IL_0034: ldc.i4.2
IL_0035: stloc.0
IL_0036: br.s IL_0041
IL_0038: ldarg.2
IL_0039: brfalse.s IL_003f
IL_003b: ldc.i4.1
IL_003c: stloc.0
IL_003d: br.s IL_0041
IL_003f: ldarg.0
IL_0040: stloc.0
IL_0041: ldloc.0
IL_0042: ldfld ""Door.Action System.ValueTuple<Door.DoorState, Door.Action>.Item2""
IL_0047: stloc.2
IL_0048: ldc.i4.3
IL_0049: ldloc.2
IL_004a: beq.s IL_005d
IL_004c: br.s IL_0064
IL_004e: ldc.i4.1
IL_004f: stloc.3
IL_0050: br.s IL_0066
IL_0052: ldc.i4.0
IL_0053: stloc.3
IL_0054: br.s IL_0066
IL_0056: ldarg.2
IL_0057: brfalse.s IL_0064
IL_0059: ldc.i4.2
IL_005a: stloc.3
IL_005b: br.s IL_0066
IL_005d: ldarg.2
IL_005e: brfalse.s IL_0064
IL_0060: ldc.i4.1
IL_0061: stloc.3
IL_0062: br.s IL_0066
IL_0064: ldarg.0
IL_0065: stloc.3
IL_0066: ldloc.3
IL_0067: ret
IL_0042: ret
}"
);
}
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录