Hacker News new | comments | ask | show | jobs | submit login
JavaScript Engine Fundamentals: Shapes and Inline Caches (mathiasbynens.be)
87 points by mariuz 8 months ago | hide | past | web | favorite | 8 comments

Hidden classes and inline caching are very clever ideas. The massive amount of research and work put into making a language such as JavaScript execute faster is impressive.

The problem in my opinion is that not all JavaScript code will be efficiently optimized by these techniques. Some JavaScript code still gets frequently deoptimized, or optimized to a lesser extent.

The way to prevent that is to learn about these optimizations, which change often and in undocumented ways, making your code perform very differently across versions.

Because of this, I found the topic of JavaScript performance to be full of leaky abstractions (for the JavaScript user). Optimizing JavaScript in practice can be very, very hard.

In the past maintainers of the major JS runtimes (v8, etc) have stated they avoid documenting performance and optimization tips, because people build code around them and as a result the engine maintainers can't make fundamental changes without regressing performance of those apps. With how widely some JS libraries get distributed, you can imagine how this becomes a problem. It's a nasty situation.

If the difference between a game running at 30fps and 60fps is using weird optimizations to compensate for quirks in v8 and spidermonkey, you better believe I'm going to optimize for them. But then script runtime changes later make my performance tank when other (originally slower) pieces of code speed up.

One thing I've noticed is that in the past, performance advice was given for specific engines (e.g. V8/crankshaft). Nowadays, if any performance advice is given, it's applicable to all major JavaScript engines, and in general the advice is for developers to write "idiomatic JavaScript", leaving the optimization to the engines.

There's a question of what came first there.

I have a feeling those optimizations apply to all engines because they applied to V8, and maintainers of the other engines attempted to match their performance since so many were coding for performance on V8 only.

When coding JS, I've always tried to optimize based on my experience with multiple languages ... the usual culprits, like keeping the operations inside loops to a minimum, using native functions whenever possible, etc.

So I assume that the 'universal' speed tips apply to JS as well. So far - when I've refactored for speed gains - they have.

Optimizing JavaScript in practice can be very, very hard.

This is a very good observation. I think we're getting to the point where designers of languages and programming environments should start paying attention to the programmer cost/benefit trade-offs around optimization. It doesn't matter what language it is, if performance is critical, and your application is well used, you will get to the point where you'll have to optimize.

Optimizing a managed language with garbage collection is hard. JIT and Generational GC tends to make optimization especially hard. Rust takes an approach without GC. Golang has GC, but makes it easy to avoid creating memory pressure.

Back when Java came into scene, all major GC enabled systems programming languages had support for value types, some kind of off-heap allocation, some of them also had generics and were AOT compiled to native code.

But then the way it was massively marketed meant those languages died, with Eiffel and Oberon being the only two that are still kind of around, but they are pretty niche.

Thankfully .NET designers learned the lesson and kept value types, some ways of manually allocating, AOT compilation at installation time, reified generics, but "it's Microsoft" meant many did not explore this path.

Java is now trying to fix these bad decisions.

In a way Go is what Java 1.0 should have been.

> The way to prevent that is to learn about these optimizations, which change often and in undocumented ways, making your code perform very differently across versions.

Not only that, your code can perform very differently across minor changes! All it takes is a single modification to start triggering cascading deoptimizations and lead to severely degraded performance. Even writing 0 instead of 0.0 (or vice versa) can change how the code is optimized and reduce performance.

Applications are open for YC Summer 2019

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