MSIL:多余的分支
考虑这个 C# 片段:
static string input = null;
static string output = null;
static void Main(string[] args)
{
input = "input";
output = CallMe(input);
}
public static string CallMe(string input)
{
output = "output";
return output;
}
使用 Reflector 进行反汇编显示:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 8
L_0000: nop
L_0001: ldstr "input"
L_0006: stsfld string Reflector_Test.Program::input
L_000b: ldsfld string Reflector_Test.Program::input
L_0010: call string Reflector_Test.Program::CallMe(string)
L_0015: stsfld string Reflector_Test.Program::output
L_001a: ret
}
.method public hidebysig static string CallMe(string input) cil managed
{
.maxstack 1
.locals init (
[0] string CS$1$0000)
L_0000: nop
L_0001: ldstr "output"
L_0006: stsfld string Reflector_Test.Program::output
L_000b: ldsfld string Reflector_Test.Program::output
L_0010: stloc.0
L_0011: br.s L_0013
L_0013: ldloc.0
L_0014: ret
}
令我困惑的是:
L_0010: stloc.0
L_0011: br.s L_0013
L_0013: ldloc.0
它存储项目,分支到下一行(无论如何都会执行),然后再次加载它。
是否有一个原因?
Consider this C# snippet:
static string input = null;
static string output = null;
static void Main(string[] args)
{
input = "input";
output = CallMe(input);
}
public static string CallMe(string input)
{
output = "output";
return output;
}
Dissassembling using Reflector shows:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 8
L_0000: nop
L_0001: ldstr "input"
L_0006: stsfld string Reflector_Test.Program::input
L_000b: ldsfld string Reflector_Test.Program::input
L_0010: call string Reflector_Test.Program::CallMe(string)
L_0015: stsfld string Reflector_Test.Program::output
L_001a: ret
}
.method public hidebysig static string CallMe(string input) cil managed
{
.maxstack 1
.locals init (
[0] string CS$1$0000)
L_0000: nop
L_0001: ldstr "output"
L_0006: stsfld string Reflector_Test.Program::output
L_000b: ldsfld string Reflector_Test.Program::output
L_0010: stloc.0
L_0011: br.s L_0013
L_0013: ldloc.0
L_0014: ret
}
The piece that puzzles me is:
L_0010: stloc.0
L_0011: br.s L_0013
L_0013: ldloc.0
It stores the item, branches to the next line (which would have been executed anyway) and then loads it again.
Is there a reason for this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这只发生在 Debug 中,不会发生在 Release 中。 我怀疑它在调试过程中提供帮助。 它也许允许您在语句中间插入断点并查看返回值。
请注意,发布版本有更简洁的 IL:
This only happens in Debug, not in Release. I suspect its to assist during debugging. It perhaps allows you to chuck breakpoints mid statement and see the return value.
Note the release version has much more concise IL:
我的猜测是,这是用于执行 return 语句的样板代码,编译器执行无条件跳转到最后一行,并在执行 ret 之前将返回值加载到寄存器中。 JIT 会更好地优化它,我认为编译器不会费心做任何优化。
My guess is that this is boilerplate code for executing a return statement, the compiler executes an unconditional jump to the last line, and loads the return value into a register before executing the
ret
. The JIT will optimise it better, I think the compiler doesn't bother doing any optimisations.