6 ms·
One important thing to note that this post kind of hints at: JavaScript can be optimized more than equivalent WebAssembly if you give the JS runtime enough help
by kevingadd 6y ago
One important thing to note that this post kind of hints at: JavaScript can be optimized more than equivalent WebAssembly if you give the JS runtime enough help, because it can use runtime-only information to produce better-optimized JS. It can exploit type information gathered during runtime to devirtualize method calls and produce type-specialized code, while also doing things like escape analysis to eliminate some allocations entirely. You have to carefully identify places in your native code where you can do unchecked array accesses, etc, but the JS runtime just figures it out for you.
For any of those optimizations to happen for your WASM code, the compiler has to be able to do it statically and that can be much harder. Devirtualization in particular is essential for Java or C# to run fast and some C++ codebases also benefit tremendously from it. If you're interacting a lot with JS APIs from WASM (like issuing network requests or creating DOM elements, etc) you're going to be dealing with lots of dynamically typed data, and in those scenarios handwritten JS may actually be faster than WASM because the runtime can JIT optimal code with the right type specializations.
Note that these optimizations will fail if you aren't careful about how you write your JS: If a given function f(x,y) is passed values of different types during execution, it probably won't be fully optimized. If you have two functions f1(x,y) and f2(x,y) and ensure that each one is only passed values of a certain type, they will both be heavily optimized (iirc the JS runtime terminology for these functions is 'monomorphic') Naturally, this means uses of Function.apply and Function.call should be avoided at all costs.
- RcouF1uZ4gsC 6y agoI have seen much the same made about Java versus C++ for the past 25 years that the Java byte code JIT would have more information and thus be able to optimize and do stuff like devirtualization better. However, that has not planned out. There are a few reasons for this. First C++ and Rust optimizers can do amazing things when they are given time. In addition, I think devirtualization is not as big a deal in C++ and Rust because in general you avoid writing code that uses virtual functions when you are writing performance sensitive code and instead use things like templates/generics where there is no indirect function calls.
- kevingadd 6y agoYour argument basically boils down to "If you write fast C++ it will be fast", which is true. But a significant fraction of code out there is not fast C++ written by experts to be fast. This is different than "Java will be faster than C++ because of HotSpot" arguments, because java is competing with C++. This is not a competition between JS and native C++, it's a competition between JS and WASM.
- astrange 6y agoThe main problems with Java aren't being JITted, it's that it's not expressive enough. It doesn't have SIMD (yet) or value types (yet…?). I would expect a JIT to not really be able to find a lot of magic optimization opportunities, though maybe there are some, and it'd actually be annoying if it could. The most important thing in a tool like that is predictability, because you can't make development decisions based on magic.
- kevingadd 6y agoOptimizations like 'these two function arguments are always int31' in v8 or spidermonkey are 100% predictable at this point and result in all your type checks and boxing being eliminated, and with the known types it also becomes much cheaper/faster to create object instances (since now if you store those values into properties of an object, that object's shape is fully known). Various properties like this can extend out into larger parts of your JS application. There's still a lot of magic you can't rely on, but you'd be surprised how much you CAN rely on. Asm.js was built on this observation: If you write your JS following some basic rules it's actually pretty easy to land on predictable, well-optimized paths. Of course, one of WASM's advantages is that by design you're almost always on those paths and don't have to worry.
- pjmlp 6y agoIt surely has had support for AVX for several releases, although via the autovectorization support, and explicit SIMD has been made available as preview on Java 16.
- lilyball 6y agoSurely there’s some way to do profile-guided optimization when compiling to WASM?
- kevingadd 6y agoSome WASM compiler toolchains have PGO available, yes.