Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
5959af0c
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,体验更适合开发者的 AI 搜索 >>
未验证
提交
5959af0c
编写于
12月 07, 2020
作者:
M
msftbot[bot]
提交者:
GitHub
12月 07, 2020
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #49806 from dotnet/merges/release/dev16.9-to-master
Merge release/dev16.9 to master
上级
85bb2da3
a7147fbc
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
182 addition
and
2 deletion
+182
-2
src/Compilers/CSharp/Portable/FlowAnalysis/LocalDataFlowPass.cs
...mpilers/CSharp/Portable/FlowAnalysis/LocalDataFlowPass.cs
+1
-1
src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
+110
-1
src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionPerfTests.cs
...rp/Test/Semantic/Semantics/OverloadResolutionPerfTests.cs
+71
-0
未找到文件。
src/Compilers/CSharp/Portable/FlowAnalysis/LocalDataFlowPass.cs
浏览文件 @
5959af0c
...
...
@@ -30,7 +30,7 @@ internal interface ILocalDataFlowState : ILocalState
/// <summary>
/// A mapping from local variables to the index of their slot in a flow analysis local state.
/// </summary>
protected
readonly
PooledDictionary
<
VariableIdentifier
,
int
>
_variableSlot
=
PooledDictionary
<
VariableIdentifier
,
int
>.
GetInstance
();
protected
PooledDictionary
<
VariableIdentifier
,
int
>
_variableSlot
=
PooledDictionary
<
VariableIdentifier
,
int
>.
GetInstance
();
/// <summary>
/// A mapping from the local variable slot to the symbol for the local variable itself. This
...
...
src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
浏览文件 @
5959af0c
...
...
@@ -116,7 +116,7 @@ public VisitArgumentResult(VisitResult visitResult, Optional<LocalState> stateFo
/// <summary>
/// The inferred type at the point of declaration of var locals and parameters.
/// </summary>
private
readonly
PooledDictionary
<
Symbol
,
TypeWithAnnotations
>
_variableTypes
=
SpecializedSymbolCollections
.
GetPooledSymbolDictionaryInstance
<
Symbol
,
TypeWithAnnotations
>();
private
PooledDictionary
<
Symbol
,
TypeWithAnnotations
>
_variableTypes
=
SpecializedSymbolCollections
.
GetPooledSymbolDictionaryInstance
<
Symbol
,
TypeWithAnnotations
>();
/// <summary>
/// Binder for symbol being analyzed.
...
...
@@ -190,6 +190,11 @@ public VisitArgumentResult(VisitResult visitResult, Optional<LocalState> stateFo
/// </summary>
private
readonly
bool
_isSpeculative
;
/// <summary>
/// Is a method that contains only blocks, expression statements, and lambdas.
/// </summary>
private
readonly
bool
_isSimpleMethod
;
/// <summary>
/// True if this walker was created using an initial state.
/// </summary>
...
...
@@ -380,6 +385,7 @@ protected override void Free()
_returnTypesOpt
=
returnTypesOpt
;
_snapshotBuilderOpt
=
snapshotBuilderOpt
;
_isSpeculative
=
isSpeculative
;
_isSimpleMethod
=
IsSimpleMethodVisitor
.
IsSimpleMethod
(
node
);
if
(
initialState
!=
null
)
{
...
...
@@ -404,6 +410,68 @@ protected override void Free()
}
}
internal
sealed
class
IsSimpleMethodVisitor
:
BoundTreeWalkerWithStackGuard
{
private
bool
_hasComplexity
;
internal
static
bool
IsSimpleMethod
(
BoundNode
?
node
)
{
if
(
node
is
BoundConstructorMethodBody
constructorBody
&&
constructorBody
.
Initializer
is
{
})
{
return
false
;
}
if
(
node
is
BoundMethodBodyBase
methodBody
)
{
var
blockBody
=
methodBody
.
BlockBody
;
var
expressionBody
=
methodBody
.
ExpressionBody
;
node
=
blockBody
;
if
(
node
is
{
})
{
if
(
expressionBody
is
{
})
return
false
;
}
else
{
node
=
expressionBody
;
}
}
var
visitor
=
new
IsSimpleMethodVisitor
();
try
{
visitor
.
Visit
(
node
);
return
!
visitor
.
_hasComplexity
;
}
catch
(
CancelledByStackGuardException
)
{
return
false
;
}
}
public
override
BoundNode
?
Visit
(
BoundNode
?
node
)
{
if
(
node
is
null
)
{
return
null
;
}
if
(
_hasComplexity
)
{
return
node
;
}
if
(
node
is
BoundExpression
)
{
return
base
.
Visit
(
node
);
}
switch
(
node
.
Kind
)
{
case
BoundKind
.
Block
:
case
BoundKind
.
ExpressionStatement
:
case
BoundKind
.
ReturnStatement
:
return
base
.
Visit
(
node
);
}
_hasComplexity
=
true
;
return
node
;
}
}
public
string
GetDebuggerDisplay
()
{
if
(
this
.
IsConditionalState
)
...
...
@@ -2640,6 +2708,37 @@ private void VisitStatementsWithLocalFunctions(BoundBlock block)
var
oldState
=
this
.
State
;
this
.
State
=
state
;
var
oldVariableSlot
=
_variableSlot
;
var
oldVariableTypes
=
_variableTypes
;
var
oldVariableBySlot
=
variableBySlot
;
var
oldNextVariableSlot
=
nextVariableSlot
;
// As an optimization, if the entire method is simple enough,
// we'll reset the set of variable slots and types after analyzing the nested function,
// to avoid accumulating entries in the outer function for variables that are
// local to the nested function. (Of course, this will drop slots associated
// with variables in the outer function that were first used in the nested function,
// such as a field access on a captured local, but the state associated with
// any such entries are dropped, so the slots can be dropped as well.)
// We don't optimize more complicated methods (methods that contain labels,
// branches, try blocks, local functions) because we track additional state for
// those nodes that might be invalidated if we drop the associated slots or types.
if
(
_isSimpleMethod
)
{
_variableSlot
=
PooledDictionary
<
VariableIdentifier
,
int
>.
GetInstance
();
foreach
(
var
pair
in
oldVariableSlot
)
{
_variableSlot
.
Add
(
pair
.
Key
,
pair
.
Value
);
}
_variableTypes
=
SpecializedSymbolCollections
.
GetPooledSymbolDictionaryInstance
<
Symbol
,
TypeWithAnnotations
>();
foreach
(
var
pair
in
oldVariableTypes
)
{
_variableTypes
.
Add
(
pair
.
Key
,
pair
.
Value
);
}
variableBySlot
=
new
VariableIdentifier
[
oldVariableBySlot
.
Length
];
Array
.
Copy
(
oldVariableBySlot
,
variableBySlot
,
oldVariableBySlot
.
Length
);
}
var
previousSlot
=
_snapshotBuilderOpt
?.
EnterNewWalker
(
lambdaOrFunctionSymbol
)
??
-
1
;
var
oldPending
=
SavePending
();
...
...
@@ -2681,6 +2780,16 @@ private void VisitStatementsWithLocalFunctions(BoundBlock block)
_snapshotBuilderOpt
?.
ExitWalker
(
this
.
SaveSharedState
(),
previousSlot
);
if
(
_isSimpleMethod
)
{
nextVariableSlot
=
oldNextVariableSlot
;
variableBySlot
=
oldVariableBySlot
;
_variableTypes
.
Free
();
_variableTypes
=
oldVariableTypes
;
_variableSlot
.
Free
();
_variableSlot
=
oldVariableSlot
;
}
this
.
State
=
oldState
;
_returnTypesOpt
=
oldReturnTypes
;
_useDelegateInvokeParameterTypes
=
oldUseDelegateInvokeParameterTypes
;
...
...
src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionPerfTests.cs
浏览文件 @
5959af0c
...
...
@@ -4,6 +4,7 @@
#
nullable
disable
using
Microsoft.CodeAnalysis.CSharp.Syntax
;
using
Microsoft.CodeAnalysis.CSharp.Test.Utilities
;
using
Roslyn.Test.Utilities
;
using
System.Linq
;
...
...
@@ -375,5 +376,75 @@ public void ArrayInitializationAnonymousTypes()
var
comp
=
CreateCompilation
(
source
);
comp
.
VerifyEmitDiagnostics
();
}
[
Fact
]
[
WorkItem
(
49745
,
"https://github.com/dotnet/roslyn/issues/49745"
)]
public
void
NullableStateLambdas
()
{
const
int
nFunctions
=
10000
;
var
builder
=
new
StringBuilder
();
builder
.
AppendLine
(
"#nullable enable"
);
builder
.
AppendLine
(
"class Program"
);
builder
.
AppendLine
(
"{"
);
builder
.
AppendLine
(
" static void F1(System.Func<object, object> f) { }"
);
builder
.
AppendLine
(
" static void F2(object arg)"
);
builder
.
AppendLine
(
" {"
);
for
(
int
i
=
0
;
i
<
nFunctions
;
i
++)
{
builder
.
AppendLine
(
$" F1(arg
{
i
}
=> arg
{
i
}
);"
);
}
builder
.
AppendLine
(
" }"
);
builder
.
AppendLine
(
"}"
);
var
source
=
builder
.
ToString
();
var
comp
=
CreateCompilation
(
source
);
comp
.
VerifyDiagnostics
();
CheckIsSimpleMethod
(
comp
,
"F2"
,
true
);
}
[
Theory
]
[
InlineData
(
"class Program { static object F() => null; }"
,
"F"
,
true
)]
[
InlineData
(
"class Program { static void F() { } }"
,
"F"
,
true
)]
[
InlineData
(
"class Program { static void F() { { } { } { } } }"
,
"F"
,
true
)]
[
InlineData
(
"class Program { static void F() { ;;; } }"
,
"F"
,
false
)]
[
InlineData
(
"class Program { static void F2(System.Action a) { } static void F() { F2(() => { }); } }"
,
"F"
,
true
)]
[
InlineData
(
"class Program { static void F() { void Local() { } } }"
,
"F"
,
false
)]
[
InlineData
(
"class Program { static void F() { System.Action a = () => { }; } }"
,
"F"
,
false
)]
[
InlineData
(
"class Program { static void F() { if (true) { } } }"
,
"F"
,
false
)]
[
InlineData
(
"class Program { static void F() { while (true) { } } }"
,
"F"
,
false
)]
[
InlineData
(
"class Program { static void F() { try { } finally { } } }"
,
"F"
,
false
)]
[
InlineData
(
"class Program { static void F() { label: F(); } }"
,
"F"
,
false
)]
[
WorkItem
(
49745
,
"https://github.com/dotnet/roslyn/issues/49745"
)]
public
void
NullableState_IsSimpleMethod
(
string
source
,
string
methodName
,
bool
expectedResult
)
{
var
comp
=
CreateCompilation
(
source
);
var
diagnostics
=
comp
.
GetDiagnostics
().
Where
(
d
=>
d
.
Severity
==
DiagnosticSeverity
.
Error
);
diagnostics
.
Verify
();
CheckIsSimpleMethod
(
comp
,
methodName
,
expectedResult
);
}
private
static
void
CheckIsSimpleMethod
(
CSharpCompilation
comp
,
string
methodName
,
bool
expectedResult
)
{
var
tree
=
comp
.
SyntaxTrees
[
0
];
var
model
=
(
CSharpSemanticModel
)
comp
.
GetSemanticModel
(
tree
);
var
methodDeclaration
=
tree
.
GetCompilationUnitRoot
().
DescendantNodes
().
OfType
<
MethodDeclarationSyntax
>().
Single
(
m
=>
m
.
Identifier
.
ToString
()
==
methodName
);
var
methodBody
=
methodDeclaration
.
Body
;
BoundBlock
block
;
if
(
methodBody
is
{
})
{
var
binder
=
model
.
GetEnclosingBinder
(
methodBody
.
SpanStart
);
block
=
binder
.
BindEmbeddedBlock
(
methodBody
,
new
DiagnosticBag
());
}
else
{
var
expressionBody
=
methodDeclaration
.
ExpressionBody
;
var
binder
=
model
.
GetEnclosingBinder
(
expressionBody
.
SpanStart
);
block
=
binder
.
BindExpressionBodyAsBlock
(
expressionBody
,
new
DiagnosticBag
());
}
var
actualResult
=
NullableWalker
.
IsSimpleMethodVisitor
.
IsSimpleMethod
(
block
);
Assert
.
Equal
(
expectedResult
,
actualResult
);
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录