什么是x86最快的虚拟机设计?
-
10-07-2019 - |
题
我将在x86中实现虚拟机,我想知道哪种设计会产生最佳效果。我该怎样专注于挤出果汁?我将在x86程序集中实现整个虚拟机。
我没有太多指示,我可以选择他们的表格。这些指令直接在块中投射到smalltalk的语法中。我给出了我想到的指令设计:
^ ... # return
^null # return nothing
object # address to object
... selector: ... # message pass (in this case arity:1 selector: #selector:)
var := ... # set
var # get
我正在考虑的那种VM:
mov eax, [esi]
add esi, 2
mov ecx, eax
and eax, 0xff
and ecx, 0xff00 # *256
shr ecx, 5 # *8
jmp [ecx*4 + operations]
align 8:
operations:
dd retnull
dd ret
# so on...
retnull: # jumps here at retnul
# ... retnull action
ret:
# ... ret action
#etc.
不要开始问为什么我还需要另一个虚拟机实现。解释性例程不是您在需要时随时获取的库存内容。您在其他地方提出的大多数虚拟机都会考虑性能成本而实现可移植性。我的目标不是可移植性,我的目标是性能。
完全需要这个解释器的原因是因为smalltalk块最终没有得到同样的解释:
A := B subclass: [
def a:x [^ x*x]
clmet b [...]
def c [...]
def d [...]
]
[ 2 < x ] whileTrue: [...]
(i isNeat) ifTrue: [...] ifFalse: [...]
List fromBlock: [
"carrots"
"apples"
"oranges" toUpper
]
我需要来自解释例程的真正好处,即选择上下文来读取程序。当然,好的编译器应该在大多数情况下编译明显的情况,如:'ifTrue:ifFalse'或'whileTrue:'或列表示例。对翻译的需求不仅仅会消失,因为你总是可能遇到一个你不能确定这个区块能得到你期望的治疗的情况。
解决方案
我看到这里有一些关于可移植性的混淆,所以我觉得有必要澄清一些问题。这些是我的拙见,所以你当然可以自由地反对他们。
我假设你来到 http://www.complang.tuwien.ac .at / forth / threading / 如果你认真考虑写VM,那么我不会详述所描述的技术。
已经提到过,针对VM有一些优势,例如减小代码大小,降低编译器复杂性(通常转换为更快的编译速度),可移植性(请注意,VM的重点是语言的可移植性 ,因此VM本身不可移动并不重要。)
考虑到示例的动态特性,您的VM将比其他更受欢迎的VM更像 JIT编译器。所以,尽管S.Lott在这种情况下错过了这一点,他提到的Forth非常在现场。如果我要为非常动态的语言设计VM,我会将解释分为两个阶段;
-
生产者阶段,根据需要查询AST流并将其转换为更有意义的形式(例如,取一个块,决定是立即执行还是存储在某个地方以便以后执行)可能引入新的令牌。基本上,您可以恢复在此处解析时可能丢失的上下文敏感信息。
-
消费者阶段从1获取生成的流并像其他任何机器一样盲目地执行。如果你喜欢它,你可以推送一个存储的流,而不是跳过指令指针。
醇>
正如你所说,只是模仿该死的处理器如何以另一种方式工作,并不能达到你所需要的任何动力(或任何其他值得一试的功能,如安全性)。否则,你将编写一个编译器。
当然,您可以在第1阶段添加任意复杂的优化。
其他提示
如果您想要一些非常快的东西,请尝试使用 LLVM 。它可以从高级程序描述为大多数处理器生成本机代码。您可以使用自己的汇编语言,也可以生成跳过汇编阶段的llvm结构,具体取决于您最方便的内容。
我不确定它对你的问题是否是最好的,但如果我做一些无法用程序其余部分编译的性能关键执行代码,那肯定是我会使用的。
解释器的重点是可移植性,大部分时间都是如此。我能想到的最快的方法是直接在内存中生成x86代码,就像JIT编译器那样,但是,当然,你再也没有解释器了。你有一个编译器。
但是,我不确定在汇编程序中编写解释器会给你带来最佳性能(除非你是汇编程序大师并且你的项目范围非常有限)。使用更高级别的语言可以帮助您专注于更好的算法,例如符号查找和寄存器分配策略。
您可以使用未编码的指令集加速您的调度例程:
mov eax, [esi]
add esi, 4
add eax, pOpcodeTable
jmp eax
应该有开销<!> lt; cpu的每个调度的4个周期<!> gt;奔腾4.
另外,出于性能原因,最好在每个原始例程中增加ESI(IP),因为增量可能与其他指令配对的可能性很高:
mov eax, [esi]
add eax, pOpcodeTable
jmp eax
~2-2气柱。
我不得不问,为什么要创建一个专注于性能的虚拟机?为什么不直接编写x86代码?什么都不可能更快。
如果您需要非常快速解释语言,请查看 Forth 。他们的设计非常整洁,很容易复制。
如果你不喜欢JIT,你的目标不是便携性。我想您可能会对Google NativeClient 项目感兴趣。他们做静态分析师,沙盒等。它们允许主机执行RAW x86指令。