As a last example, V8 doesn’t made no attempt to optimize statements contained within try-catch blocks; such code is simply executed slowly. However, if the try block contains some compute-heavy code that can be easily moved to a separate function, refactoring the compute-heavy code into a separate function allows V8 to optimize the subsidiary function, essentially eliminating the try-catch penalty.
Most instrumentation efforts have focused on instrumenting at the level of machine code or static source code. There are good reasons for shying away form instrumenting dynamic code; constructs like eval and on-the-fly anonymous function generation pose challenges to instrumenting all code.
However, there are many use-cases where instrumentation of dynamic code is desirable. We discovered some of them by working on V8 optimization issues. To determine if an object has properties added after being initialized, it is desirable to be able to instrument every line where the object is mutated to see if the list of properties the object possesses change as a result of the line running.
Furthermore, we believe that this is broadly-useful functionality that can help with debugging, monitoring of large-scale deployed websites, and more.
We built an optimization-barrier diagnostic tool around the Esprima parsing library, a JS parser writen in JS.
We also initially used an Esprima derivative product called Esmorph, a JS mutation tool usable as an instrumentation framework. However, Esmorph is a fledgling project of under 100 LOC, so we unsurprisingly found it to be extremely limiting. As a result, we extended it significantly.
We extended the API to be able to insert instrumenting code before and after lines. We allow targeted instrumentation as well; for example, instrumenting every return statement, or instrumenting every if statement (before it, after it, or in its consequent blocks).
We also believe that our combination of static and dynamic checking is an underused idea that will become increasingly important as more work is done with dynamic languages. By reporting only optimization hurdles that are actually encountered when the JIT attempts to compile and optimize code, we can suppress issues in code that never runs enough to be JIT-ed and focus the programmer time on the highest-value optimization opportunities.
This also would allow a system to find bugs and other anomalies most effectively. Some bugs should be found totally statically, some can be found statically but should be filtered based on whether the JIT actually encounters them. But some, especially in a dynamic language, must be caught at runtime. (A flexible code instrumentation tool is critical for instrumenting the code to find these.)
We certainly did not invent this idea. Profile-guided optimization is a similar idea, but we have extended it beyond the realm of compilers looking to make optimization decisions.
Try / catch
As of October 2012, V8 didn’t even try – ha – to optimize try/catch statements. However, as mentioned before, compute-heavy code refactored into a separate function called from within the try/catch can still be optimized. If V8 reports a blocked inline due to a try/catch, we walk the AST emitted by Esprima looking for calls to the function that couldn’t be inlined and test if they’re contained within an offending try/catch statement.
Adding fields to objects
Using the line instrumentation facility that we added to Esmorph, we
created a small tool that examines all expressions, assignments, and
fields to extant objects dynamically. This practice incurs a
performance penalty as engines like V8 must create a new C++ class to
represent the object with a new field. Moving these dynamic field
additions outside of performance sensitive inner loops and functions
thus present an easy way to extract more performance with little
Understanding paths through functions
Esmorph includes a demo that counts how many times each function is called. However, there is no way to count which path through the function is taken, due to the shortcomings of Esmorph discussed above. With our extensions, a similar amount of code can give more understanding. As an example, we have implemented a tool that instruments each return statement to count how many times each return is taken.
Thomas M. Conte, Burzin A. Patel, Kishore N. Menezes, and J. Stan Cox. Hardware-Based Proﬁling: An Effective Technique for Proﬁle-Driven Optimization. International Journal of Parallel Processing, 24(2):187–206, 1996.
Florian Lotisch. Optimizing for V8 - Introduction. http://floitsch.blogspot.com/2012/03/optimizing-for-v8-introduction.html