关于尾部调用,我的一点贡献

下文摘自我翻译《Expert .NET 2.0 IL Assembler》第13章中的一节,这本书是IL的权威之作,作者就是IL开发Team的:
尾部调用

尾部调用类似于方法调用(jmp),二者都是放弃当前方法,并将参数传递到尾部调用(跳转)的方法上。然而,由于尾部调用的参数必须在计算堆栈上被显式加载(与跳转不同,尾部调用丢弃了当前方法的堆栈帧[1]stack frame),它保护了栈的框架并可以使用已经被加载的参数),与跳转不同,尾部调用不需要被调用方法的全部签名匹配调用方法的签名;而只要求返回类型是相同的或兼容的。尾部调用在大规模的递归方法实现中是非常有用的;调用方的栈帧在尾部调用的过程中会被丢弃,因此,不管递归有多么的深,栈的溢出都是没有风险的。对于功能性语言来说这是很重要的,它们会使用递归来代替循环。

尾部调用是通过在callcallvirtcalli指令前加上前缀tail.指令来识别的:

l         tail. (0xFE 0x14) 将随后的调用指令标注为尾部调用。该指令不使用参数和栈。和其他前缀指令unaligned.volatite.一样,ILAsm要求该指令与其后随的指令之间至少有一个空格符分隔。

跳转方法和尾部调用的区别在于尾部调用指令对(tail call pair)原则上是可验证的,只要该指令后面紧跟着ret指令(这取决于调用参数的可验证性)。和其他前缀指令一样,跳过前缀并直接转移到前缀指令(如callcallvirtcalli)是非法的。



[1] 译注:stack frame,即堆栈帧,是堆栈中的一块区域,它保存着一个函数的返回地址,和该函数内部使用的局部数据(Local Data),它是由函数入口处的SUB ESP48h之类的语句来建立的。

详细内容参见http://www.zaoxue.com/article/tech-32942.htm




此外,给出尾部调用的几个异常:

0x80131899

Can not pass byref to a tail call.

0x8013189A

Missing ret.

0x8013189B

Void ret type expected for tail call.

0x8013189C

Tail call return type not compatible.

0x8013189D

Stack not empty after tail call.

posted @   包建强  Views(1018)  Comments(2Edit  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
历史上的今天:
2007-03-31 WPF笔记(2.4 Grid)——Layout
2007-03-31 Description of AJAX
2007-03-31 SQL大量数据操作 切身经验总结
2007-03-31 WPF笔记(2.3 StackPanel)——Layout
2007-03-31 The description of GameHall and my program experience for interview
2007-03-31 WPF笔记(2.2 DockPanel)——Layout
2007-03-31 WPF笔记(1.10 绘图)——Hello,WPF!
点击右上角即可分享
微信分享提示