Search code examples
javascriptoptimizationv8

What's the deal with optimising arguments?


It is a known fact that using arguments improperly in JavaScript may result in a function not being optimisable (see here and here by the end):

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

However, none of the sources have so far managed to explain why this prevents the optimisation from happening.

It is even more mind-boggling as all I have to do is

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]
}

and voilá - I have a copy of arguments that is an actual array and the function can be optimised:

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]

Thus, I ask thee:

Why?

  • What technical challenges prevent the optimisation from taking place?
  • Why can't the v8 engine simply return a standard array of arguments, just like the second code sample shows and optimise the function?
  • For extra points, why is the arguments only an "array-like" object from the language design perspective (i.e. it has numeric keys, but it is not a descendant of Array) and does that somehow play a role in the optimisation process?

Solution

  • There are no insurmountable technical challenges. It was just a shortcut decision made during implementation of arguments object in Crankshaft: to support only cases where arguments object materialization can be easily avoided.

    Even if Crankshaft supported materialization of arguments object the resulting code would still be slower than code that does not allocate arguments object.

    It's just a question of supporting the fastest case in 10 minutes vs. supporting slower, but more generic case, in 10 days. (10 minutes / 10 days are imaginary numbers, I am just trying to convey the difference in scale of the implementation complexity).

    If one wants to support the case when arguments object is materialize (and potentially leaks) then one needs to account for aliasing between arguments object and parameters - which changes how SSA form is constructed for these variables. This also complicates inlining for similar reasons.

    A more generic approach to arguments object should have been based on the escape analysis / allocation sinking pass - but Crankshaft did not have anything like that when it was implemented and it still needed to support at least some fast path for arguments manipulation.