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

Some of the world's greatest minds have been spending decades making JavaScript go fast inside VMs where the JIT can take advantage of profile information gathered at runtime.

Getting even remotely comparable performance in an ahead-of-time compiler—without spending eons waiting for complex whole program analysis—is, as far as I know, an unsolved problem for real-world programs. I'd like to see what "really, really fast" means for this compiler.



Seconded. An "offline" compiler can't use things like the type information gathered at runtime. So I'd expect this to actually be slower than JITs. Benchmarks should be provided before making performance claims!


However, the JIT compilation process itself is expensive, as is the interpretation and tracing. Since JIT-optimisation happens at run-time, often sub-optimal but fast optimisations are chosen (e.g. linear scan register alloc instead of graph-colouring).

Indeed the performance benefits of JITing have been difficult to measure: https://arxiv.org/abs/1602.00602


Register allocation isn't super important in JS. Type inference is most important, and it is impossible to do that AOT for JS. With PGO I bet you could do decently for some specific scenarios, but you will necessarily fall off a cliff if execution deviates from your profile.


> An "offline" compiler can't use things like the type information gathered at runtime.

This isn't true. At run-time you only need to pay the cost of dispatching once per (type of) input variable.

C++-style templates are popular enough that this concept should be readily understood by now: You pay with heavy compile times (IIRC Crystal takes almost a GB of ram to compile its compiler).

> Benchmarks should be provided before making performance claims!

Yes, absolutely. And reproducible.


> At run-time you only need to pay the cost of dispatching once per (type of) input variable.

That also means you can't inline (potentially) polymorphic calls. Inlining is the great big hammer when it comes to optimization.


Why then don't people write in Java for performance? HotSpot has this runtime information. It runs OK (GCCish) for code that gets past the JIT threshold and dog slow otherwise. Hell, Java 9 is offering AOT.

JITs have been around for 30+ years and they're umm OK. As in not magical.


> Why then don't people write in Java for performance?

They do. Just like people write for PyPy for performance.

The only challenge to Java's performance is from languages without dynamic GC and with detailed static type information: C, C++, Rust. Even then, Java is usually "only" half the speed.

And AOT is coming for fast start-up, not good steady-state performance.


The things that make Java slow compared to C++ aren't in the compiler so much as in the language. In a sentence, Java made tradeoffs for productivity and simplicity that in C++ went in favor of performance and power.


Well, back in the day, the Sun people were crowing that HotSpot would be faster than C++.


Lots of people do write in Java for performance. It is all relative.

JIT performance benefits are highly dependent on the language.


Performance of generated code for Java is actually pretty fantastic. As far as I know, most of the performance ceiling now is because pointer indirection and cache misses. Java's "everything is a reference to a heap-allocated object" model is nice for simplicity, but it's very expensive in today's world where you really don't want to fall down the memory hierarchy.


You'd be surprised


I'm always happy to be surprised, but if you can statically compile standards-compliant JS and make it as fast as a dynamic compiler with profiling then you will be profoundly surprising the entire programming language community and up-ending most of what we know about how to optimise dynamic languages.

But then many people pooh-pooh'd me in a similar way when I said I could make Ruby 10x faster which was my project for the last few years, so best of luck to you!


Can you explain how you would optimise an expression like "a + b" at compile-time when the types are ambiguous? Surely you have to fall back to generic code, which is slower than a JIT that can observe that both types are e.g. a number and emit the ideal instructions for it.


if I were to make a bet, I'd say that they don't implement the whole JavaScript and that there is some sort of a static type system which either rejects some programs where types can't be inferred or causes performance to fall of the cliff where types can't be inferred.

so essentially it's likely "JavaScript-like compiler" rather than "JavaScript compiler"... similar to how Crystal is Ruby-like but not really Ruby.


I would definitely bet that eval() is unsupported. And Function(body). Probably with(){}.

However, apart from that, I don't see what can't be done: you can simply look at what functions get called, with what parameters, and generate code for each fundamental type (doubles, strings, …) used. It's like making C++-style templates for all function parameters.

The flip side is awful compilation times on large projects, and (I expect) poor results on maths for which JS VMs detect small ints.

I actually wanted to do something like this as a follow-up from my experiments with JS type inference, but I lacked time…


I imagine the big problem is anything depending on user input, which is unpredictable. Then the unpredictability probably propagates a long way through the program.

A simple example would be something like `x = (isUserOnMars() ? "foo" : 1)`. The type of `x` depends on if the user is on Mars. In practice they never will be, but a compiler can't tell that and so must consider that case and make code appropriately generic. A JIT however can see that it always appears to be false, and optimise around `x` tending to be a number, with bailout if it's wrong (which it likely never will be). Then the use of `x` may propagate a long way through the program in all sorts of places, extending the effect.


Is there any reason the compiler can't just emit optimized code for both the string and int cases?


You're going to need to bias in one direction or another. If you can safely inline assumptions regarding the int into the hot path that exists, with a consciously slower bail-out path if it's not an integer. Now consider a situation where `x` is probably an integer--but can be a string or null. We're rapidly getting to a situation where this is going to be puffy code that is hard to constrain to an effective hot path without running the code, yeah?

Profile-guided optimization seeks to do this for compiled languages like C++, but you also have a boatload more data to do it with. And, y'know. You're profiling the application. You're running it.


Depending on the ground rules that you set, I don't think eval() or Function() would be that bad considering they both evaluate in the global scope and you're working with strings in the first place.

My first guess for the chopping block would be the functionality of franken-objects like Function.arguments (especially properties like arguments.callee).


You can generate code for all type combinations for a and b. This will blow-up compiled code. It's a classic space-time trade-off.

Moreover, you can carry out heavy static analysis that can often narrow down the possible types for a and b. The main problem with this is that static analysis that is good enough will run very slow, hence it not an option for the web-browser.


You only need to generate code if it's being used, which means you can trade RAM (for a larger compilation unit) to reduce the number of (different types of) inputs.


I'm always surprised when someone backs up their claims.




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

Search: