Why are unexecuted statements slowing down my functions?

JavascriptPerformance

Javascript Problem Overview


I have created four different functions, like this:

var normal = function() {
    return;
};
var control = function() {
    return;
    alert("Hello, world!");
};
var withArguments = function() {
    return;
    arguments;
};
var withEval = function() {
    return;
    eval("");
};

Since they all just do nothing and immediately return, I would expect all of them to have the same speed. But, after testing it on jsPerf, I find that normal and control execute about the same, but withArguments and withEval execute much more slowly.

Why would these unexecuted statements have any performance impact? Since they're never executed, how is it possible for them to have any effect?

Javascript Solutions


Solution 1 - Javascript

In short, calling eval inside of a function and being able to access the arguments array both use extra set-up during function invocation. If it is known that neither arguments nor eval will be executed, this extra set-up can be skipped.

The compiler does not attempt to predict whether or not the arguments array will actually be accessed or whether eval will actually be called, it only checks whether or not they exist in the function.

arguments

It is more expensive during runtime to invoke a variadic function that uses the arguments object than a "normal" function that doesn't use the arguments object.

The extra steps required to bind the execution environment when the arguments object is declared are specified in §10.6 of the ECMA-262 standard. Creating the arguments object is a somewhat expensive 15-step process. Basically, arguments has to be populated with the passed-in arguments, and the .caller and .callee properties have to be created.

The standard says that the arguments object should be created when a function enters its execution context, unless there is already a parameter, variable, or function declared inside the function named arguments.

For purposes of optimization, most browsers do not actually create the arguments object unless the function actually uses it somewhere (even after a return). This is why you see a performance hit when arguments is referenced, even when lines containing it are never executed.

eval

Entering eval code, as specified in §10.4.2 of the ECMA-262 standard, requires creating a special execution context. Basically, it has to bind all the properties of the calling function's execution context to the eval context.

If there are multiple evals called in one function, they will basically both be doing the same process twice. For optimization, if browsers detect that there is an eval in the function (even after a return), it pre-populates this new execution context that every eval can use, so that it doesn't need to be recreated multiple times.


Note that these optimizations are browser dependent and not required by the standard, so some browsers might not actually perform the optimizations described, or they might do things differently.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDanielView Question on Stackoverflow
Solution 1 - JavascriptPeter OlsonView Answer on Stackoverflow