Commit ddf4b487 authored by oliver@apple.com's avatar oliver@apple.com

Implement Error.stack

https://bugs.webkit.org/show_bug.cgi?id=66994

Reviewed by Gavin Barraclough.

Source/JavaScriptCore:

Implement support for stack traces on exception objects.  This is a rewrite
of the core portion of the last stack walking logic, but the mechanical work
of adding the information to an exception comes from the original work by
Juan Carlos Montemayor Elosua.

* interpreter/Interpreter.cpp:
(JSC::getCallerInfo):
(JSC):
(JSC::getSourceURLFromCallFrame):
(JSC::getStackFrameCodeType):
(JSC::Interpreter::getStackTrace):
(JSC::Interpreter::throwException):
(JSC::Interpreter::privateExecute):
* interpreter/Interpreter.h:
(JSC):
(StackFrame):
(JSC::StackFrame::toString):
(Interpreter):
* jsc.cpp:
(GlobalObject::finishCreation):
(functionJSCStack):
* parser/Nodes.h:
(JSC::FunctionBodyNode::setInferredName):
* parser/Parser.h:
(JSC::::parse):
* runtime/CommonIdentifiers.h:
* runtime/Error.cpp:
(JSC::addErrorInfo):
* runtime/Error.h:
(JSC):

LayoutTests:

Add testcases for producing a stack trace on exception objects.

