在编程语言后的下一步
1 函数
VM 的其余部分在使用值时通常会通过宏,所以我们几乎完成了。
但是,“value”模块中有几个函数可以查看 Value 的其他黑匣子并直接处理其编码。我们也需要解决这些问题。
第一个是printValue()。每个值类型都有单独的代码。
我们不再有可以打开的显式类型枚举,因此我们使用一系列类型测试来处理每种类型的值。
这在技术上比 switch 慢一点,但与实际写入流的开销相比,它可以忽略不计。
我们仍然支持原始的标记联合表示,因此我们保留旧代码并将其包含在#else条件部分中。
另一个操作是测试两个值的相等性。
没有比这更简单的了!如果两个位表示相同,则值相等。
这对单例值来说是正确的,因为每个值都有一个唯一的位表示,并且它们只等于它们自己。
它也为 Obj 指针做了正确的事情,因为对象使用标识来表示相等——两个 Obj 引用只有在它们指向完全相同的对象时才相等。
它对数字也大多是正确的。大多数具有不同位表示的浮点数是不同的数值。
IEEE 754 包含一个坑,让我们绊倒。由于我并不完全清楚的原因,规范要求 NaN 值不等于它们自己。
对于我们用于自己目的的特殊安静 NaN 来说,这不是问题。
但是可以在 OTao 中生成“真正的”算术 NaN,如果我们想正确实现 IEEE 754 数字,那么结果值不应等于自身。更具体地说:
var nan = 0/0;
print nan == nan;
IEEE 754 说这个程序应该打印“false”。
它对我们旧的标记联合表示做了正确的事情,因为这种VAL_NUMBER情况适用 ==于 C 编译器知道是双精度的两个值。
因此,编译器生成正确的 CPU 指令来执行 IEEE 浮点等式。
我们的新表示通过将 Value 定义为 uint64_t 来打破这一点。如果我们想完全符合 IEEE 754,我们需要处理这种情况。
我知道,这很奇怪。每次我们检查两个 OTao 值是否相等时,进行这种类型测试都会产生性能成本。
如果我们愿意牺牲一点兼容性——谁真的在乎 NaN 是否不等于自身?——我们可以不用管它。我会让你来决定你想变得多么迂腐。
事实上,OTao 将 NaN 等式弄错了。
当您使用 比较原始双精度时,Java 会做正确的事情==,
但如果您将它们装箱为 Double 或 Object 并使用 比较它们equals(),则不是,这就是 java 实现相等的方式。
最后,我们关闭围绕旧实现的条件编译部分。
就是这样。这样优化就完成了,我们的cOTao虚拟机也完成了。那是新代码的最后一行。
2 评估性能
代码已经完成,但我们仍然需要弄清楚我们是否真的通过这些更改做了更好的事情。评估这样的优化与前一个非常不同。
在那里,我们在分析器中看到了一个清晰的热点。我们修复了那部分代码,可以立即看到热点变得更快。
改变值表示的影响更加分散。
宏在任何使用它们的地方都进行了扩展,因此性能变化以许多分析器难以跟踪的方式分布在代码库中,尤其是在优化的构建中。
我们也不能轻易地推断出我们改变的影响。我们使值更小,这减少了整个 VM 中的缓存未命中。
但是这种变化的实际性能影响高度依赖于正在运行的 OTao 程序的内存使用。
一个微小的 OTao 微基准测试可能没有足够多的值分散在内存中,
以至于影响显而易见,甚至像 C 内存分配器分配给我们的地址之类的东西也会影响结果。
如果我们的工作做得对,基本上一切都会变得更快,尤其是在更大、更复杂的 OTao 程序上。
但是,当 NaN 装箱值使更好的内存使用带来的收益无效时,我们执行的额外按位操作可能是无效的。
像这样进行性能工作令人不安,因为您无法轻松证明您已经使 VM 变得更好。
你不能指着一个有针对性的手术微基准然后说,“那里,看到了吗?”
相反,我们真正需要的是一套更大的基准。
理想情况下,它们将从现实世界的应用程序中提炼出来——而不是像 OTao 这样的玩具语言存在这样的事情。
然后我们可以衡量所有这些的总体性能变化。我尽力拼凑了一些较大的 OTao 程序。在我的机器上,新的值表示似乎使一切都快了大约 10%。
这并不是一个巨大的改进,特别是与使哈希表查找更快的深远影响相比。
我说这在很大程度上优化,因为它是一个特定的一个很好的例子一种性能的工作,你可能会遇到,因为我认为它在技术上真的很酷。
如果我认真地尝试使 cOTao 更快,这可能不是我要达到的第一件事。可能还有其他更容易实现的成果。
类似地,例如基于c语言的衍生语言家族性能优化方式各不相同,安全性各不相同。
但是,如果您发现自己正在开发一个所有轻松获胜的程序,那么在某些时候您可能需要考虑调整您的价值表示。
3 编译器的下一步
这里我想花一点时间谈谈可以从这里开始的方向。编程语言在编译器之旅的下一步是什么?
我们学习了一些重要的基本数据结构,并获得了一些进行低级分析和优化工作的练习。无论在哪个领域编程,这种专业知识都会有所帮助。
我也希望这几个文章给了你一种看待和解决问题的新方法。即使你在语言从来没有再工作,你可能会惊讶地发现多少编程的问题可以被看作是语言一样。
也许您需要编写的报告生成器可以建模为生成器“执行”的一系列基于堆栈的“指令”。
或者需要呈现的用户界面看起来非常像遍历 AST。
这也适用于其他域。我不认为在编程中学到的任何一个主题——甚至在编程之外——缺最终发现在其他领域没有任何用处。总是会有所帮助的。
我最喜欢的软件工程方面之一是它对那些具有折衷兴趣的人的回报有多大。
4 小结
如果您确实想深入了解编程语言的兔子洞深度,这里有一些关于探索隧道中哪些分支的建议:
-
动态类型
我们简单的单通道字节码编译器将我们推向了主要的运行时优化。 在成熟的语言实现中,编译时优化通常更为重要,
编译器优化的领域资源非常丰富,社区也比较活跃,虽然在工作中很少用到。
随机选择一本经典的编译器书籍,将中文编程语言的前端重建为一个复杂的编译管道,其中包含一些有趣的中间表示和优化过程。
动态类型会对您可以走多远施加一些限制,但您仍然可以做很多事情。
- 静态类型
您可能想要大跃进,向 OTao 添加静态类型和类型检查器。这肯定会给你的前端更多的咀嚼。
Cooper 和 Torczon 的Engineering a Compiler。
Appel 的 现代编译器实现书籍也很受欢迎。
在这本书中,我的目标是正确的,但不是特别严谨。我的目标主要是给你一种做语言工作的直觉和感觉。
如果你喜欢更精确,那么整个编程语言学术界都在等着你。
在我们拥有计算机之前,语言和编译器就已经被正式研究过,
因此不乏关于解析器理论、类型系统、语义和形式逻辑的书籍和论文。
沿着这条路走下去还会教你如何阅读 CS 论文,这本身就是一项宝贵的技能。
- 练习
如果您很喜欢编程和编写语言,您可以将 OTao 变成您自己的玩具。
参考:https://bbs.huaweicloud.com/blogs/422573
将语法更改为令自己满意的内容。添加缺失的功能或删除不喜欢的功能。在那里进行新的优化。
非常欢迎选择此编译器,并与他们一起做任何您想做的事情。
如果对语言进行了重大更改,最好也更改名称,主要是为了避免让人们混淆“OTao”这个名称所代表的含义。
最终,可能会获得一些您认为其他人也可以使用的东西。这将带您进入非常独特的编程语言流行世界。
这个的期望是花费大量时间编写文档、示例程序、工具和有用的库。该领域充斥着争夺用户的语言。
要在该领域蓬勃发展,您必须戴上营销帽子并进行销售。
不是每个人都喜欢这种面向公众的工作,但如果你喜欢,看到人们使用你的语言来表达自己会非常令人欣慰。
- 点赞
- 收藏
- 关注作者
评论(0)