From the translator: unfortunately, I didn’t wait for the next post to be translated from browser developers about IE9 vs SunSpider, I had to translate myself. Why one more? Unlike the others ( first , second ), which gave only information for reflection, this one also gives practical knowledge - a description of the pitfalls that each developer may encounter when running his code in the new IE9.Dean Hachamovitch: One of the changes in our new JavaScript engine, code-named Chakra, is the destruction of dead code , in order to improve the performance of real sites. [ 1 ]
Yesterday I sent a bug after a light analysis of the dead code removal algorithm in IE9. After that, the IE9 team released a platform preview 7 and
updated its blog about IE.
')
Removing a dead code is a valid optimization, but very easily surface implementations can lead to unpredictable behavior and become a source of errors.
Regarding the fragility of the algorithm implemented in IE9, our study showed that only the following operations can be optimized: -, +, ++, <<, + =, - =, and if (>). For example, if you change this comparison in
that test :
if (TargetAngle> CurrAngle) {
on
if (TargetAngle <= CurrAngle) {
then IE9 will no longer delete this code. It is curious that the developers of IE9 decided not to delete such resource-intensive operations as multiplication and division. The set of operations chosen for optimization seems to coincide with that used in the math tests in SunSpider.
As for reasonableness, several problems have already been found in implementing the removal of dead code in IE9. One of our developers, Andreas Gal., Attracted my attention to the first one I touched on. Dean on the IE blog gave this example:
In the following example, the code in the loop constantly overwrites the same variable (in CS, this is known as dead save), so this code can be simplified to one call.
function func (a, b) {
var x;
var i = 300;
while (i--) {
x = a + b; // dead store
}
}
I think with this example Dean tries to show that since x is constantly being overwritten, the JavaScript engine can perform only one iteration of the loop and save time, since all calls give the same value to x.
This may be true for
statically typed languages such as C #, but unfortunately this is not true for JavaScript.
This function can be optimized if it is called as
func (1,2)
since there is no
side effect . However, if we call a function like this, then it cannot be optimized:
func (1, {valueOf: function () {alert ("Hi Dean!"); return 2;}});
Here we pass the object as the second argument (b), and in it we declare the valueOf method, which will be called by the operation a + b. Unexpected turn? This dynamic side of the language makes it very difficult to optimize JavaScript, and the task of adding traditional compiler optimizations, such as removing dead code or deleting dead save, becomes anything but not trivial.
IE9 Platform Preview # 7 does not handle this example from their blog correctly (you can
try ). If the function is called with an object that has its own implementation of the valueOf method, then IE9 does not mistakenly call this handler.
Deep analysis of dead code in javascript is in fact very complex and requires a global analysis of the entire program. The IE9 blog explained how local operations on
literals for arrays can be simplified as dead code, since they do not have side effects. Therefore, we can assume that the following call can be safely removed:
func (1, [1,2,3,4,5])
The first argument is a constant and the array literal looks pretty safe. Unfortunately, if the following code was executed in the program before this call, this deletion again becomes superficial:
Object.prototype.valueOf = function () {alert ("IE9 is fast!"); }
Here we override the valueOf handler for all objects, including literals, and therefore adding a + b will cause our implementation of valueOf. And again, IE9 mistakenly misses a call to our handler, and defining this case is even more difficult than the previous one, because now the “optimization” can be affected by code in other files.
The second problem of surface implementation, which I will describe, was noticed by Chris Leary, another developer from the Mozilla team. The loop in the math test, which IE9 deletes like a dead code, works with the global variable "Angles". We found that IE9 still removes the call for cordicsincos (), even when the definition of the variable "Angles" was removed from the source. In this case, the correct behavior would be to throw a Reference Error exception, since Angles is not defined anywhere. If you wish, try
this demo to check the error. In addition, you will find many more problems with the dead code removal algorithm in IE9, if you start using
new ES5 features such as getters for the Angles variable or the window object.
The fact that the time of my post coincided with the release of IE9 PP7 is pure coincidence, and I am glad that all browsers are faster and faster to execute JavaScript. But, as I said, I don’t think that the implementation of deleting dead code in IE9 can be considered a serious wide-area optimization. It seems that it was not tested on anything, except for the SunSpider test.
Obviously, I could have missed something, so even more information should appear on
Twitter Q & A session from the IE team tomorrow morning.
From the translator: in the comments to the original are alternative and cheaper solutions to these problems instead of global analysis. I hope the developers of IE9 will fix these problems, and the developers of SunSpider will add side effects to their tests. Thanks to XPilot for linking to this wonderful analysis.