2

这根本不是一个真正的 Haskell 问题,但我想有很多追随 Haskell 标签的人会知道这个问题的答案......

我目前正在努力思考如何将函数的输入输出以及局部变量临时值都保存在同一个堆栈上,但最终在退出时得到正确的堆栈布局。

通常堆栈提供 Push 和 Pull 操作,它们仅修改最顶部的堆栈项。有时,您还可以随机读取堆栈下方的项目。(这解释了如何将变量保留在那里并随机访问它们。)但通常更改堆栈大小的唯一方法是从其中拉出项目。如果您想将项目保留在堆栈顶部并删除其下方的内容,那并不是很好。

真正的编译器是如何做这些事情的?

4

2 回答 2

2

调用堆栈可以只在参数所在的空间之前为返回值保留空间,然后是局部变量。这就是为什么知道类型有助于确定保留空间的大小。或者,在像 Lisp 这样的动态语言中,指向装箱值的指针会放在那里。它只是特定函数调用协议的一部分。

顺便说一句,带有闭包的语言中的运行时堆栈通常是一棵树(参见“Funarg 问题”)。

于 2013-03-16T12:48:12.507 回答
2

我不能直接与 Haskell 交谈,但一般来说,应用程序二进制接口(或 ABI)的工作是指定数据如何传入和传出函数(称为调用约定)。根据调用约定和数据的大小,您提到的部分或全部内容可能存储在寄存器(甚至是全局)而不是堆栈中。此外,调用函数的返回地址和可能的某些处理器状态也将存储在堆栈中。

OS X IA-32 Function Calling Conventions为例。堆栈布局:

OS X IA-32 堆栈约定

在这种调用约定中,返回值通常存储在寄存器中

于 2013-03-16T13:04:45.727 回答