SSCLI声明中某些C++代码中隐藏的注释,指的是String的非托管内部实现。Chars属性:
实际上并没有使用这种方法。JIT将为字符串类上的索引器方法生成代码。
所以。。。这是什么神奇的代码?我理解抖动的全部意义在于,它们在不同的情况下产生不同的代码。但至少,对于现代x64 Windows 7+平台来说,抖动是如何实现的?还是那真的是秘制酱汁?
其他详细信息
不久前,我正在寻找最快的方法来迭代C#中字符串中的各个字符。它是最快的方法,不需要使用不安全的代码或复制内容(通过ToCharArray()
)是内置的字符串索引器,它实际上是对string.Chars属性的调用。就在我的原件里我问了一个问题,是否有人了解索引器的实际工作方式,但尽管Skeet和利珀特,我没有得到任何回应。所以我决定自己深入研究:
停止1:mscorlib
通过使用ildasm检查mscorlib.dll,我们可以看到String::get_Chars(int32 index)
只是一个internalcall
指针(加上一个属性):
.method public hidebysig specialname instance char
get_Chars(int32 index) cil managed internalcall
{
.custom instance void System.Security.SecuritySafeCriticalAttribute::.ctor() = ( 01 00 00 00 )
} // end of method String::get_Chars
正如MethodImplOptions枚举的文档中所指出的,"内部调用是对在公共语言运行库中实现的方法的调用。"2004 MSDN Magazine的一篇文章和SO的一篇帖子都表明,internalcall
名称到非托管实现的映射可以在Shared Source CLI的ecall.cpp中找到
停止2:ecapp.cpp
搜索ecall.cpp的在线副本可以发现get_Chars
是由COMString::GetCharAt
:实现的
FCIntrinsic("get_Chars", COMString::GetCharAt, CORINFO_INTRINSIC_StringGetChar)
停止3:comstring.cpp
comstring.cpp确实包含GetCharAt的实现,从第1219行开始。除了,它前面有这样的评论:
/*==================================GETCHARAT===================================
**Returns the character at position index. Thows IndexOutOfRangeException as
**appropriate.
**This method is not actually used. JIT will generate code for indexer method on string class.
**
==============================================================================*/
首先,请参阅Hans-Passant对关键位的评论。
在早期的.NET(CLR 1和2)中,CLR对String
和StringBuilder
类型有相当大的特殊支持。事实上,这两种类型的工作非常紧密,以至于StringBuilder.ToString
不会将实际字符复制到任何地方,字符串索引器仍然使用特殊的抖动支持从同一内存位置获取字符。我认为String.Chars
的抖动支持最初是必要的,以避免通过堆栈传递索引整数,但从那时起抖动似乎有所改善。
.NET4提供了StringBuilder
(ropes)的不同实现,它不再与处理String
的方式挂钩。(它必须在ToString
期间复制,但附加速度要快得多。)在这些更改之后,
StringBuilder
索引器在大型字符串上被戏剧性地减慢到O(logn)。请参见此处。它从不内联,甚至在短字符串上也不内联String
索引器仍然使用(未公开的)特殊抖动支持。我希望这一个基本上被内联到移位、加法和内存提取中,或者比最近的循环更快的东西