News for hackers. Stuff that matters.
Re:Maybe you don't need Rust and WASM to speed up your JS by mraleph on Monday February 19, 2018 @02:31PM (#16415076)
[Thank you for reading the post! I am glad you enjoyed it]

All optimizations in the post can mostly be divided into three large groups:

1) algorithmic improvements; 2) workarounds for implementation independent, but potentially language dependent issues; 3) workarounds for V8 specific issues;

You need to think about algorithms no matter which language you write in, so we don't need to talk much about the first group. In the post it is represented by sorting improvements (sorting subsequences rather than the whole array) and by discussions of caching benefits (or lack of them there-off).

The second group is represented by a monomorphisation trick: the fact that the performance suffers due to polymorphism is not really a V8 specific issue and it is not even JS specific issue. You can apply this approach across implementations and even languages. Some languages apply it in some form for you under the hood.

The last group is represented by argument adaptation stuff.

Finally an optimization I did to mappings representation (using typed array instead of an object) is an optimization that spans all three groups. It's about understanding limitations and costs of a GCed system as whole.

Now... Why did I choose the title? That's because I think group #3 represents the issue that should and would be mostly fixed over time. While groups 1 and 2 represent universal knowledge that spans across implementations and languages.

Obviously it is up to each developer and each team to choose between spending N rigorous hours profiling and reading and thinking about their JavaScript code, or to spend N hours rewriting their stuff in a language X. What I want is:

a) that everybody was fully aware that the choice even exists; b) language designers and implementors worked together on making this choice less and less obvious - which means working on language features and tools and reducing the need in group #3 optimizations.

Re:Maybe you don't need Rust and WASM to speed up your JS by vanderZwan on Monday February 19, 2018 @05:07PM (#16416144)
> monomorphisation trick

Here's a crazy thing I recently learned: apparently monomorphism isn't just "object with identical keys", apparently (at least in Chrome), the order in which you declare those keys matters. According to this presentation from 2015[0], adjusting the following lines in the Octane/Splaytree benchmark so that node.left and node.right are always assigned in the same order resulted in 15% better performance:

    var node = new SplayTree.Node(key, value);
    if (key > this.root_.key) {
      node.left = this.root_;
      node.right = this.root_.right;
      ...
    } else {
      node.right = this.root_;
      node.left = this.root_.left;
      ...
    }
Now, I assume that this out-of-order thing was actually done on purpose, to benchmark how the JIT handles code like this. Further evidence for that is that the SplayTree constructor[1] does not feature a left and right key either:

    SplayTree.Node = function(key, value) {
      this.key = key;
      this.value = value;
    };
Still, I wouldn't be surprised if it was common for real-life code to accidentally have objects that should have the same hidden class end up with different ones because of this.

[0] http://mp.binaervarianz.de/fse2015_slides.pdf

[1] https://github.com/chromium/octane/blob/master/splay.js#L390

Re:Maybe you don't need Rust and WASM to speed up your JS by ridiculous_fish on Monday February 19, 2018 @05:32PM (#16416293)
Yes, this is because the JS spec requires that object keys are iterated in insertion order (with a bizarre exception for arrays).
Re:Maybe you don't need Rust and WASM to speed up your JS by vanderZwan on Monday February 19, 2018 @06:55PM (#16416759)
Ah, I guess that explains it. Although that does not require the engine to have under-the-hood layout respect that, does it? They could just as easily choose to keep the memory layout in the same order.

Although I suppose you're already required to have two separate hidden classes to distinguish these two kinds of objects anyway.

> with a bizarre exception for arrays

Wow, you weren't joking with how bizarre this gets:

    var a = {};
    var b = {};
    a.a = 0;
    a.b = 1;
    a[0] = 0;
    a[1] = 1;
    b.b = 1;
    b.a = 0;
    b[1] = 1;
    b[0] = 0;
    Object.keys(a); // Array [ "0", "1", "a", "b" ]
    Object.keys(b); // Array [ "0", "1", "b", "a" ]
