【问题标题】:Can return throw an exception?可以返回抛出异常吗?
【发布时间】: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

当我删除 trycatch 块时:

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


【解决方案1】:

通常,由于语句中允许的表达式的通用性质,return 语句可能会导致异常 - 通常,表达式可能会导致异常。

知道表达式0 不能抛出,JIT 是否应该优化异常处理?也许,在一个完美的世界里。有人抱怨这个吗?

【讨论】:

    猜你喜欢
    • 2012-07-03
    • 2012-02-09
    • 1970-01-01
    • 1970-01-01
    • 2015-02-13
    • 2013-10-28
    • 1970-01-01
    • 1970-01-01
    • 2016-08-09
    相关资源
    最近更新 更多