函数调用
在大多数支持块结构的程序设计语言都支持函数或者子程序(函数和子程序的区别在于函数有返回值而子程序没有,在这里我们不区分这两个概念)。在进行函数调用和从函数返回时通常由一个被称为控制栈的运行时刻栈进行管理。每一个活跃的函数在控制栈中都会有一个相对应的活动记录,有时也称为栈帧。活动记录存储着函数调用时传递的参数信息和从函数返回时返回值与控制跳转的信息。
函数的活动记录需要包括下面的信息
- 控制链(control link):指向控制栈中前一个活动记录的指针;
- 访问链(access link):指向源程序中最近的外层块对应的活动记录,用于维护静态作用域(本文中不讨论);
- 返回地址:函数调用结束后被执行的第一条指令地址(本文讨论中将忽略);
- 返回结果地址:存放函数返回值位置的地址;
- 实际参数:函数调用时传递的参数值;
- 局部变量:函数体中声明的局部变量;
- 临时存储区:在函数执行过程中产生的临时结果。
不同语言的不同实现中对上述信息的存放顺序和存放方式可能不一样。在这里我们按照上面说明的顺序来进行讨论。
每当一个函数被调用时,就创建一个相对应的活动记录,并压入控制栈中;而当从一个函数调用结束时,在控制栈中与该函数对应的活动记录(即栈顶的活动记录)就会被弹出控制栈。每个函数所对应的活动记录的大小是不一致的,而堆栈寄存器每次记录的都只是栈顶的活动记录,所以在每个活动记录中需要一个控制链来记录前一个活动记录。
<