在MSDN文档的cpblk是一个有点稀疏:
的
cpblk指令将一个数(类型unsigned int32从源地址字节)(类型*,native int或&)到目的地地址(类型*,native int或&).cpblk如果源和目标区域重叠,则未指定行为.
cpblk假设所寻址的源和目标都与机器的自然尺寸对齐.该cpblk指令可以紧接在unaligned.指令之前,以指示源或目标是未对齐的.
好吧,相比其他大容量复制操作,如Array.Copy,Marshal.Copy和Buffer.BlockCopy,我们知道:
这给我留下了一些问题:
native int"非托管指针"还是"托管指针(&)"是否重要?Buffer.BlockCopy仅适用于基本类型,而不是结构,即使它们只包含基本类型)根据/sf/answers/1846607381/钉扎是不必要的,但支持说明是错误的.(我怀疑大型对象堆没有被压缩这是一个过度概括)
ECMA-335也不是很有帮助.那里的指令描述包含相同的措辞并添加
[基本原理:
cpblk用于复制结构(而不是任意字节运行).由CLI分配的所有这些结构自然地与当前平台对齐.因此,生成cpblk指令的编译器不需要知道代码最终是在32位还是64位平台上执行.最终理由 ]
好吧,这听起来应该接受更多的类型Buffer.BlockCopy.但仍然不是任意类型.
也许新发布的.NET核心源代码会有一些答案.
cpblk及其伴星,initblk直接映射到任何本地语言编译器依赖于初始化和复制结构的内在函数.无需等待.NETCore源,您可以从SSCLI20,clr/src/fjit/fjitdef.h中看到它们的语义.一个简单的抖动,将其转换cpblk直接向呼叫memcpy(),initblk来memset().与C编译器相同的内在函数.
当然,不考虑GC,C#和VB.NET编译器根本不使用这些操作码.但是C++/CLI编译器就是一个简单的例子:
using namespace System;
struct s { int a; int b; };
int main(array<System::String ^> ^args)
{
s var = {}; // initblk
s cpy = var; // cpblk
return 0;
}
Run Code Online (Sandbox Code Playgroud)
优化的MSIL:
.method assembly static int32 main(string[] args) cil managed
{
// Code size 34 (0x22)
.maxstack 3
.locals ([0] valuetype s cpy,
[1] valuetype s var)
IL_0000: ldloca.s var
IL_0002: ldc.i4.0
IL_0003: ldc.i4.8
IL_0004: initblk
IL_0006: ldloca.s cpy
IL_0008: ldloca.s var
IL_000a: ldc.i4.8
IL_000b: cpblk
...
}
Run Code Online (Sandbox Code Playgroud)
当前的.NET抖动生成内联代码,其中包含针对小型结构的简单寄存器移动,针对大型结构的REP STOS/MOVS.与Buffer.Memcpy()的作用非常相似.
| 归档时间: |
|
| 查看次数: |
1075 次 |
| 最近记录: |