答案在于虚拟机可以对“热函数”进行启发式检测,即执行数百甚至数千次的代码。如果一个函数的执行计数超过了预定的限制,VMs 优化器可能会拾取那段代码并尝试根据传递给函数的参数编译一个优化版本。在这种情况下,它假定您的函数将始终使用相同类型的参数(不一定是相同的对象)调用。
其原因在这个v8 特定指南文档中有详细记录,其中解释了整数与一般数字优化。假设你有:
function add(a, b) { return a + b; }
...并且您总是使用整数调用此函数,可以通过编译一个在 CPU 上进行整数求和的函数来优化此方法,这很快。如果在优化后你给它一个非整数值,那么 VM 会取消优化函数并回退到未优化的版本,因为它不能对非整数执行整数求和,并且函数会返回错误的结果。
在您指定重载单态方法的语言中,您可以通过简单地编译具有不同参数签名的同一方法名称的多个版本,然后自行优化来解决此问题。这意味着您调用不同的优化方法,因为使用不同类型的参数需要您使用不同的重载方法,因此您使用哪种方法没有问题。
您可能认为您可以在 VM 中保留多个优化函数的副本并检查类型以确定要使用的优化编译函数。从理论上讲,如果方法调用之前的类型检查是免费的或非常便宜的话,那将是可行的。在实践中,通常情况并非如此,您可能希望根据实际代码平衡事物以确定最佳权衡阈值。
这是一个更通用的解释,特别是 v8 的优化编译器(来自 Google I/O 2012):
https://youtu.be/UJPdhx5zTaw?t=26m26s
简而言之:一遍又一遍地使用相同类型调用的函数在 JIT 编译器中进行了优化,因此速度更快。