Last active
October 30, 2016 01:47
-
-
Save dlongley/5b1f4284922ec0deac9abbed5665c7ed to your computer and use it in GitHub Desktop.
Safari 10 optimization bug
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<title>Safari 10 Optimization Bug</title> | |
</head> | |
<body> | |
<h1>Safari 10 Optimization Bug</h1> | |
<p>This test reveals an optimization bug in Safari 10. A | |
deterministic function is run in a loop. Its first return | |
value is stored and printed to the screen. If any subsequent | |
turn of the loop produces a different return value, the | |
test exits immediately and prints the different value. | |
</p> | |
<p>This test passes successfully on Chrome, Firefox, and | |
early versions of Safari (less than v10). It fails on | |
Safari 10. You may need to refresh the page a few times | |
to get a failure, but it typically fails every time. | |
</p> | |
<div>Attempt: <span id="iteration">...</span></div> | |
<div>First result is <span id="expected">...</span></div> | |
<div>Final result | |
<span id="result">matches first result.<br> | |
<span style="color: green">SUCCESS!</span></span> | |
</div> | |
<script> | |
var expected; | |
var attempts = 5; | |
for(var x = 0; x < attempts; ++x) { | |
if(!_runTest(x, 100)) { | |
break; | |
} | |
} | |
function _runTest(attempt, max) { | |
for(var itr = 0; itr < max; ++itr) { | |
var s = { | |
a: 0, | |
b: 0, | |
c: 0x80000000, // setting to anything less avoids the bug | |
d: 0, | |
e: 0 | |
}; | |
for(var i = 0; i < 15000; ++i) { | |
var t, a, b, c, d, e; | |
a = s.a; | |
b = s.b; | |
c = s.c; | |
d = s.d; | |
e = s.e; | |
for(var j = 0; j < 2; ++j) { | |
t = a + e; | |
e = d; | |
// uncommenting line below with `>>> 0` will avoid the bug | |
//c = c >>> 0; | |
d = c; | |
c = (b >>> 1); | |
b = a; | |
a = t; | |
} | |
s.a = a | 0; | |
s.b = b | 0; | |
s.c = c | 0; | |
s.d = d | 0; | |
s.e = e | 0; | |
} | |
// compute the result | |
var result = Object.keys(s).reduce(function(a, b) { | |
return a + (s[b] >>> 0).toString(16); | |
}, ''); | |
// display and result comparison | |
document.getElementById('iteration').innerHTML = | |
(attempt + 1) + ', Iteration ' + (itr + 1) + ' / ' + max; | |
if(attempt === 0 && itr === 0) { | |
expected = result; | |
document.getElementById('expected').innerHTML = expected; | |
} else if(result !== expected) { | |
var output = {iteration: itr, result: result}; | |
document.getElementById('result').innerHTML = | |
' is ' + output.result + '<br>' + | |
'<span style="color: red">FAILURE!</span> ' + | |
'Final result does not match first result.'; | |
return false; | |
} | |
} | |
return true; | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment