Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
lwm1986
roslyn
提交
b932a6d1
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,发现更多精彩内容 >>
提交
b932a6d1
编写于
2月 16, 2015
作者:
S
Stephen Toub
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #415 from stephentoub/string_concat_opt
Avoid unnecessary boxing with String.Concat
上级
298bdf88
70d2dee7
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
332 addition
and
0 deletion
+332
-0
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StringConcat.cs
...able/Lowering/LocalRewriter/LocalRewriter_StringConcat.cs
+82
-0
src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStringConcat.cs
...Compilers/CSharp/Test/Emit/CodeGen/CodeGenStringConcat.cs
+250
-0
未找到文件。
src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_StringConcat.cs
浏览文件 @
b932a6d1
...
...
@@ -45,6 +45,10 @@ private BoundExpression RewriteStringConcatenation(CSharpSyntaxNode syntax, Bina
return
RewriteStringConcatInExpressionLambda
(
syntax
,
operatorKind
,
loweredLeft
,
loweredRight
,
type
);
}
// avoid run time boxing and ToString operations if we can reasonably convert to a string at compile time
loweredLeft
=
ConvertConcatExprToStringIfPossible
(
syntax
,
loweredLeft
);
loweredRight
=
ConvertConcatExprToStringIfPossible
(
syntax
,
loweredRight
);
// try fold two args without flattening.
var
folded
=
TryFoldTwoConcatOperands
(
syntax
,
loweredLeft
,
loweredRight
);
if
(
folded
!=
null
)
...
...
@@ -346,5 +350,83 @@ private BoundExpression RewriteStringConcatInExpressionLambda(CSharpSyntaxNode s
return
new
BoundBinaryOperator
(
syntax
,
operatorKind
,
loweredLeft
,
loweredRight
,
default
(
ConstantValue
),
method
,
default
(
LookupResultKind
),
type
);
}
/// <summary>
/// Checks whether the expression represents a boxing conversion of a special value type.
/// If it does, it tries to return a string-based representation instead in order
/// to avoid allocations. If it can't, the original expression is returned.
/// </summary>
private
BoundExpression
ConvertConcatExprToStringIfPossible
(
CSharpSyntaxNode
syntax
,
BoundExpression
expr
)
{
if
(
expr
.
Kind
==
BoundKind
.
Conversion
)
{
BoundConversion
conv
=
(
BoundConversion
)
expr
;
if
(
conv
.
ConversionKind
==
ConversionKind
.
Boxing
)
{
BoundExpression
operand
=
conv
.
Operand
;
if
(
operand
!=
null
)
{
// Is the expression a literal char? If so, we can
// simply make it a literal string instead and avoid any
// allocations for converting the char to a string at run time.
if
(
operand
.
Kind
==
BoundKind
.
Literal
)
{
ConstantValue
cv
=
((
BoundLiteral
)
operand
).
ConstantValue
;
if
(
cv
!=
null
&&
cv
.
SpecialType
==
SpecialType
.
System_Char
)
{
return
_factory
.
StringLiteral
(
cv
.
CharValue
.
ToString
());
}
}
// Can the expression be optimized with a ToString call?
// If so, we can synthesize a ToString call to avoid boxing.
if
(
ConcatExprCanBeOptimizedWithToString
(
operand
.
Type
))
{
var
toString
=
GetSpecialTypeMethod
(
syntax
,
SpecialMember
.
System_Object__ToString
);
return
BoundCall
.
Synthesized
(
syntax
,
operand
,
toString
);
}
}
}
}
// Optimization not possible; just return the original expression.
return
expr
;
}
/// <summary>
/// Gets whether the type of an argument used in string concatenation can
/// be optimized by first calling ToString on it before passing the argument
/// to the String.Concat function.
/// </summary>
/// <param name="symbol">The type symbol of the argument.</param>
/// <returns>
/// true if ToString may be used; false if using ToString could lead to observable differences in behavior.
/// </returns>
private
static
bool
ConcatExprCanBeOptimizedWithToString
(
TypeSymbol
symbol
)
{
// There are several constraints applied here in support of backwards compatibility:
// - This optimization potentially changes the order in which ToString is called
// on the arguments. That's a a compatibility issue if one argument's ToString
// depends on state mutated by another, such as current culture.
// - For value types, this optimization causes ToString to be called on the original
// value rather than on a boxed copy. That means a mutating ToString implementation
// could change the original rather than the copy.
// For these reasons, this optimization is currently restricted to primitives
// known to have a non-mutating ToString implementation that is independent
// of externally mutable state. Common value types such as Int32 and Double
// do not meet this bar.
switch
(
symbol
.
SpecialType
)
{
case
SpecialType
.
System_Boolean
:
case
SpecialType
.
System_Char
:
case
SpecialType
.
System_IntPtr
:
case
SpecialType
.
System_UIntPtr
:
return
true
;
default
:
return
false
;
}
}
}
}
src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStringConcat.cs
浏览文件 @
b932a6d1
...
...
@@ -845,5 +845,255 @@ static void Main()
CompileAndVerify
(
source
,
expectedOutput
:
"(0)(0)(0)(1)(2)(0)(0)(0)(1)(2)"
);
}
[
Fact
]
public
void
ConcatWithSpecialValueTypes
()
{
var
source
=
@"
using System;
public class Test
{
static void Main()
{
const char a = 'a', b = 'b';
char c = 'c', d = 'd';
Console.WriteLine(a + ""1"");
Console.WriteLine(""2"" + b);
Console.WriteLine(c + ""3"");
Console.WriteLine(""4"" + d);
Console.WriteLine(true + ""5"" + c);
Console.WriteLine(""6"" + d + (IntPtr)7);
Console.WriteLine(""8"" + (UIntPtr)9 + false);
Console.WriteLine(c + ""10"" + d + ""11"");
Console.WriteLine(""12"" + c + ""13"" + d);
Console.WriteLine(a + ""14"" + b + ""15"" + a + ""16"");
Console.WriteLine(c + ""17"" + d + ""18"" + c + ""19"");
Console.WriteLine(""20"" + 21 + c + d + c + d);
Console.WriteLine(""22"" + c + ""23"" + d + c + d);
}
}
"
;
var
comp
=
CompileAndVerify
(
source
,
expectedOutput
:
@"a1
2b
c3
4d
True5c
6d7
89False
c10d11
12c13d
a14b15a16
c17d18c19
2021cdcd
22c23dcd"
);
comp
.
VerifyDiagnostics
();
comp
.
VerifyIL
(
"Test.Main"
,
@"
{
// Code size 611 (0x263)
.maxstack 4
.locals init (char V_0, //c
char V_1, //d
bool V_2,
System.IntPtr V_3,
System.UIntPtr V_4)
IL_0000: ldc.i4.s 99
IL_0002: stloc.0
IL_0003: ldc.i4.s 100
IL_0005: stloc.1
IL_0006: ldstr ""a1""
IL_000b: call ""void System.Console.WriteLine(string)""
IL_0010: ldstr ""2b""
IL_0015: call ""void System.Console.WriteLine(string)""
IL_001a: ldloca.s V_0
IL_001c: constrained. ""char""
IL_0022: callvirt ""string object.ToString()""
IL_0027: ldstr ""3""
IL_002c: call ""string string.Concat(string, string)""
IL_0031: call ""void System.Console.WriteLine(string)""
IL_0036: ldstr ""4""
IL_003b: ldloca.s V_1
IL_003d: constrained. ""char""
IL_0043: callvirt ""string object.ToString()""
IL_0048: call ""string string.Concat(string, string)""
IL_004d: call ""void System.Console.WriteLine(string)""
IL_0052: ldc.i4.1
IL_0053: stloc.2
IL_0054: ldloca.s V_2
IL_0056: constrained. ""bool""
IL_005c: callvirt ""string object.ToString()""
IL_0061: ldstr ""5""
IL_0066: ldloca.s V_0
IL_0068: constrained. ""char""
IL_006e: callvirt ""string object.ToString()""
IL_0073: call ""string string.Concat(string, string, string)""
IL_0078: call ""void System.Console.WriteLine(string)""
IL_007d: ldstr ""6""
IL_0082: ldloca.s V_1
IL_0084: constrained. ""char""
IL_008a: callvirt ""string object.ToString()""
IL_008f: ldc.i4.7
IL_0090: call ""System.IntPtr System.IntPtr.op_Explicit(int)""
IL_0095: stloc.3
IL_0096: ldloca.s V_3
IL_0098: constrained. ""System.IntPtr""
IL_009e: callvirt ""string object.ToString()""
IL_00a3: call ""string string.Concat(string, string, string)""
IL_00a8: call ""void System.Console.WriteLine(string)""
IL_00ad: ldstr ""8""
IL_00b2: ldc.i4.s 9
IL_00b4: conv.i8
IL_00b5: call ""System.UIntPtr System.UIntPtr.op_Explicit(ulong)""
IL_00ba: stloc.s V_4
IL_00bc: ldloca.s V_4
IL_00be: constrained. ""System.UIntPtr""
IL_00c4: callvirt ""string object.ToString()""
IL_00c9: ldc.i4.0
IL_00ca: stloc.2
IL_00cb: ldloca.s V_2
IL_00cd: constrained. ""bool""
IL_00d3: callvirt ""string object.ToString()""
IL_00d8: call ""string string.Concat(string, string, string)""
IL_00dd: call ""void System.Console.WriteLine(string)""
IL_00e2: ldloca.s V_0
IL_00e4: constrained. ""char""
IL_00ea: callvirt ""string object.ToString()""
IL_00ef: ldstr ""10""
IL_00f4: ldloca.s V_1
IL_00f6: constrained. ""char""
IL_00fc: callvirt ""string object.ToString()""
IL_0101: ldstr ""11""
IL_0106: call ""string string.Concat(string, string, string, string)""
IL_010b: call ""void System.Console.WriteLine(string)""
IL_0110: ldstr ""12""
IL_0115: ldloca.s V_0
IL_0117: constrained. ""char""
IL_011d: callvirt ""string object.ToString()""
IL_0122: ldstr ""13""
IL_0127: ldloca.s V_1
IL_0129: constrained. ""char""
IL_012f: callvirt ""string object.ToString()""
IL_0134: call ""string string.Concat(string, string, string, string)""
IL_0139: call ""void System.Console.WriteLine(string)""
IL_013e: ldstr ""a14b15a16""
IL_0143: call ""void System.Console.WriteLine(string)""
IL_0148: ldc.i4.6
IL_0149: newarr ""string""
IL_014e: dup
IL_014f: ldc.i4.0
IL_0150: ldloca.s V_0
IL_0152: constrained. ""char""
IL_0158: callvirt ""string object.ToString()""
IL_015d: stelem.ref
IL_015e: dup
IL_015f: ldc.i4.1
IL_0160: ldstr ""17""
IL_0165: stelem.ref
IL_0166: dup
IL_0167: ldc.i4.2
IL_0168: ldloca.s V_1
IL_016a: constrained. ""char""
IL_0170: callvirt ""string object.ToString()""
IL_0175: stelem.ref
IL_0176: dup
IL_0177: ldc.i4.3
IL_0178: ldstr ""18""
IL_017d: stelem.ref
IL_017e: dup
IL_017f: ldc.i4.4
IL_0180: ldloca.s V_0
IL_0182: constrained. ""char""
IL_0188: callvirt ""string object.ToString()""
IL_018d: stelem.ref
IL_018e: dup
IL_018f: ldc.i4.5
IL_0190: ldstr ""19""
IL_0195: stelem.ref
IL_0196: call ""string string.Concat(params string[])""
IL_019b: call ""void System.Console.WriteLine(string)""
IL_01a0: ldc.i4.6
IL_01a1: newarr ""object""
IL_01a6: dup
IL_01a7: ldc.i4.0
IL_01a8: ldstr ""20""
IL_01ad: stelem.ref
IL_01ae: dup
IL_01af: ldc.i4.1
IL_01b0: ldc.i4.s 21
IL_01b2: box ""int""
IL_01b7: stelem.ref
IL_01b8: dup
IL_01b9: ldc.i4.2
IL_01ba: ldloca.s V_0
IL_01bc: constrained. ""char""
IL_01c2: callvirt ""string object.ToString()""
IL_01c7: stelem.ref
IL_01c8: dup
IL_01c9: ldc.i4.3
IL_01ca: ldloca.s V_1
IL_01cc: constrained. ""char""
IL_01d2: callvirt ""string object.ToString()""
IL_01d7: stelem.ref
IL_01d8: dup
IL_01d9: ldc.i4.4
IL_01da: ldloca.s V_0
IL_01dc: constrained. ""char""
IL_01e2: callvirt ""string object.ToString()""
IL_01e7: stelem.ref
IL_01e8: dup
IL_01e9: ldc.i4.5
IL_01ea: ldloca.s V_1
IL_01ec: constrained. ""char""
IL_01f2: callvirt ""string object.ToString()""
IL_01f7: stelem.ref
IL_01f8: call ""string string.Concat(params object[])""
IL_01fd: call ""void System.Console.WriteLine(string)""
IL_0202: ldc.i4.6
IL_0203: newarr ""string""
IL_0208: dup
IL_0209: ldc.i4.0
IL_020a: ldstr ""22""
IL_020f: stelem.ref
IL_0210: dup
IL_0211: ldc.i4.1
IL_0212: ldloca.s V_0
IL_0214: constrained. ""char""
IL_021a: callvirt ""string object.ToString()""
IL_021f: stelem.ref
IL_0220: dup
IL_0221: ldc.i4.2
IL_0222: ldstr ""23""
IL_0227: stelem.ref
IL_0228: dup
IL_0229: ldc.i4.3
IL_022a: ldloca.s V_1
IL_022c: constrained. ""char""
IL_0232: callvirt ""string object.ToString()""
IL_0237: stelem.ref
IL_0238: dup
IL_0239: ldc.i4.4
IL_023a: ldloca.s V_0
IL_023c: constrained. ""char""
IL_0242: callvirt ""string object.ToString()""
IL_0247: stelem.ref
IL_0248: dup
IL_0249: ldc.i4.5
IL_024a: ldloca.s V_1
IL_024c: constrained. ""char""
IL_0252: callvirt ""string object.ToString()""
IL_0257: stelem.ref
IL_0258: call ""string string.Concat(params string[])""
IL_025d: call ""void System.Console.WriteLine(string)""
IL_0262: ret
}
"
);
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录