On Wed, May 1, 2013 at 10:25 PM, Stuart Jansen <[email protected]> wrote:
> I don't follow compilers either, but I do remember being convinced of > the value of runtime optimization when the following came out in 1999: > http://www.hpl.hp.com/techreports/1999/HPL-1999-78.html Dynamo was cool stuff. Basically gives you the benefits of whole-program optimization along with the benefits of separate compilation and run-time linking. And without the cost of optimizing *everything* instead of just hot paths. > I also know that these days, even sophisticated JavaScript engines > perform multiple levels of optimization and deoptimization based on > observed hot spots. Many of the sophisticated JIT techniques were developed in the context of Smalltalk, which is a highly-dynamic language that requires a lot of optimization to perform well. Everything in Smalltalk is a method call (even simple arithmetic and conditional expressions) and there are no type declarations, so a naive implementation would be punishingly slow. One of the biggest wins comes from a technique called polymorphic inline caching. Every method call site, when it is first dispatched, can be replaced by an inline call to the method on the type that is resolved the first time. A quick check to verify that it didn't make a type mistake is then made, and assuming every call is operating on the same type, the method dispatch overhead is essentially erased. If the check fails due to a polymorphic call, it can use standard method lookup and possibly change the inline method to the new implementation. With polymorphic inline caches and JIT compiling, you can have a highly abstract program compile to perform efficiently on a job of one data type, then reconfigure itself to perform efficiently on the next one. In a language without dynamic optimizations, you'd have to anticipate the data types to be used and instruct the compiler to generate efficient code for all of them. Ahead-of-time compilers are typically able to apply more sophisticated optimization techniques, but only if enough information is available at compile time. The more dynamic a program's behavior is, the less information there will be at compile time for an optimizer to take advantage of, and the more benefit you'll get from dynamic optimizations. As I mentioned in the context of Dynamo, run-time compilation also allows you to perform optimization across boundaries that would be impossible to optimize across in many languages like C and C++, such as compilation unit boundaries and library boundaries. Calling a library function in a tight loop, or even calling a function implemented in a separate compilation unit of the same program, could create significant overhead due to the inability to inline or otherwise optimize the calls. Modern Javascript optimizers use a technique similar to Dynamo called tracing just-in-time compilation, in which the compilation unit is not the method/function, but a repeated code path that may involve multiple methods or just a small part of a method. By "tracing" execution through these paths as they are taken, they can have optimizations applied to them that would not have appeared to a static ahead-of-time compiler, thereby eliminating a lot of language-induced overhead for commonly executed code paths. C++ gives opportunities to specialize code via templates, but that can cause both compilation time issues and severe code bloat, as static code must be generated at compile time for all types used in templates. JIT compiling with dynamic or generic types allows for the same generality in code and efficiency in implementation, but without needing to generate code for all types in the program, just the ones that are actually being used at the time. > Digging for the old HP article turned up the following, which seems like > a good starting point for someone interested in learning more: > http://en.wikipedia.org/wiki/Dynamic_recompilation That's all good stuff, and there's a lot more out there as well, both for static and dynamic optimizing compilers. C and C++ are really very poor examples of languages that compilers can do optimization well with. They can, of course, both be compiled to very efficient code, but the programmer must be very involved in the process at a low level. Languages like Haskell give the compiler a *lot* more information about the program that can be used for optimization in ahead-of-time compilation, and JIT compilers and dynamic compilation techniques can deliver the optimizations you need at just the places you need them without bloating the code or compilation time with unnecessary "optimization". /* PLUG: http://plug.org, #utah on irc.freenode.net Unsubscribe: http://plug.org/mailman/options/plug Don't fear the penguin. */
