Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Just to highlight what for me was non-obvious but interesting. It implies that this change in two places made a significant improvement to their performance stats. Basically, the optimizing compiler is finicky about the arguments object especially if it is used out of bounds. Without that knowledge, the change seems non-intuitive. I wonder if this true for all pseudo-arrays?

Old Code:

  var args = Array.prototype.slice.call(arguments, 1);
New Code:

  var l = arguments.length;      
  var args = new Array(l - 1);
  for (var i = 1; i < l; i++) args[i - 1] = arguments[i];


  > especially if it is used out of bounds.
Fortunately in EventEmitter.prototype.emit it was never used out-of-bounds.

  > I wonder if this true for all pseudo-arrays?
Arguments object has a very special semantics. It is specified as an object with getter&setter for each indexed property. If somebody would write some approximation of it in JS it would look like:

    function foo (x, y) {
      var arguments_parody = { 
        get "1" () { return x; }, set "1" (x_) { x = x_; }
        get "2" () { return y; }, set "2" (y_) { y = y_; }
      };
    }
It's a very heavy "pseudo-array" in this sense. And the code above is indeed just a parody, real arguments object is more tightly integrated with the language, e.g. it knows exactly how many arguments were passed smth that you can't emulate in JS (without using arguments object). For more intricacies in http://es5.github.com/#x10.6

What optimizing compiler tries to do is to avoid creating arguments object and rewrite simple uses (simple is defined in the referenced post) to operate directly on the stack instead of creating and passing around real object. I should probably do yet another post about that but now with some assembly (but my battery is running low atm) :-)

Doing something like:

    Array.prototype.slice.call(arguments, 1);
this use is not simple so compiler just gives up. But theoretically compiler could have inlined slice and looked one level deeper to see that.


    > theoretically compiler could have inlined slice
    > and looked one level deeper to see that.
I'd suspect that optimizing Array.prototype.slice.call(arguments, n, m) at the v8 level would yield pretty significant gains, even if no other arguments-object abuse was supported intelligently.

For almost any complicated operation on the arguments, your first step is to convert it (or part of it) to a true Array. Most libraries do that using Array.prototype.slice, in my experience.


Here's a jsperf that tests just the arguments copy via slice, while loop, or for loop: http://jsperf.com/args-copy

In the browsers I tested in, it does indeed seem to be significantly faster to copy the array via a normal loop (in Chrome, Firefox, and WebKit mobile, at least). That said, don't start optimizing everything into for loops unless you've identified the code as a bottleneck. It's not worth the additional complexity for a function that's rarely called.


Interestingly, the change you overlook here is a slight performance hit: http://jsperf.com/arguments-woes/2




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: