函数的返回值存储在哪里

Sas*_*sha 3 c# clr

我读过一些关于堆栈、堆以及它们在程序执行中如何使用的文章。是其中之一。人们总是说,在调用函数时,它的参数以及局部变量都被放置到堆栈中(严格来说这是不正确的,正如 Eric Lippert 在他的文章中所描述的那样,但这不是我现在的问题)。

我的问题是函数的返回值存储在哪里以及如何传递给调用者?没有人说它被放在堆栈上,但仍然没有人说它不是。有人能澄清一下吗?

例如,考虑以下函数:

public DateTime GetTomorrowDate()
{
    return DateTime.Now.AddDays(1).Date;
}
Run Code Online (Sandbox Code Playgroud)

我的理解是它将声明一个局部变量作为返回值是否正确?如果是这样,为什么当函数返回并且堆栈帧被破坏时它没有被破坏?它是否在调用者的堆栈帧中声明(即使调用者没有使用它)?或者它可能存储在寄存器中的某个位置(我不相信这一点,因为对于某些自定义结构可能没有合适大小的寄存器)。

dav*_*pfx 6

有几种策略(我已经使用过)。

  1. 返回值足够小,可以放入寄存器中,并作为为此目的保留的寄存器中的值从函数返回。如果需要,可以扩展到 2 个或更多寄存器。
  2. 返回值作为临时变量创建在调用者的堆栈帧上。然后,对临时值的引用(指针)被压入堆栈,以便返回值充当额外的输出参数。在某些语言中,该变量作为命名变量(“结果”)出现在被调用函数内,而在其他语言中,编译器会生成对该参数的移动。
  3. 创建了两个局部变量,一个在函数内部,一个在函数外部。在函数退出时,该值从一个复制到另一个。
  4. 返回值只是作为额外参数创建的。在该参数中找到的值由调用者在展开堆栈之前取出。
  5. 该值在“特殊”寄存器中返回,例如浮点累加器。
  6. 该值被放置在已知位置(例如任务框架),稍后可以从中检索。

可能还有其他的,但这些是一个好的开始。


我的回答是基于将问题阅读为想要总结常用技术。在 C# 上下文中,它适用于 JIT 生成的代码,但不适用于 CIL 本身。

典型的面向堆栈的 VM 语言(包括 CIL)主要通过在函数返回时将值保留在堆栈上来从函数返回值。参数位于其下方,因此函数返回后需要进行一些堆栈清理。

正如 @eric 所说,很难看出这些信息何时有用。显然,从函数返回大值类型可能会对性能产生影响,但这只是预期的。

CIL 有很好的文档记录,但 JIT 编译和可能的其他机制却没有,这将进一步降低任何此类见解的有用性。