Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Performance penalty for undefined arguments

I quite often have optional arguments in functions, but some testing is showing a huge performance hit for them in firefox and safari (70-95%). Strangely, if I pass in the literal value undefined then there is no penalty. What could be happening here? I wouldn't have thought that it was a scope chain issue as they are inherently local to the function. Am I to start passing undefined into every optional argument?

jsPerf: http://jsperf.com/function-undefined-args/2

like image 578
robC Avatar asked Sep 30 '12 15:09

robC


2 Answers

For a function like this:

function threeArgs(x, y, z) {
  return x + y + z;
}

that's called like this:

threeArgs(1, 2, 3);

the optimizer is free to make the choice to generate no code at all. It's fairly easy for it to determine that there are no side effects, because the function simply references its parameter values and returns the result of a simple expression. Since the return value is ignored, there's no reason for the runtime to do anything at all.

Beyond that, if the code were:

something += threeArgs(1, 2, 3);

the optimizer might decide to generate code roughly equivalent to:

something += 6;

Why? Because the call was made with numeric constants, and it can safely fold those at code generation time. It might be conservative on that, because numbers are weird, but here they're all integers so it could well do this. Even if it didn't, it could safely inline the function:

something += 1 + 2 + 3;

When there's a parameter missing, however, it may be that the optimizers bail out and generate a real function call. For such a simple function, the overhead of the function call could easily account for a large difference in performance.

By using variables instead of constants in a test, and by actually using the return value of the function, you can "confuse" the optimizer and keep it from skipping the call or pre-computing the result, but you can't keep it from inlining. I still think that your result is interesting for that reason: it exposes the fact that (as of today anyway) those optimizers are sensitive to the way that functions are invoked.

like image 127
Pointy Avatar answered Nov 15 '22 14:11

Pointy


I think what could explain the performance difference is the way arguments are passed to a function object: via the arguments object. When not passing any arguments, JS will start by scanning the arguments object for any of the given arguments, when those are undefined, The arguments prototype chain will be scanned, all the way up to Object.prototype. If those all lack the desired property, JS will return undefined. Whereas, passing undefined explicitly, sets it as a property directly on the arguments object:

function foo(arg)
{
    console.log(arguments.hasOwnProperty('0'));
}
foo();//false'
foo('bar');//true
foo(undefined);//true

I gather that's the reason why passing undefined explicitly tends to be faster.

like image 22
Elias Van Ootegem Avatar answered Nov 15 '22 13:11

Elias Van Ootegem