答案 0 :(得分:6)
说实话,我认为这主要取决于VM的用途,类似于处理器设计在很大程度上取决于处理器的主要用途。
换句话说,您最好能够确定VM的常见用例场景,以便您可以建立可能需要的功能,并建立那些不太常见的功能。
我当然明白,您可能正在构想一个抽象的,非常通用的虚拟机,可以用作其他编程语言的内部/后端实现吗?
然而,我觉得,重要的是要意识到并强调实际上没有任何事物的“通用理想”实现,即一旦你保持通用和抽象,你将不可避免地面临你需要的情况妥协。
理想情况下,这些妥协将基于您的代码的实际使用场景,因此这些妥协实际上是基于您可以做出的明智的假设和简化,而不会出现问题。
换句话说,我会考虑你的VM的目标是什么? 它是如何主要用于您的愿景的? 你想达到什么目标?
这将帮助您提出要求并帮助您进行简化,以便您可以根据合理的假设设计指令集。
如果您希望您的VM主要由编程语言用于数字处理,那么您可能希望通过提供大量低级原语来支持宽数据类型,从而为数学运算寻找相当强大的基础。
如果另一方面,您将服务器作为OO语言的后端,您将需要考虑优化相应的低级指令(即散列/词典)。
一般情况下,我建议在开始时尽可能保持指令集的简单和直观,并且只有在证明具有它们的位置确实有用(即配置文件和操作码转储)时才添加特殊指令。确实会带来性能提升。因此,这将主要取决于您的VM将拥有的第一批“客户”。
如果您真的非常渴望研究更多涉及的方法,您甚至可以考虑在运行时动态优化指令集,使用模式匹配来查找字节码中常见的操作码,以便派生更抽象的实现,以便您可以使用自定义的,运行时生成的操作码动态转换字节码。
答案 1 :(得分:4)
对于软件性能,如果所有操作码长度相同,则更容易,因此您可以拥有一个巨大的switch语句,而不必检查可能由前面的修饰符操作码设置的各种选项位。
我认为你没有问过的两个问题是编写编程语言的编写器易于编写VM代码,以及编写执行VM代码的解释器的简易性。使用较少的操作码可以更轻松地完成这两项操作。 (但不是太少。例如,如果省略除法操作码,那么你就有机会学习如何编写好的除法函数。好的函数比简单函数要难得多。)
答案 2 :(得分:0)
我更喜欢简约的指令集,因为它可以组合成一个操作码。例如,可以使用256条目跳转表调度由两个4位指令字段组成的操作码。由于调度开销是解释性能的主要瓶颈,因此只增加了因子〜2,因为只需要调度每一条指令。实现简约但有效的指令集的一种方法是累加器/存储设计。
答案 3 :(得分:0)
本质上来说,原子操作代码更少。
但是,如果经常使用某些操作码的组合,则将其添加为一条指令。
例如,许多高级PL具有更简单的“ if”和“ goto”指令,但它们也具有组合的“ while”,“ for”,“ do-while”或“ repeat-until”指示,根据之前的指示。