

18% speedup by replacing o.f() with (0,o.f)() - surganov
http://mrale.ph/talks/goto2015/

======
TheLoneWolfling
Why does this require JS (to the point of giving a blank page!) for something
that can be trivially done without? A bit of tweaking to the source later, and
I have something readable. Now, about the actual article:

Also:

Can someone explain to me why it has to assume that arr.length could change?
It states it does, but I don't see why. That seems like a pretty obvious
optimization flaw: you should be able to safely assume that something won't
change if the only cases where it could change is if it already has changed.
In other words, why is this:

    
    
        var sum = 0;
        for (var i = 0, L = arr.length;
             i < arr.length;
             ++i) {
          if (arr.length !== L)
            H.throwConcurrentModificationError(arr);
          var item = list[i];
          sum += item;
        }
    

not optimizable to remove the whole business with L and the if check?

Also, this is one of my frustrations with optimizers in general. Far too many
of them end up with global (or at the very least) side-effects of trivial
changes (or worse, changes that shouldn't do anything!), to the point of
making optimization a fool's game. (I optimized this method, but now the
change in function alignment changes cache aliasing such that the program runs
slower. Hey look: A runs substantially faster than B. But if you add a comment
here, B runs faster than A.)

~~~
mraleph
> Why does this require JS (to the point of giving a blank page!) for
> something that can be trivially done without?

This is a slide deck (not a blog post or article) hence its dependence on JS.

(though even blog posts I write usually depend on JS to provide proper syntax
highlighting and diagrams)

> Can someone explain to me why it has to assume that arr.length could change?
> It states it does, but I don't see why.

If you don't know where `throwConcurrentModificationError(arr)` goes then you
don't know what it does, e.g. it can do something like this:

    
    
        H.throwConcurrentModificationError = function (arr) {
          arr.push(10);
        };
    

(contrary to its name - but JITs don't optimize based on names)

That's why JIT has to assume global side effects from the
`throwConcurrentModificationError` call - unless of course it emits an
unconditional deoptimization right before it which is what happens in the (0,
o.f)() case.

~~~
TheLoneWolfling
As I said:

The only case that arr.length could change, and hence the if statement taken,
is if the if statement had already been taken - i.e. arr.length had already
changed. This seems safe to optimize.

It doesn't matter what H.throwConcurrentModificationError is - it can only be
called iff it has already been called. Which means that as soon as you're
through the first loop iteration, you know that arr.length hasn't changed that
loop, and it won't change any other iterations through the loop.

And as for JS - there are plenty of slide decks that work perfectly fine
without, or at the very least degrade gracefully. So that's not a good excuse.

~~~
mraleph
> The only case that arr.length could change, and hence the if statement
> taken, is if the if statement had already been taken - i.e. arr.length had
> already changed.

Fair point. I misread your original comment. To see this you need a more
sophisticated analysis pass than V8 is capable of performing - something
similar in spirit to sparse conditional constant propagation, V8's LICM just
assumes that all blocks are reachable so it takes the union of all possible
side-effects.

> So that's not a good excuse.

I am not making an excuse, I am simply stating a fact: this is a slide deck,
it needs JS to operate. As simple as that. If there is an easy fix - please
send me a PR[1], I will gladly take it

[1]
[https://github.com/mraleph/mraleph.github.com/tree/master/ta...](https://github.com/mraleph/mraleph.github.com/tree/master/talks/goto2015)

------
breakingcups
This was a very, very interesting and entertaining slide deck. Thanks for
taking the time to make this.

The angry face you use reminded me a lot of Ally Brosh's style and made me
laugh out loud.

Love this style.

------
olliej
o.f() and (0, o.f)() have different semantics - the latter is closer to temp =
o.f; temp().

For that reason the optimisers see the code being function-call vs. method-
call. Given the usage of function and method calls are generally different the
compilers make different optimising decisions.

~~~
mraleph
Yes, you are absolutely right - semantics is quite different. But that's not
what changes perf here - the difference comes from whether there is an
explicit property load or a property load is an implicit part of the method
call. This change is also made in the code that never executes during the
benchmark run - which adds to a conundrum.

There is a very V8 / Crankshaft specific thing going on here - slides try to
explain it.