PS: Thanks for making a great shell :)
Re:Maybe you don't need Rust and WASM to speed up your JS by sayrer on Monday February 19, 2018 @08:42PM (#16417237)
Prior to Chrome's release, browsers preserved insertion order for numeric keys as well (but this was not in the ES3 spec).

Chrome/V8's team found they could get substantial performance improvements by diverging from the de facto standard, without too much of a cost to web compatibility.

Re:Maybe you don't need Rust and WASM to speed up your JS by deathanatos on Tuesday February 20, 2018 @12:55AM (#16418148)
TIL. For those like me for which this is new, this was apparently a change in the ES 2015 / ES 6 version of the standard.

See: https://stackoverflow.com/questions/5525795/does-javascript-...

The order is only sometimes guaranteed, of course, because JavaScript. (But critically, for this discussion, it is important that it is sometimes guaranteed, because it forces that information to be stored by the VM.)

Re:Maybe you don't need Rust and WASM to speed up your JS by vanderZwan on Tuesday February 20, 2018 @06:58AM (#16419688)
I feel so justified in adding this guard in my compression pre-processor[0] code, even though I never had a bug without it:

    // the keys of an object
    export function keysOf(obj) {
      let keys = Object.keys(obj);
      keys.sort();
      return oneOf(keys);
    }
Context: the rest of the code takes an object representing a schema, and creates two functions. One that can turn any object fitting that schema into an array, with positions indicating which key they originally belonged to, and another one that can reverse the process.

Could this also explain why I have no consistent order of properties when viewing state with the Redux dev-tools? Instead of Object.assign I use my own simplified merge code[1]. Maybe if I also make that use a sorted set of keys, the devtools will become more consistent in their presentation (and it might result in more consistent hidden classes too).

[0] https://github.com/linnarsson-lab/loom-viewer/blob/master/cl...

[1] https://github.com/linnarsson-lab/loom-viewer/blob/master/cl...

Re:Maybe you don't need Rust and WASM to speed up your JS by pdpi on Tuesday February 20, 2018 @08:53AM (#16420276)
Wait what? Since when? That wasn’t the case at all 5 or 6 years ago (I got bitten in the arse by Rhino not implementing it that way)
Re:Maybe you don't need Rust and WASM to speed up your JS by epmatsw on Tuesday February 20, 2018 @10:33AM (#16421073)
Most browsers already did, and some (not all) of the ES2015 stuff requires property ordering. Probably easier to just keep everything ordered since it could be needed by those methods.
Re:Maybe you don't need Rust and WASM to speed up your JS by zbentley on Monday February 19, 2018 @03:02PM (#16415288)
> Some languages apply it in some form for you under the hood.

I suspect some respondents will say, or believe, that this falls under the category of "you have to know the VM/runtime intimately to get good performance".

I don't think that's true. If you know the general problems with polymorphic call sites, you can (in JS and many other languages) check to see if the runtime is applying optimizations of this kind by being explicit. If it helps, you can get a free optimization by setting explicit arity/dispatch just because you happened to know about the issues surrounding polymorphic dispatch. That's a case of fundamental knowledge speeding up/improving your progress; not a case of "you need to know the VM guts like the back of your hand to make code fast".

Re:Maybe you don't need Rust and WASM to speed up your JS by TAForObvReasons on Monday February 19, 2018 @10:47PM (#16417705)
Ultimately, much of the enthusiasm over WASM, like ASM.JS, is rooted in the idea that it's extremely difficult to improve JS engine performance. ASM.JS used certain conventions to essentially create a "language within JS", while WASM is a new language altogether. The goal was the same in both cases: construct a language that is easier to optimize and make the end users conform.

The key takeaway of your commentary on asm.js five years ago (http://mrale.ph/blog/2013/03/28/why-asmjs-bothers-me.html) is the same as the key takeaway from this post: we haven't reached the end of JS engine performance improvements, and if we apply the same rigor to JS development that we apply to C++ or C or Rust or some other language the results are definitely surprising!