Chez Scheme 的传说Word格式.docx
- 文档编号:15382070
- 上传时间:2022-10-29
- 格式:DOCX
- 页数:5
- 大小:47.63KB
Chez Scheme 的传说Word格式.docx
《Chez Scheme 的传说Word格式.docx》由会员分享,可在线阅读,更多相关《Chez Scheme 的传说Word格式.docx(5页珍藏版)》请在冰豆网上搜索。
但为什么又说它无聊呢?
因为你一旦掌握了编译器技术里面最精华的原理,就会发现其实说来说去就那么点东西。
编译器代码里面的“创造性含量”其实非常低。
里面有些固定的“模式”,几十年都不变。
这是因为编译器只是一种“工具”,而不是最终的“目的”。
它就像做菜的锅一样,只有屈指可数的那几种形状。
设计应用程序才是程序员的最终目的。
只有应用程序才能有无穷无尽的创造性。
这就像厨师用同样的锅,却能做出无穷变化的菜肴来。
然而,我并不是说普通程序员不应该学习写编译器。
相反,编译器的原理是非常重要的知识。
不理解编译原理的应用程序设计者,就像不理解菜锅组成原理的厨师。
先来说一说为什么早期的Lisp编译器生成的代码效率低下吧。
在函数式语言的早期,由于它比普通的语言多了一些表达力强大的构造(比如函数作为值传递),人们其实都不知道如何实现它的编译器。
很多Scheme的编译器其实只是把Scheme编译成C,然后再调用C语言的编译器。
Haskell的编译器GHC在早期也是这样的。
而且由于C编译器生成的汇编代码不完全符合Haskell的需求,GHC里面含有一个Perl脚本,专门用于调整这汇编代码的结构。
这个Perl脚本,由于它的工作方式毫无原则,被叫做evilmangler。
现在这个东西已经被去掉了,但从它曾经的存在你可以看出,其实函数式编译器的技术在早期是相当混沌的。
在我看来,早期Lisp编译器出现的主要问题,其实在于对编译的本质的理解,以及编译器与解释器的根本区别。
解释器之所以大部分时候比编译器慢,是因为解释器“问太多的问题”。
每当看到一个构造,解释器就会问:
“这是一个整数吗?
”“这是一个字符串吗?
”“这是一个函数吗?
”……然后根据问题的结果进行不同的处理。
这些问题,在编译器的理论里面叫做“解释开销”(interpretiveoverhead)。
编译的本质,其实就是在程序运行之前进行“静态分析”,试图一劳永逸的回答这些问题。
于是编译后的代码根本不问这种问题,它直接就知道那个位置肯定会出现什么构造,应该做什么事,于是它就直接去做了。
早期的Lisp编译器,以及现在的很多Scheme编译器出现的问题其实在于,它们并没有干净的消除这些问题,甚至根本没有消除这些问题。
当我最早学习Scheme语言的时候,我发现Scheme有太多的“实现”:
PLTScheme(现在叫Racket),MITScheme,Scheme48,Bigloo,Chicken,Gambit,Guile,...让人搞不清楚哪一个更好。
有些Scheme实现显得高级一些,但实际用起来总是感觉不放心,因为你心里总想着,这代码编译出来到底能不能跟C语言代码比?
这也是我后来开始使用CommonLisp的原因,因为CommonLisp似乎有挺多高效的编译器(CMUCL,Lispworks,Allegro等等)。
直到有一天,我发现了ChezScheme,它改变了我对Scheme编译器,以至于整个编译器概念的理解。
当时我只下载了ChezScheme的免费版本,叫做Petite。
Petite与正式版ChezScheme的区别是,它不输出二进制代码,所以你不能把编译后的代码拿去销售。
另外出于商业目的,Petite的出错信息非常的“简约”,以至于有时候你不得不用其它的Scheme实现,才能找到bug的位置。
但是一运行就见分晓,Petite被作为一个“解释器”直接运行Scheme代码,比其他的Scheme实现编译后的代码还要快很多倍。
ChezScheme导致了我命运的改变,我怎么也没有想到,自己最终会见到它的作者R.KentDybvig,并且成为他的学生。
我只能说也许一切都是天意吧。
第一次见到Kent的时候,他安静的对我说,你应该拥有自己的代码,将来有一天,你会发现它的价值。
也就是这个Kent,单枪匹马的创造了ChezScheme,世界上唯一的商业Scheme编译器,并且为此成立了自己的公司(CadenceResearchSystems)。
ChezScheme价格不菲,而且不明码实价,它的价格跟项目的大小和公司的规模成正比。
有些大公司花重金购买ChezScheme用于一些核心的项目。
其中有些公司为了保证这编译器的安全,又花了好几倍的价钱买下了它的源代码。
Kent的公司只有他一个人,不用操心管理,也不用操心销售。
所以他过的非常舒服,基本是一个不愁吃穿,不问世事的人。
Kent是我一生中见过的最神秘,最酷的人。
他几乎从来不表扬任何人,但也不贬低任何人。
从冷漠的言语之中,你仿佛感觉他并不是这个世界上的人。
任何人的喜怒与哀乐,傲慢与偏见,蔑视与奉承,全都不能引起他情绪的变化。
他的心里有许许多多的秘密,你需要一些技巧才能套出他的真言。
他很少发表论文,却把别人的论文全都看得很透。
没有人知道他的核心技术,他也从来不在乎别人是否了解他的水平。
最让人惊奇的是,没有人知道他叫什么名字!
他的全名叫R.KentDybvig,那么R.就应该是他的firstname。
然而,却从来没有人知道那个R.是哪一个名字的简写,所以大家只好叫他的middlename,Kent。
他的照片从来不放在网上,如果你真想知道他长得什么样,我在网上找到一个跟他长得非常相似的人的照片:
ChezScheme生成的“目标代码”效率之高,我还没有见到任何其它Scheme编译器可以与之匹敌。
而它的“编译速度”之快,没有任何语言的任何编译器可以相提并论(注意我去掉了“Scheme”这个限定词)。
ChezScheme可以在5秒钟之内完成从头到尾的自我编译。
想想编译GCC或者GHC需要多少时间,你就明白差距了。
另外值得一提的是,ChezScheme从头到尾都是Kent一个人的作品。
它的工作原理是从Scheme源程序一直编译到机器代码,而不依赖任何其他语言的编译器。
它甚至不依赖第三方的汇编器,所有三种体系构架(Intel,ARM,SPARC)的汇编器,都是Kent自己写的。
为什么这样做呢?
因为几乎没有其它人的编译器代码能够达到他的标准。
连Intel自己给自己的处理器写的汇编器,都不能满足他的要求。
如果你上了Kent的课,再来看看普通的编译器书籍(比如有名的DragonBook),或者LLVM的代码,你就会发现Kent的水平其实远在这些知名的大牛之上。
我为什么可以这么说呢?
因为如果你的水平不如这些人的话,你自己都会对这种判断产生怀疑。
而如果你超过了别人,他们的一言一行,他们的每一个错误,都像是处于你的显微镜底下,看得一清二楚。
这就是为什么有一天我拿起DragonBook,感觉它变得那么的幼稚。
而其实并不是它变幼稚了,而是我变成熟了。
实话实说吧,在编译器这个领域,我觉得Kent很有可能就是世界的No.1。
如果你不了解Scheme的编译器里面有什么东西,也许就会轻视它的难度。
Scheme是比C语言高级很多的语言,所以它的编译器需要做比C语言的编译器多很多的事情。
在Kent的编译器课程的前半段,我们其实本质上是在实现一个C语言的编译器,把一种基于“S表达式”的中间语言,编译为X64汇编代码。
在后半学期的课程中,我们才加入了各种Scheme的先进功能,比如函数作为值(需要进行closureconversion以及closure优化),尾递归优化(tail-calloptimization),等等。
另外,我还自己为它加入了一种非常漂亮的技术,叫做onlinepartialevaluation。
这种技术可以在一个pass就完成普通编译器需要好几个pass才能完成的优化。
在这些先进的优化技术之下,几乎所有的冗余代码都会被编译器消除掉。
这些优化的智能程度,在很多方面拥有人类思维没法达到的准确性和深度。
如果你的程序没有使用到Scheme特有的功能,那么生成的目标代码就会跟C语言编译后的代码没有什么两样。
比如,如果你的代码没有把函数作为值传递,或者你的函数里面没有“自由变量”,或者你的函数里虽然有自由变量,但是你却没法在函数外部改变它的值,那么生成的代码里面就不会含有“闭包”,也就不会产生多余的内存数据交换。
你有时甚至会得到比C程序编译之后更好的代码,因为我们的“后端”编译器其实比GCC,LLVM之类的C编译器先进。
Kent的课程编译器有很好的结构,它被叫做“nanopass编译器构架”。
它的每一个pass只做很小的一件事情,然后这些pass被串联起来,形成一个完整的编译器。
编译的过程,就是将输入程序经过一系列的变换之后,转化为机器代码。
你也许发现了,这在本质上跟LLVM的构架是一样的。
但是我可以告诉你,我们的课程编译器比LLVM干净利落许多,处于远远领先的地位。
每一节课,我们都学会一个pass。
每一个讲义,都非常精确的告诉你需要干什么。
每一次的作业,提交的时候都会经过上百个测试(当然Kent不可能把ChezScheme的测试都给我们),如果没有通过就会被拒绝接受。
这些测试也可以下载,用于自己的调试。
有趣的是,每一次作业我们都需要提交一些自己写的新测试,目的是用于“破坏”别人的编译器。
所以我们每次都会想出很刁钻的输入代码,让同学的日子不好过。
当然是开玩笑的,这种做法其实大大的提高了我们对编译器测试的理解和兴趣,以及同学之间的友谊。
这比起我曾经在Cornell选过(然后drop掉)的编译器课程,真是天壤之别。
在课程的最后,我们做出了一个完整的编译器,它可以把Scheme最关键的子集编译到X64汇编代码,然后通过GNU的汇编器转化成机器代码。
在最后的一节课,Kent对我们的学期做了一个令人难忘的总结。
他说:
“你们现在写出的这个编译器里面含有很多先进的技术。
也许过一段时间再回头看这段代码,你们才会发现它的价值。
如果你们觉得自己已经成为了编译器的专家,那我就告诉你们,你们提交的最快的编译器,编译速度比ChezScheme慢了700倍。
但是不要灰心,我告诉你们哪些地方可以改进……”
只有极少数的人见到过ChezScheme的源代码,我也没有看见过。
但是见到过它的人告诉我,ChezScheme里面其实只有很少几个pass,而不是像我们的课程编译器有50个左右的pass,这节省了很多用于“遍历”代码树所需要的时间。
ChezScheme只使用了一些非常简单的算法,没有使用论文里很炫很复杂的方法,这也是它速度快的原因之一。
比如它的寄存器分配,没有使用通常的“图着色”(graphcoloring)方法,而是使用非常简单的一种类似linearscan的算法,生成的代码效率却更高。
另外
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Chez Scheme 的传说 传说