什么是优化参数的协议?

时间:2015-03-22 18:30:36

标签: javascript optimization v8

众所周知,在JavaScript中使用arguments不当可能会导致函数无法优化(请参阅herehere by the end):

function notOptimisable (a, b) {
  // Optimising compiler says: Nope.
  var args = [].slice.call(arguments)
}

然而,到目前为止,没有一个消息来源设法解释为什么这会阻止优化发生

它更令人难以置信,因为我所要做的就是

function optimisable (a, b) {
  // Optimising compiler says: I can do this!
  var args = new Array(arguments.length)
    , i = 0

  // Copy the arguments into an actual array, very carefully...
  for(i; i < args.length; ++i)
     args[i] = arguments[i]
}

和voilá - 我有arguments的副本,它是一个实际数组,可以优化该功能:

node --trace_opt --trace_deopt script.js # Exerpt below

[marking 0x24ba2c0bf0f1 <JS Function notoptimisable (SharedFunctionInfo 0x26b62a724859)> for recompilation, reason: small function, ICs with typeinfo: 3/3 (100%), generic ICs: 0/3 (0%)]
[disabled optimization for 0x26b62a724859 <SharedFunctionInfo notoptimisable>, reason: Bad value context for arguments value]
[failed to optimize notoptimisable: Bad value context for arguments value]
[marking 0x24ba2d0041b1 <JS Function optimisable (SharedFunctionInfo 0x26b62a7247b1)> for recompilation, reason: small function, ICs with typeinfo: 7/7 (100%), generic ICs: 0/7 (0%)]
[optimizing 0x24ba2d0041b1 <JS Function optimisable (SharedFunctionInfo 0x26b62a7247b1)> - took 0.039, 0.164, 0.051 ms]

因此,我问你:

为什么?

  • 哪些技术挑战阻碍了优化的发生?
  • 为什么v8引擎不能简单地返回一个标准的参数数组,就像第二个代码示例显示和优化函数一样?
  • 对于额外的点,为什么arguments只是语言设计视角中的“类似数组”对象(即它有数字键,但它不是数组的后代)并且以某种方式播放在优化过程中的作用?

3 个答案:

答案 0 :(得分:6)

没有不可克服的技术挑战。这只是在Crankshaft中实现arguments对象时做出的快捷决策:仅支持可以轻松避免参数对象实现的情况。

即使Crankshaft支持参数​​对象的实现,结果代码仍然会比不分配参数对象的代码

这只是在10分钟内支持最快案例而不是在10天内支持更慢但更通用的案例的问题。 (10分钟/ 10天是虚数,我只想传达实现复杂程度的差异)。

如果想要支持参数对象实现(并且可能泄漏)的情况,那么需要考虑参数对象和参数之间的别名 - 这会改变如何为这些变量构造SSA表单。由于类似的原因,这也使内联复杂化。

参数对象的更通用的方法应该基于转义分析/分配下沉传递 - 但Crankshaft在实现时没有类似的东西,它仍然需要至少支持一些参数操作的快速路径。

答案 1 :(得分:2)

arguments不是数组,例如,考虑:

function abc(a) {
    arguments[0] = 1;
    console.log(a);
}
abc(0);

这里的问题是arguments[0] = 1的分配神奇地改变了a的值,I.E。 arguments[0] aliases a。它是evalwith导致的同一问题 - 您无法再静态地查看更改的变量以及何时更改。

strict mode下删除了混淆错误,没有技术上的理由说明为什么这不会被优化,但是它可能被认为是不值得的,因为大多数网络都没有首先使用严格模式或删除它以获取生产代码。

答案 2 :(得分:1)

原因可能是因为JavaScript没有实现传统意义上的实际数组。数组更像是具有length属性的JavaScript对象,即{}arguments不是Array的事实是该语言中的设计错误。这可能是优化器出现问题的原因。