* fast/js/exception-properties-expected.txt:
* fast/js/script-tests/exception-properties.js:
* fast/js/script-tests/stack-trace.js: Added.
(printStack):
(hostThrower):
(callbacker):
(outer):
(inner):
(evaler):
(normalOuter):
(normalInner):
(scripterInner):
(scripterOuter):
(selfRecursive1):
(selfRecursive2):
(selfRecursive3):
(throwError):
(object.get getter1.o.valueOf):
(object.get getter1):
(object.get getter2):
(object.get getter3.o2.valueOf):
(object.get getter3):
(object.nonInlineable.callCount):
(object.nonInlineable):
(object.inlineable):
(yetAnotherInlinedCall):
(makeInlinableCall):
(.try.g):
(h):
(mapTest):
(mapTestDriver):
(dfgFunction):
(try.f):
* fast/js/stack-trace-expected.txt: Added.
* fast/js/stack-trace.html: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@108112 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 56e5a9f9
2012-02-16 Oliver Hunt <oliver@apple.com>
Implement Error.stack
https://bugs.webkit.org/show_bug.cgi?id=66994
Reviewed by Gavin Barraclough.
Add testcases for producing a stack trace on exception objects.
* fast/js/exception-properties-expected.txt:
* fast/js/script-tests/exception-properties.js:
* fast/js/script-tests/stack-trace.js: Added.
(printStack):
(hostThrower):
(callbacker):
(outer):
(inner):
(evaler):
(normalOuter):
(normalInner):
(scripterInner):
(scripterOuter):
(selfRecursive1):
(selfRecursive2):
(selfRecursive3):
(throwError):
(object.get getter1.o.valueOf):
(object.get getter1):
(object.get getter2):
(object.get getter3.o2.valueOf):
(object.get getter3):
(object.nonInlineable.callCount):
(object.nonInlineable):
(object.inlineable):
(yetAnotherInlinedCall):
(makeInlinableCall):
(.try.g):
(h):
(mapTest):
(mapTestDriver):
(dfgFunction):
(try.f):
* fast/js/stack-trace-expected.txt: Added.
* fast/js/stack-trace.html: Added.
2012-01-23 Robert Hogan <robert@webkit.org>
REGRESSION: empty span creates renders with non-zero height
......@@ -4,7 +4,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
PASS enumerableProperties(error) is []
PASS enumerableProperties(nativeError) is ["line", "sourceURL"]
PASS enumerableProperties(nativeError) is ["line", "sourceURL", "stack"]
PASS Object.getPrototypeOf(nativeError).name is "RangeError"
PASS Object.getPrototypeOf(nativeError).message is ""
PASS successfullyParsed is true
......
......@@ -16,7 +16,7 @@ try {
var error = new Error("message");
shouldBe('enumerableProperties(error)', '[]');
shouldBe('enumerableProperties(nativeError)', '["line", "sourceURL"]');
shouldBe('enumerableProperties(nativeError)', '["line", "sourceURL", "stack"]');
shouldBe('Object.getPrototypeOf(nativeError).name', '"RangeError"');
shouldBe('Object.getPrototypeOf(nativeError).message', '""');
......
if (!this.alert) {
debug = print;
description = print;
}
description(
'This test checks stack trace corectness in special cases.'
);
function printStack(stackTrace) {
debug("--> Stack Trace:")
var length = Math.min(stackTrace.length, 100);
for (var i = 0; i < length; i++) {
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);
debug(" " + i + " " + functionName + " at " + fileName);
}
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) { printStack(e.stack) } // selfRecursive3 -> eval -> selfRecursive3 -> eval ...
var callCount = 0;
function throwError() {
throw {};
}
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 {};
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);
}
successfullyParsed = true;
This test checks stack trace corectness in special cases.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
--> Stack Trace:
0 normalInner at stack-trace.js:31
1 normalOuter at stack-trace.js:30
2 global code at stack-trace.js:36
--> Stack Trace:
0 inner at stack-trace.js:28
1 at eval code
2 eval at [native code]
--> Stack Trace:
0 inner at stack-trace.js:28
1 outer at stack-trace.js:27
2 at eval code
3 eval at [native code]
--> Stack Trace:
0 inner at stack-trace.js:28
1 global code at stack-trace.js:43
--> Stack Trace:
0 inner at stack-trace.js:28
1 outer at stack-trace.js:27
2 global code at stack-trace.js:44
--> Stack Trace:
0 hostThrower at stack-trace.js:25
1 global code at stack-trace.js:47
--> Stack Trace:
0 htmlInner at stack-trace.html:10
1 scripterInner at stack-trace.js:32
2 global code at stack-trace.js:49
--> Stack Trace:
0 htmlInner at stack-trace.html:10
1 htmlOuter at stack-trace.html:11
2 scripterOuter at stack-trace.js:33
3 global code at stack-trace.js:50
--> Stack Trace:
0 selfRecursive1 at stack-trace.js:53
1 selfRecursive1 at stack-trace.js:53
2 selfRecursive1 at stack-trace.js:53
3 selfRecursive1 at stack-trace.js:53
4 selfRecursive1 at stack-trace.js:53
5 selfRecursive1 at stack-trace.js:53
6 selfRecursive1 at stack-trace.js:53
7 selfRecursive1 at stack-trace.js:53
8 selfRecursive1 at stack-trace.js:53
9 selfRecursive1 at stack-trace.js:53
10 selfRecursive1 at stack-trace.js:53
11 selfRecursive1 at stack-trace.js:53
12 selfRecursive1 at stack-trace.js:53
13 selfRecursive1 at stack-trace.js:53
14 selfRecursive1 at stack-trace.js:53
15 selfRecursive1 at stack-trace.js:53
16 selfRecursive1 at stack-trace.js:53
17 selfRecursive1 at stack-trace.js:53
18 selfRecursive1 at stack-trace.js:53
19 selfRecursive1 at stack-trace.js:53
20 selfRecursive1 at stack-trace.js:53
21 selfRecursive1 at stack-trace.js:53
22 selfRecursive1 at stack-trace.js:53
23 selfRecursive1 at stack-trace.js:53
24 selfRecursive1 at stack-trace.js:53
25 selfRecursive1 at stack-trace.js:53
26 selfRecursive1 at stack-trace.js:53
27 selfRecursive1 at stack-trace.js:53
28 selfRecursive1 at stack-trace.js:53
29 selfRecursive1 at stack-trace.js:53
30 selfRecursive1 at stack-trace.js:53
31 selfRecursive1 at stack-trace.js:53
32 selfRecursive1 at stack-trace.js:53
33 selfRecursive1 at stack-trace.js:53
34 selfRecursive1 at stack-trace.js:53
35 selfRecursive1 at stack-trace.js:53
36 selfRecursive1 at stack-trace.js:53
37 selfRecursive1 at stack-trace.js:53
38 selfRecursive1 at stack-trace.js:53
39 selfRecursive1 at stack-trace.js:53
40 selfRecursive1 at stack-trace.js:53
41 selfRecursive1 at stack-trace.js:53
42 selfRecursive1 at stack-trace.js:53
43 selfRecursive1 at stack-trace.js:53
44 selfRecursive1 at stack-trace.js:53
45 selfRecursive1 at stack-trace.js:53
46 selfRecursive1 at stack-trace.js:53
47 selfRecursive1 at stack-trace.js:53
48 selfRecursive1 at stack-trace.js:53
49 selfRecursive1 at stack-trace.js:53
50 selfRecursive1 at stack-trace.js:53
51 selfRecursive1 at stack-trace.js:53
52 selfRecursive1 at stack-trace.js:53
53 selfRecursive1 at stack-trace.js:53
54 selfRecursive1 at stack-trace.js:53
55 selfRecursive1 at stack-trace.js:53
56 selfRecursive1 at stack-trace.js:53
57 selfRecursive1 at stack-trace.js:53
58 selfRecursive1 at stack-trace.js:53
59 selfRecursive1 at stack-trace.js:53
60 selfRecursive1 at stack-trace.js:53
61 selfRecursive1 at stack-trace.js:53
62 selfRecursive1 at stack-trace.js:53
63 selfRecursive1 at stack-trace.js:53
64 selfRecursive1 at stack-trace.js:53
65 selfRecursive1 at stack-trace.js:53
66 selfRecursive1 at stack-trace.js:53
67 selfRecursive1 at stack-trace.js:53
68 selfRecursive1 at stack-trace.js:53
69 selfRecursive1 at stack-trace.js:53
70 selfRecursive1 at stack-trace.js:53
71 selfRecursive1 at stack-trace.js:53
72 selfRecursive1 at stack-trace.js:53
73 selfRecursive1 at stack-trace.js:53
74 selfRecursive1 at stack-trace.js:53
75 selfRecursive1 at stack-trace.js:53
76 selfRecursive1 at stack-trace.js:53
77 selfRecursive1 at stack-trace.js:53
78 selfRecursive1 at stack-trace.js:53
79 selfRecursive1 at stack-trace.js:53
80 selfRecursive1 at stack-trace.js:53
81 selfRecursive1 at stack-trace.js:53
82 selfRecursive1 at stack-trace.js:53
83 selfRecursive1 at stack-trace.js:53
84 selfRecursive1 at stack-trace.js:53
85 selfRecursive1 at stack-trace.js:53
86 selfRecursive1 at stack-trace.js:53
87 selfRecursive1 at stack-trace.js:53
88 selfRecursive1 at stack-trace.js:53
89 selfRecursive1 at stack-trace.js:53
90 selfRecursive1 at stack-trace.js:53
91 selfRecursive1 at stack-trace.js:53
92 selfRecursive1 at stack-trace.js:53
93 selfRecursive1 at stack-trace.js:53
94 selfRecursive1 at stack-trace.js:53
95 selfRecursive1 at stack-trace.js:53
96 selfRecursive1 at stack-trace.js:53
97 selfRecursive1 at stack-trace.js:53
98 selfRecursive1 at stack-trace.js:53
99 selfRecursive1 at stack-trace.js:53
--> Stack Trace:
0 selfRecursive2 at stack-trace.js:62
1 selfRecursive2 at stack-trace.js:62
2 selfRecursive2 at stack-trace.js:62
3 selfRecursive2 at stack-trace.js:62
4 selfRecursive2 at stack-trace.js:62
5 selfRecursive2 at stack-trace.js:62
6 selfRecursive2 at stack-trace.js:62
7 selfRecursive2 at stack-trace.js:62
8 selfRecursive2 at stack-trace.js:62
9 selfRecursive2 at stack-trace.js:62
10 selfRecursive2 at stack-trace.js:62
11 selfRecursive2 at stack-trace.js:62
12 selfRecursive2 at stack-trace.js:62
13 selfRecursive2 at stack-trace.js:62
14 selfRecursive2 at stack-trace.js:62
15 selfRecursive2 at stack-trace.js:62
16 selfRecursive2 at stack-trace.js:62
17 selfRecursive2 at stack-trace.js:62
18 selfRecursive2 at stack-trace.js:62
19 selfRecursive2 at stack-trace.js:62
20 selfRecursive2 at stack-trace.js:62
21 selfRecursive2 at stack-trace.js:62
22 selfRecursive2 at stack-trace.js:62
23 selfRecursive2 at stack-trace.js:62
24 selfRecursive2 at stack-trace.js:62
25 selfRecursive2 at stack-trace.js:62
26 selfRecursive2 at stack-trace.js:62
27 selfRecursive2 at stack-trace.js:62
28 selfRecursive2 at stack-trace.js:62
29 selfRecursive2 at stack-trace.js:62
30 selfRecursive2 at stack-trace.js:62
31 selfRecursive2 at stack-trace.js:62
32 selfRecursive2 at stack-trace.js:62
33 selfRecursive2 at stack-trace.js:62
34 selfRecursive2 at stack-trace.js:62
35 selfRecursive2 at stack-trace.js:62
36 selfRecursive2 at stack-trace.js:62
37 selfRecursive2 at stack-trace.js:62
38 selfRecursive2 at stack-trace.js:62
39 selfRecursive2 at stack-trace.js:62
40 selfRecursive2 at stack-trace.js:62
41 selfRecursive2 at stack-trace.js:62
42 selfRecursive2 at stack-trace.js:62
43 selfRecursive2 at stack-trace.js:62
44 selfRecursive2 at stack-trace.js:62
45 selfRecursive2 at stack-trace.js:62
46 selfRecursive2 at stack-trace.js:62
47 selfRecursive2 at stack-trace.js:62
48 selfRecursive2 at stack-trace.js:62
49 selfRecursive2 at stack-trace.js:62
50 selfRecursive2 at stack-trace.js:62
51 selfRecursive2 at stack-trace.js:62
52 selfRecursive2 at stack-trace.js:62
53 selfRecursive2 at stack-trace.js:62
54 selfRecursive2 at stack-trace.js:62
55 selfRecursive2 at stack-trace.js:62
56 selfRecursive2 at stack-trace.js:62
57 selfRecursive2 at stack-trace.js:62
58 selfRecursive2 at stack-trace.js:62
59 selfRecursive2 at stack-trace.js:62
60 selfRecursive2 at stack-trace.js:62
61 selfRecursive2 at stack-trace.js:62
62 selfRecursive2 at stack-trace.js:62
63 selfRecursive2 at stack-trace.js:62
64 selfRecursive2 at stack-trace.js:62
65 selfRecursive2 at stack-trace.js:62
66 selfRecursive2 at stack-trace.js:62
67 selfRecursive2 at stack-trace.js:62
68 selfRecursive2 at stack-trace.js:62
69 selfRecursive2 at stack-trace.js:62
70 selfRecursive2 at stack-trace.js:62
71 selfRecursive2 at stack-trace.js:62
72 selfRecursive2 at stack-trace.js:62
73 selfRecursive2 at stack-trace.js:62
74 selfRecursive2 at stack-trace.js:62
75 selfRecursive2 at stack-trace.js:62
76 selfRecursive2 at stack-trace.js:62
77 selfRecursive2 at stack-trace.js:62
78 selfRecursive2 at stack-trace.js:62
79 selfRecursive2 at stack-trace.js:62
80 selfRecursive2 at stack-trace.js:62
81 selfRecursive2 at stack-trace.js:62
82 selfRecursive2 at stack-trace.js:62
83 selfRecursive2 at stack-trace.js:62
84 selfRecursive2 at stack-trace.js:62
85 selfRecursive2 at stack-trace.js:62
86 selfRecursive2 at stack-trace.js:62
87 selfRecursive2 at stack-trace.js:62
88 selfRecursive2 at stack-trace.js:62
89 selfRecursive2 at stack-trace.js:62
90 selfRecursive2 at stack-trace.js:62
91 selfRecursive2 at stack-trace.js:62
92 selfRecursive2 at stack-trace.js:62
93 selfRecursive2 at stack-trace.js:62
94 selfRecursive2 at stack-trace.js:62
95 selfRecursive2 at stack-trace.js:62
96 selfRecursive2 at stack-trace.js:62
97 selfRecursive2 at stack-trace.js:62
98 selfRecursive2 at stack-trace.js:62
99 selfRecursive2 at stack-trace.js:62
--> Stack Trace:
0 selfRecursive3 at stack-trace.js:69
1 at eval code
2 eval at [native code]
--> Stack Trace:
0 throwError at stack-trace.js:77
1 valueOf at stack-trace.js:84
2 getter1 at stack-trace.js:87
3 nonInlineable at stack-trace.js:113
4 inlineable at stack-trace.js:121
5 yetAnotherInlinedCall at stack-trace.js:126
6 makeInlinableCall at stack-trace.js:131
7 g at stack-trace.js:140
8 map at [native code]
--> Stack Trace:
0 throwError at stack-trace.js:77
1 getter2 at stack-trace.js:93
2 nonInlineable at stack-trace.js:115
3 inlineable at stack-trace.js:121
4 yetAnotherInlinedCall at stack-trace.js:126
5 makeInlinableCall at stack-trace.js:131
6 g at stack-trace.js:140
7 map at [native code]
--> Stack Trace:
0 throwError at stack-trace.js:77
1 getter3 at stack-trace.js:105
2 nonInlineable at stack-trace.js:117
3 inlineable at stack-trace.js:121
4 yetAnotherInlinedCall at stack-trace.js:126
5 makeInlinableCall at stack-trace.js:131
6 g at stack-trace.js:140
7 map at [native code]
--> Stack Trace:
0 throwError at stack-trace.js:77
1 valueOf at stack-trace.js:101
2 getter3 at stack-trace.js:107
3 nonInlineable at stack-trace.js:117
4 inlineable at stack-trace.js:121
5 yetAnotherInlinedCall at stack-trace.js:126
6 makeInlinableCall at stack-trace.js:131
7 g at stack-trace.js:140
8 map at [native code]
--> Stack Trace:
0 h at stack-trace.js:151
1 map at [native code]
--> Stack Trace:
0 h at stack-trace.js:153
1 map at [native code]
--> Stack Trace:
0 throwError at stack-trace.js:77
1 dfgFunction at stack-trace.js:184
2 map at [native code]
--> Stack Trace:
0 throwError at stack-trace.js:77
1 dfgFunction at stack-trace.js:184
2 f at stack-trace.js:202
3 global code at stack-trace.js:208
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<link rel="stylesheet" href="resources/js-test-style.css">
<script src="resources/js-test-pre.js"></script>
</head>
<body>
<p id="description"></p>
<p id="console"></p>
<script>function htmlInner() { throw new Error("Error in HTML"); }</script>
<script>function htmlOuter() { htmlInner(); }</script>
<script src="script-tests/stack-trace.js"></script>
</body>
</html>
2012-02-16 Oliver Hunt <oliver@apple.com>
Implement Error.stack
https://bugs.webkit.org/show_bug.cgi?id=66994
Reviewed by Gavin Barraclough.
Implement support for stack traces on exception objects. This is a rewrite
of the core portion of the last stack walking logic, but the mechanical work
of adding the information to an exception comes from the original work by
Juan Carlos Montemayor Elosua.
* interpreter/Interpreter.cpp:
(JSC::getCallerInfo):
(JSC):
(JSC::getSourceURLFromCallFrame):
(JSC::getStackFrameCodeType):
(JSC::Interpreter::getStackTrace):
(JSC::Interpreter::throwException):
(JSC::Interpreter::privateExecute):