【发布时间】:2021-04-03 07:07:16
【问题描述】:
在玩 C# 时,我发现以下 sn-p:
public int F()
{
try
{
return 0;
}
catch (Exception)
{
return -1;
}
}
这会生成以下 asm:
Program.F()
L0000: push ebp
L0001: mov ebp, esp
L0003: push esi
L0004: sub esp, 0x14
L0007: xor eax, eax
L0009: mov [ebp-0x18], eax
L000c: mov [ebp-0x14], eax
L000f: mov [ebp-0x10], eax
L0012: mov [ebp-0xc], eax
L0015: xor esi, esi
L0017: jmp short L0023
L0019: mov esi, 0xffffffff
L001e: call 0x6fb2d4d3
L0023: mov eax, esi
L0025: lea esp, [ebp-4]
L0028: pop esi
L0029: pop ebp
L002a: ret
当我删除 try 和 catch 块时:
public int F()
{
return 0;
}
那么生成的输出是:
Program.F()
L0000: xor eax, eax
L0002: ret
问题
如您所见,JIT(发布)知道它不会返回 -1(您找不到任何会跳转到 return -1 案例的分支),但它确实会为 return 0 生成 try 块案子。问题是return语句可以抛出异常还是为什么JIT会为它生成asm?
注意
相比之下:这是为C++ 输出g++(O2)。
int
f(void *this_) {
try {
return 0;
}
catch(...) {
return -1;
}
}
asm
f(void*):
xor eax, eax
ret
【问题讨论】:
-
返回本身不会抛出异常。当然,您可以在计算要返回的表达式时遇到异常,但这与实际返回无关,因为如果将该表达式分配给变量而不是返回它,它会做同样的事情。
-
@paxdiablo 对,但我在那里返回 0。我可以在这里得到一个例外吗?也许我选错了词组。
-
如果从
catch中删除(Exception)说明符会有什么不同吗? -
我认为抖动编译 try...catch 没有任何特殊原因。即使它只符合 xor + ret 指令,代码的行为仍然符合规范。我想说这只是抖动的实现细节之一的人工制品。
-
也许 JIT 编译器的开发人员不想在这种优化上浪费任何时间,因为围绕这种微不足道的返回的 try-catch 块首先没有意义。对于 C++,这可能是另一回事,因为使用预处理器宏的 return 语句对开发人员来说可能看起来相当复杂,这表明 try-catch 操作系统值得,但在开发人员甚至不知道的预处理阶段。
标签: c# assembly try-catch x86-64