Reputation: 4456
Recently I encountered this article optimization killers about the V8 engine's optimization of JavaScript programs. But the article is not completely clear to me, so I would like to ask a couple of question about this stuff.
The article states:
Code compiled by the optimizing compiler can easily be, say, 100x faster than the code generated by the generic compiler... It is important to note that patterns that cause optimization bailouts affect the entire containing function.
Does this mean that if, for instance, some large piece of code, let's say a JavaScript library, which is in a form of the IIFE (Immediately-Invoked Function Expression) contains a try {} catch(e) {}
statement inside it wrapped by another function declaration, then the entire library is not optimized?
It seems so, because I tried to run this command $ node --trace_opt --trace_deopt --allow-natives-syntax try_catch.js
, and try_catch.js is below:
//Function that contains the pattern to be inspected (using with statement)
function optimizeWhack() {
foo();
function foo() {
try {} catch(e) {}
}
return 12
}
function printStatus(fn) {
switch(%GetOptimizationStatus(fn)) {
case 1: console.log("Function is optimized"); break;
case 2: console.log("Function is not optimized"); break;
case 3: console.log("Function is always optimized"); break;
case 4: console.log("Function is never optimized"); break;
case 6: console.log("Function is maybe deoptimized"); break;
}
}
//Fill type-info
optimizeWhack();
%OptimizeFunctionOnNextCall(optimizeWhack);
//The next call
optimizeWhack();
//Check
printStatus(optimizeWhack);
And the response I've got was this one, with function is not optimized
:
$ node --trace_opt --trace_deopt --allow-natives-syntax try_catch.js
[deoptimize context: ea2f6f14679]
[optimizing: optimizeWhack / ea2f6fc9c29 - took 0.033, 0.064, 0.000 ms]
**** DEOPT: optimizeWhack at bailout #1, address 0x0, frame size 8
[deoptimizing: begin 0xea2f6fc9c29 optimizeWhack @1]
translating optimizeWhack => node=3, height=8
0x7fff113fa238: [top + 40] <- 0xd7de9006c91 ; [sp + 40] 0xd7de9006c91 <JS Global Object>
0x7fff113fa230: [top + 32] <- 0x1bca01a663fc ; caller's pc
0x7fff113fa228: [top + 24] <- 0x7fff113fa268 ; caller's fp
0x7fff113fa220: [top + 16] <- 0xea2f6f14679; context
0x7fff113fa218: [top + 8] <- 0xea2f6fc9c29; function
0x7fff113fa210: [top + 0] <- 0xea2f6fca051 ; rbx 0xea2f6fca051 <JS Function foo>
[deoptimizing: end 0xea2f6fc9c29 optimizeWhack => node=3, pc=0x1bca01a665ff, state=NO_REGISTERS, alignment=no padding, took 0.074 ms]
[removing optimized code for: optimizeWhack]
Function is not optimized
A more general question is one to point me to some literature, sources etc. about all this optimization stuff, if those exist at all.
Thank you in advance.
Upvotes: 2
Views: 918
Reputation: 10492
V8's optimizing compiler is function based so if it's unable to optimized some function that does not affect any other functions - including those that enclose declaration of this unoptimizable function.
Almost all statements that are unsupported by the optimizing compiler also have only local effect - they disable optimizations of a particular function that contains them, but do not affect functions which contain that function. There is one exception however: direct eval
has affect on all enclosing functions.
function foo() {
function bar() {
function baz() {
eval(str);
}
}
}
In the example above none of foo
, bar
, baz
are optimizable by V8's Crankshaft.
Now to your example: from the logs you can see that optimizeWhack
was indeed optimized after you requsted it's optimization
[optimizing: optimizeWhack / ea2f6fc9c29 - took 0.033, 0.064, 0.000 ms]
However when execution entered optimized function it deoptimized
*** DEOPT: optimizeWhack at bailout #1, address 0x0, frame size 8
[deoptimizing: begin 0xea2f6fc9c29 optimizeWhack @1]
The reason for deopt is as follows: because you executed optimizeWhack
once call IC at foo()
entered monomorphic state and V8 specialed the call for a particular function value. However next time you call optimizeWack
a new foo
is created which no longer matches expected foo
value from the previous call. This causes deopt.
If you rewrite your sample to call optimizeWhack
twice before requesting optimization then you will see that optimizeWhack
stays optimized:
optimizeWhack();
optimizeWhack();
%OptimizeFunctionOnNextCall(optimizeWhack);
optimizeWhack();
printStatus(optimizeWhack);
// $ d8 --allow-natives-syntax test.js
// Function is optimized
Upvotes: 5