ImageVerifierCode 换一换
格式:DOCX , 页数:5 ,大小:47.63KB ,
资源ID:2465135      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/2465135.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(Chez Scheme 的传说.docx)为本站会员(b****2)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

Chez Scheme 的传说.docx

1、Chez Scheme 的传说Chez Scheme 的传说在上一篇博文的最后,我提到了 Lisp 编译器的问题。由于早期的 Lisp 编译器生成的代码效率普遍低下,成为了 Lisp 失败的主要原因之一。而现在的高性能 Lisp 编译器(比如 Chez Scheme),其实已经可以生成非常高效的代码,甚至可以匹敌 C 程序的速度。如果你看得到我脑子里的东西,就会明白这完全不是吹牛,而是科学的结论。我在这里介绍一下我写 Scheme 编译器的经历,也许你就会从根本上明白为什么我会对此这么自信。这里的介绍其实不止针对函数式语言,而且针对所有语言的编译器。编译器是一种神秘,有趣,又无聊的的程序。说它

2、神秘,是因为只有非常少的人知道如何写出优秀的编译器。这些会写编译器的人,就像身怀绝技的武林高手一样神出鬼没。说它有趣,是因为编译器的技术里面含有大量的“哲学问题”和深刻的理论(比如 partial evaluation)。但为什么又说它无聊呢?因为你一旦掌握了编译器技术里面最精华的原理,就会发现其实说来说去就那么点东西。编译器代码里面的“创造性含量”其实非常低。里面有些固定的“模式”,几十年都不变。这是因为编译器只是一种“工具”,而不是最终的“目的”。它就像做菜的锅一样,只有屈指可数的那几种形状。设计应用程序才是程序员的最终目的。只有应用程序才能有无穷无尽的创造性。这就像厨师用同样的锅,却能做

3、出无穷变化的菜肴来。然而,我并不是说普通程序员不应该学习写编译器。相反,编译器的原理是非常重要的知识。不理解编译原理的应用程序设计者,就像不理解菜锅组成原理的厨师。先来说一说为什么早期的 Lisp 编译器生成的代码效率低下吧。在函数式语言的早期,由于它比普通的语言多了一些表达力强大的构造(比如函数作为值传递),人们其实都不知道如何实现它的编译器。很多 Scheme 的编译器其实只是把 Scheme 编译成 C,然后再调用 C 语言的编译器。Haskell 的编译器 GHC 在早期也是这样的。而且由于 C 编译器生成的汇编代码不完全符合 Haskell 的需求,GHC 里面含有一个 Perl 脚

4、本,专门用于调整这汇编代码的结构。这个 Perl 脚本,由于它的工作方式毫无原则,被叫做 evil mangler。现在这个东西已经被去掉了,但从它曾经的存在你可以看出,其实函数式编译器的技术在早期是相当混沌的。在我看来,早期 Lisp 编译器出现的主要问题,其实在于对编译的本质的理解,以及编译器与解释器的根本区别。解释器之所以大部分时候比编译器慢,是因为解释器“问太多的问题”。每当看到一个构造,解释器就会问:“这是一个整数吗?”“这是一个字符串吗?”“这是一个函数吗?” 然后根据问题的结果进行不同的处理。这些问题,在编译器的理论里面叫做“解释开销”(interpretive overhead

5、)。编译的本质,其实就是在程序运行之前进行“静态分析”,试图一劳永逸的回答这些问题。于是编译后的代码根本不问这种问题,它直接就知道那个位置肯定会出现什么构造,应该做什么事,于是它就直接去做了。早期的 Lisp 编译器,以及现在的很多 Scheme 编译器出现的问题其实在于,它们并没有干净的消除这些问题,甚至根本没有消除这些问题。当我最早学习 Scheme 语言的时候,我发现 Scheme 有太多的“实现”:PLT Scheme(现在叫 Racket), MIT Scheme, Scheme 48, Bigloo, Chicken, Gambit, Guile, . 让人搞不清楚哪一个更好。有些

