375 lines
8.4 KiB
JavaScript
375 lines
8.4 KiB
JavaScript
if (typeof Element == "undefined" && $vm)
|
|
Element = $vm.Element;
|
|
|
|
if (!this.alert) {
|
|
debug = print;
|
|
description = print;
|
|
}
|
|
|
|
description(
|
|
'This test checks stack trace corectness in special cases.'
|
|
);
|
|
|
|
function stackTraceLineFor(stackTrace, frameIndex) {
|
|
var i = frameIndex;
|
|
var indexOfAt = stackTrace[i].indexOf('@')
|
|
var indexOfLastSlash = stackTrace[i].lastIndexOf('/');
|
|
if (indexOfLastSlash == -1)
|
|
indexOfLastSlash = indexOfAt
|
|
var functionName = stackTrace[i].substring(0, indexOfAt);
|
|
var fileName = stackTrace[i].substring(indexOfLastSlash + 1);
|
|
return functionName + " at " + fileName;
|
|
}
|
|
|
|
function printStack(stackTrace) {
|
|
debug("--> Stack Trace:")
|
|
stackTrace = stackTrace.split("\n");
|
|
var length = Math.min(stackTrace.length, 100);
|
|
for (var i = 0; i < length; i++)
|
|
debug(" " + i + " " + stackTraceLineFor(stackTrace, i));
|
|
debug('');
|
|
}
|
|
|
|
function dumpPattern(pattern) {
|
|
for (var i = 0; i < pattern.length; i++)
|
|
debug(" " + i + " " + pattern[i]);
|
|
}
|
|
|
|
function matchesPatternAtLine(pattern, patternIndex, traceLine) {
|
|
var patternLine = pattern[patternIndex];
|
|
return traceLine.slice(0, patternLine.length) == patternLine;
|
|
}
|
|
|
|
function matchPattern(pattern, traceLine) {
|
|
for (var i = 0; i < pattern.length; i++) {
|
|
if (matchesPatternAtLine(pattern, i, traceLine))
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
function checkStackForPattern(stackTrace, pattern) {
|
|
stackTrace = stackTrace.split("\n");
|
|
var length = Math.min(stackTrace.length, 100);
|
|
|
|
// Get the match in the pattern for the first line:
|
|
var firstStackTraceLine = stackTraceLineFor(stackTrace, 0);
|
|
var patternIndex = matchPattern(pattern, firstStackTraceLine);
|
|
if (patternIndex < 0) {
|
|
debug("--> Stack Trace FAILED to match pattern:")
|
|
dumpPattern(pattern);
|
|
debug('');
|
|
return;
|
|
}
|
|
|
|
for (var i = 1; i < length; i++) {
|
|
patternIndex = ++patternIndex % pattern.length;
|
|
var traceLine = stackTraceLineFor(stackTrace, i);
|
|
if (!matchesPatternAtLine(pattern, patternIndex, traceLine)) {
|
|
debug("--> Stack Trace FAILED to match pattern:")
|
|
dumpPattern(pattern);
|
|
debug('');
|
|
return;
|
|
}
|
|
}
|
|
|
|
debug("--> Stack Trace matches pattern:")
|
|
dumpPattern(pattern);
|
|
debug('');
|
|
}
|
|
|
|
function hostThrower() { Element.prototype.appendChild.call({ }, [{ }]); }
|
|
function callbacker(f) { [0].map(f); }
|
|
function outer(errorName) { inner(errorName); }
|
|
function inner(errorName) { throw new Error("Error in " + errorName); }
|
|
function evaler(code) { eval(code); }
|
|
function normalOuter() { normalInner(); }
|
|
function normalInner() { if(thisVarDoesntExist) failIfTrue("shouldFailBeforeThis") };
|
|
function scripterInner() { htmlInner(); }
|
|
function scripterOuter() { htmlOuter(); }
|
|
// Expected functions in stack trace
|
|
// Normal Case
|
|
try { normalOuter() } catch (e) { printStack(e.stack) } // normalOuter -> normalInner
|
|
|
|
// Eval Case
|
|
try { evaler("inner('inner eval');"); } catch (e) { printStack(e.stack) } // evaler -> eval -> inner
|
|
try { evaler("outer('outer eval');"); } catch (e) { printStack(e.stack) } // evaler -> eval -> outer -> inner
|
|
|
|
// Function Callback Case
|
|
try { callbacker(inner('inner map')); } catch (e) { printStack(e.stack); } // callbacker -> map -> inner
|
|
try { callbacker(outer('outer map')); } catch (e) { printStack(e.stack); } // callbacker -> map -> outer -> inner
|
|
|
|
// Host Code Case
|
|
try { hostThrower(); } catch (e) { printStack(e.stack); } // hostThrower
|
|
|
|
try { scripterInner(); } catch (e) { printStack(e.stack) } // program -> scripter -> inner
|
|
try { scripterOuter(); } catch (e) { printStack(e.stack) } // program -> scripter -> outer -> inner
|
|
|
|
function selfRecursive1() { selfRecursive1();
|
|
}
|
|
|
|
|
|
try { selfRecursive1(); } catch (e) { printStack(e.stack) } // selfRecursive1 -> selfRecursive1 -> selfRecursive1 -> selfRecursive1 ...
|
|
|
|
function selfRecursive2() {
|
|
// A little work to make the DFG kick in
|
|
for (var i = 0; i < 10; i++) {
|
|
if (i == 9)
|
|
selfRecursive2();
|
|
}
|
|
}
|
|
|
|
try { selfRecursive2(); } catch (e) { printStack(e.stack) } // selfRecursive2 -> selfRecursive2 -> selfRecursive2 -> selfRecursive2 ...
|
|
|
|
function selfRecursive3() {
|
|
eval("selfRecursive3()");
|
|
}
|
|
|
|
try {
|
|
selfRecursive3();
|
|
} catch (e) {
|
|
var pattern = [
|
|
"eval code at ",
|
|
"eval at [native code]",
|
|
"selfRecursive3 at stack-trace.js"
|
|
];
|
|
checkStackForPattern(e.stack, pattern);
|
|
}
|
|
|
|
var callCount = 0;
|
|
|
|
function throwError() {
|
|
throw new Error();
|
|
}
|
|
|
|
var object = {
|
|
get getter1() {
|
|
var o = {
|
|
valueOf: function() {
|
|
throwError()
|
|
}
|
|
};
|
|
+o;
|
|
},
|
|
get getter2() {
|
|
var o = {
|
|
valueOf: throwError
|
|
};
|
|
+o;
|
|
},
|
|
get getter3() {
|
|
var o1 = {
|
|
valueOf: throwError
|
|
};
|
|
var o2 = {
|
|
valueOf: function () {
|
|
throwError();
|
|
}
|
|
};
|
|
if (callCount == 9998)
|
|
+o1;
|
|
if (callCount == 9999)
|
|
+o2;
|
|
},
|
|
nonInlineable : function () {
|
|
if (0) return [arguments, function(){}];
|
|
++callCount;
|
|
if (callCount == 1) {
|
|
this.getter1;
|
|
} else if (callCount == 2) {
|
|
this.getter2;
|
|
} else {
|
|
this.getter3;
|
|
}
|
|
},
|
|
inlineable : function () {
|
|
this.nonInlineable();
|
|
}
|
|
}
|
|
|
|
function yetAnotherInlinedCall(o) {
|
|
o.inlineable();
|
|
}
|
|
|
|
function makeInlinableCall(o) {
|
|
for (var i = 0; i < 10000; i++) {
|
|
new yetAnotherInlinedCall(o);
|
|
}
|
|
}
|
|
for (var k = 0; k < 4; k++) {
|
|
try {
|
|
function g() {
|
|
var j = 0;
|
|
for (var i = 0; i < 1000; i++) {
|
|
j++;
|
|
makeInlinableCall(object);
|
|
}
|
|
}
|
|
[1].map(g);
|
|
} catch (e) {
|
|
printStack(e.stack);
|
|
}
|
|
}
|
|
|
|
function h() {
|
|
if (callCount++ == 1000)
|
|
throw new Error();
|
|
if (callCount > 1000) {
|
|
[].map.apply(undefined, throwError);
|
|
}
|
|
}
|
|
|
|
function mapTest(a) {
|
|
a.map(h);
|
|
}
|
|
|
|
function mapTestDriver() {
|
|
var a = [1,2,3];
|
|
for (var i = 0; i < 2000; i++)
|
|
mapTest(a);
|
|
}
|
|
|
|
try {
|
|
callCount = 0;
|
|
mapTestDriver()
|
|
} catch(e) {
|
|
printStack(e.stack);
|
|
}
|
|
|
|
try {
|
|
mapTestDriver()
|
|
} catch(e) {
|
|
printStack(e.stack);
|
|
}
|
|
|
|
var dfgFunctionShouldThrow = false;
|
|
function dfgFunction() {
|
|
if (dfgFunctionShouldThrow) {
|
|
dfgFunctionShouldThrow = false;
|
|
throwError();
|
|
}
|
|
}
|
|
|
|
for (var k = 0; k < 1000; k++)
|
|
dfgFunction();
|
|
|
|
try {
|
|
dfgFunctionShouldThrow = true;
|
|
[1,2,3,4].map(dfgFunction);
|
|
} catch (e) {
|
|
printStack(e.stack);
|
|
}
|
|
|
|
try {
|
|
var o = { };
|
|
o.__defineGetter__("g", dfgFunction);
|
|
function f(o) {
|
|
o.g;
|
|
}
|
|
for (var k = 0; k < 1000; k++)
|
|
f(o);
|
|
|
|
dfgFunctionShouldThrow = true;
|
|
f(o);
|
|
|
|
} catch (e) {
|
|
printStack(e.stack);
|
|
}
|
|
|
|
var someValue = null;
|
|
|
|
function callNonCallable() {
|
|
someValue();
|
|
}
|
|
|
|
for (var i = 0; i < 100; i++) {
|
|
try {
|
|
callNonCallable();
|
|
} catch (e) {
|
|
}
|
|
}
|
|
|
|
function dfgTest(f) {
|
|
dfgCount = 0;
|
|
while (dfgCount++ < 1000) {
|
|
try {
|
|
f();
|
|
} catch (e) {
|
|
printStack(e.stack)
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
function inlineableThrow() {
|
|
if (dfgCount > 500) throw new Error();
|
|
}
|
|
|
|
var dfgThing = {
|
|
get willThrow() {
|
|
if (dfgCount > 500)
|
|
throw new Error();
|
|
},
|
|
get willThrowEventually() {
|
|
inlineableThrow();
|
|
},
|
|
willThrowFunc: function () { if (dfgCount > 500) throw new Error(); },
|
|
willThrowEventuallyFunc: function () { inlineableThrow(); }
|
|
}
|
|
dfgThing.__defineGetter__("hostWillThrow", hostThrower);
|
|
|
|
function dfg1() {
|
|
dfgThing.willThrow
|
|
}
|
|
|
|
function dfg2() {
|
|
dfg1();
|
|
}
|
|
|
|
function dfg3() {
|
|
dfg2();
|
|
}
|
|
|
|
function dfg4() {
|
|
dfgThing.willThrowFunc();
|
|
}
|
|
|
|
function dfg5() {
|
|
dfg4();
|
|
}
|
|
|
|
function dfg6() {
|
|
dfg5();
|
|
}
|
|
|
|
function dfg7() {
|
|
dfgThing.willThrowEventually
|
|
}
|
|
|
|
function dfg8() {
|
|
dfg7();
|
|
}
|
|
|
|
function dfg9() {
|
|
dfg8();
|
|
}
|
|
|
|
function dfga() {
|
|
dfgThing.willThrowEventuallyFunc();
|
|
}
|
|
|
|
function dfgb() {
|
|
dfga();
|
|
}
|
|
|
|
function dfgc() {
|
|
dfgb();
|
|
}
|
|
|
|
dfgTest(dfg3)
|
|
dfgTest(dfg6)
|
|
dfgTest(dfg9)
|
|
dfgTest(dfgc)
|
|
|
|
successfullyParsed = true;
|