103 lines
3.3 KiB
JavaScript
103 lines
3.3 KiB
JavaScript
//@ skip
|
|
|
|
description("Regression test for https://webkit.org/b/141098. Make sure eval() properly handles running out of stack space. This test should run without crashing.");
|
|
|
|
// The tiering up to test higher levels of optimization will only test the DFG
|
|
// if run in run-jsc-stress-tests with the eager settings.
|
|
|
|
// countStart, countIncrement, and numberOfFramesToBackoffFromStackOverflowPoint were
|
|
// empirically determined to be the values that will cause StackOverflowErrors to be
|
|
// thrown where the tests expects them. If stack frame layouts change sufficiently (e.g.
|
|
// due to JIT changes) such that this test starts failing (due to text output
|
|
// differences), then these values will need to be rebased.
|
|
// Under no circumstance should this test ever crash.
|
|
let countStart = 2;
|
|
let countIncrement = 8;
|
|
let numberOfFramesToBackoffFromStackOverflowPoint = 10;
|
|
|
|
// backoffEverything is chosen to be -1 because a negative number will never be
|
|
// decremented to 0, and hence, will cause probeAndRecurse() to return out of every
|
|
// frame instead of retrying the eval test.
|
|
let backoffEverything = -1;
|
|
|
|
var lastEvalString = "";
|
|
|
|
function testEval(maxIterations)
|
|
{
|
|
var result;
|
|
var count = countStart;
|
|
|
|
if (!maxIterations)
|
|
var result = eval(lastEvalString);
|
|
else {
|
|
for (var iter = 0; iter < maxIterations; count *= countIncrement, iter++) {
|
|
var evalString = "\"dummy\".valueOf(";
|
|
|
|
for (var i = 0; i < count; i++) {
|
|
if (i > 0)
|
|
evalString += ", ";
|
|
evalString += i;
|
|
}
|
|
|
|
evalString += ");";
|
|
|
|
if (maxIterations > 1)
|
|
lastEvalString = evalString;
|
|
result = eval(evalString);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
function probeAndRecurse(reuseEvalString)
|
|
{
|
|
var framesToBackOffFromStackOverflowPoint;
|
|
|
|
// Probe stack depth
|
|
try {
|
|
remainingFramesToBackOff = probeAndRecurse(reuseEvalString);
|
|
|
|
if (!remainingFramesToBackOff) {
|
|
// We've backed off a number of frames. Now retry the eval test to see if we
|
|
// still overflow.
|
|
try {
|
|
testEval(1);
|
|
} catch (e) {
|
|
// Yikes. We still overflow. Back off some more.
|
|
return numberOfFramesToBackoffFromStackOverflowPoint;
|
|
}
|
|
} else
|
|
return remainingFramesToBackOff - 1
|
|
} catch (e) {
|
|
// We exceeded stack space, now return up the stack until we can execute a simple eval.
|
|
// Then run an eval test to exceed stack.
|
|
return numberOfFramesToBackoffFromStackOverflowPoint;
|
|
}
|
|
|
|
try {
|
|
testEval(reuseEvalString ? 0 : 20);
|
|
} catch (e) {
|
|
testPassed("Exception: " + e);
|
|
}
|
|
|
|
return backoffEverything;
|
|
}
|
|
|
|
// Because this test intentionally exhausts the stack, we call testPassed() to ensure
|
|
// everything we need in that path has been compiled and is available. Otherwise we
|
|
// might properly handle an out of stack, but run out of stack calling testPassed().
|
|
testPassed("Initial setup");
|
|
|
|
debug("Starting 1st probeAndRecurse");
|
|
probeAndRecurse(false);
|
|
|
|
// Tier up the eval'ed code.
|
|
// When run with run-jsc-stress-tests and it's agressive options, this low of a count will
|
|
// allow us to get up to the DFG.
|
|
for (var i = 0; i < 200; i++)
|
|
testEval(0);
|
|
|
|
debug("Starting 2nd probeAndRecurse");
|
|
probeAndRecurse(true);
|