6、 Scheme 实现显得高级一些,但实际用起来总是感觉不放心,因为你心里总想着,这代码编译出来到底能不能跟 C 语言代码比?这也是我后来开始使用 Common Lisp 的原因,因为 Common Lisp 似乎有挺多高效的编译器(CMUCL,Lispworks,Allegro 等等)。直到有一天,我发现了 Chez Scheme,它改变了我对 Scheme 编译器,以至于整个编译器概念的理解。当时我只下载了 Chez Scheme 的免费版本,叫做 Petite。Petite 与正式版 Chez Scheme 的区别是,它不输出二进制代码,所以你不能把编译后的代码拿去销售。另外出于商业目的,

7、Petite 的出错信息非常的“简约”,以至于有时候你不得不用其它的 Scheme 实现,才能找到 bug 的位置。但是一运行就见分晓,Petite 被作为一个“解释器”直接运行 Scheme 代码,比其他的 Scheme 实现编译后的代码还要快很多倍。Chez Scheme 导致了我命运的改变,我怎么也没有想到,自己最终会见到它的作者 R. Kent Dybvig,并且成为他的学生。我只能说也许一切都是天意吧。第一次见到 Kent 的时候,他安静的对我说,你应该拥有自己的代码,将来有一天,你会发现它的价值。也就是这个 Kent,单枪匹马的创造了 Chez Scheme,世界上唯一的商业 Sc

8、heme 编译器,并且为此成立了自己的公司(Cadence Research Systems)。Chez Scheme 价格不菲,而且不明码实价,它的价格跟项目的大小和公司的规模成正比。有些大公司花重金购买 Chez Scheme 用于一些核心的项目。其中有些公司为了保证这编译器的安全,又花了好几倍的价钱买下了它的源代码。Kent 的公司只有他一个人,不用操心管理,也不用操心销售。所以他过的非常舒服,基本是一个不愁吃穿,不问世事的人。Kent 是我一生中见过的最神秘,最酷的人。他几乎从来不表扬任何人,但也不贬低任何人。从冷漠的言语之中,你仿佛感觉他并不是这个世界上的人。任何人的喜怒与哀乐,傲慢

9、与偏见,蔑视与奉承,全都不能引起他情绪的变化。他的心里有许许多多的秘密,你需要一些技巧才能套出他的真言。他很少发表论文,却把别人的论文全都看得很透。没有人知道他的核心技术,他也从来不在乎别人是否了解他的水平。最让人惊奇的是,没有人知道他叫什么名字!他的全名叫 R. Kent Dybvig,那么 R. 就应该是他的 first name。然而,却从来没有人知道那个 R. 是哪一个名字的简写,所以大家只好叫他的 middle name,Kent。他的照片从来不放在网上,如果你真想知道他长得什么样,我在网上找到一个跟他长得非常相似的人的照片:Chez Scheme 生成的“目标代码”效率之高,我还没

10、有见到任何其它 Scheme 编译器可以与之匹敌。而它的“编译速度”之快,没有任何语言的任何编译器可以相提并论(注意我去掉了“Scheme”这个限定词)。Chez Scheme 可以在 5 秒钟之内完成从头到尾的自我编译。想想编译 GCC 或者 GHC 需要多少时间,你就明白差距了。另外值得一提的是,Chez Scheme 从头到尾都是 Kent 一个人的作品。它的工作原理是从 Scheme 源程序一直编译到机器代码,而不依赖任何其他语言的编译器。它甚至不依赖第三方的汇编器,所有三种体系构架(Intel, ARM, SPARC)的汇编器,都是 Kent 自己写的。为什么这样做呢?因为几乎没有其

11、它人的编译器代码能够达到他的标准。连 Intel 自己给自己的处理器写的汇编器,都不能满足他的要求。如果你上了 Kent 的课,再来看看普通的编译器书籍(比如有名的 Dragon Book),或者 LLVM 的代码,你就会发现 Kent 的水平其实远在这些知名的大牛之上。我为什么可以这么说呢?因为如果你的水平不如这些人的话,你自己都会对这种判断产生怀疑。而如果你超过了别人,他们的一言一行,他们的每一个错误,都像是处于你的显微镜底下,看得一清二楚。这就是为什么有一天我拿起 Dragon Book,感觉它变得那么的幼稚。而其实并不是它变幼稚了,而是我变成熟了。实话实说吧,在编译器这个领域,我觉得

12、Kent 很有可能就是世界的 No.1。如果你不了解 Scheme 的编译器里面有什么东西,也许就会轻视它的难度。Scheme 是比 C 语言高级很多的语言,所以它的编译器需要做比 C 语言的编译器多很多的事情。在 Kent 的编译器课程的前半段,我们其实本质上是在实现一个 C 语言的编译器,把一种基于“S表达式”的中间语言,编译为 X64 汇编代码。在后半学期的课程中,我们才加入了各种 Scheme 的先进功能,比如函数作为值(需要进行 closure conversion 以及 closure 优化),尾递归优化(tail-call optimization),等等。另外,我还自己为它加入

13、了一种非常漂亮的技术,叫做 online partial evaluation。这种技术可以在一个 pass 就完成普通编译器需要好几个 pass 才能完成的优化。在这些先进的优化技术之下,几乎所有的冗余代码都会被编译器消除掉。这些优化的智能程度,在很多方面拥有人类思维没法达到的准确性和深度。如果你的程序没有使用到 Scheme 特有的功能,那么生成的目标代码就会跟 C 语言编译后的代码没有什么两样。比如,如果你的代码没有把函数作为值传递,或者你的函数里面没有“自由变量”,或者你的函数里虽然有自由变量,但是你却没法在函数外部改变它的值,那么生成的代码里面就不会含有“闭包”,也就不会产生多余的内

14、存数据交换。你有时甚至会得到比 C 程序编译之后更好的代码,因为我们的“后端”编译器其实比 GCC,LLVM 之类的 C 编译器先进。Kent 的课程编译器有很好的结构,它被叫做“nanopass 编译器构架”。它的每一个 pass 只做很小的一件事情,然后这些 pass 被串联起来,形成一个完整的编译器。编译的过程,就是将输入程序经过一系列的变换之后,转化为机器代码。你也许发现了,这在本质上跟 LLVM 的构架是一样的。但是我可以告诉你,我们的课程编译器比 LLVM 干净利落许多,处于远远领先的地位。每一节课,我们都学会一个 pass。每一个讲义,都非常精确的告诉你需要干什么。每一次的作业,

15、提交的时候都会经过上百个测试(当然 Kent 不可能把 Chez Scheme 的测试都给我们),如果没有通过就会被拒绝接受。这些测试也可以下载,用于自己的调试。有趣的是,每一次作业我们都需要提交一些自己写的新测试,目的是用于“破坏”别人的编译器。所以我们每次都会想出很刁钻的输入代码,让同学的日子不好过。当然是开玩笑的,这种做法其实大大的提高了我们对编译器测试的理解和兴趣,以及同学之间的友谊。这比起我曾经在 Cornell 选过(然后 drop 掉)的编译器课程,真是天壤之别。在课程的最后,我们做出了一个完整的编译器,它可以把 Scheme 最关键的子集编译到 X64 汇编代码,然后通过 GN

16、U 的汇编器转化成机器代码。在最后的一节课,Kent 对我们的学期做了一个令人难忘的总结。他说:“你们现在写出的这个编译器里面含有很多先进的技术。也许过一段时间再回头看这段代码,你们才会发现它的价值。如果你们觉得自己已经成为了编译器的专家,那我就告诉你们,你们提交的最快的编译器,编译速度比 Chez Scheme 慢了 700 倍。但是不要灰心,我告诉你们哪些地方可以改进”只有极少数的人见到过 Chez Scheme 的源代码,我也没有看见过。但是见到过它的人告诉我,Chez Scheme 里面其实只有很少几个 pass,而不是像我们的课程编译器有 50 个左右的 pass,这节省了很多用于“遍历”代码树所需要的时间。Chez Scheme 只使用了一些非常简单的算法,没有使用论文里很炫很复杂的方法,这也是它速度快的原因之一。比如它的寄存器分配,没有使用通常的“图着色”(graph coloring)方法,而是使用非常简单的一种类似 linear scan 的算法,生成的代码效率却更高。另外

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1