Title: [182495] trunk
Revision
182495
Author
[email protected]
Date
2015-04-07 14:34:05 -0700 (Tue, 07 Apr 2015)

Log Message

Source and stack information should get appended only to native errors
Source/_javascript_Core:

and should be added directly after construction rather than when thrown.
This fixes frozen objects being unfrozen when thrown while conforming to
ecma script standard and other browser behavior.
rdar://problem/19927293
https://bugs.webkit.org/show_bug.cgi?id=141871

Reviewed by Geoffrey Garen.

Appending stack, source, line, and column information to an object whenever that object is thrown
is incorrect because it violates the ecma script standard for the behavior of throw.  Suppose for example
that the object being thrown already has one of these properties or is frozen.  Adding the properties
would then violate the frozen contract or overwrite those properties.  Other browsers do not do this,
and doing this causes unnecessary performance hits in code with heavy use of the throw construct as
a control flow construct rather than just an error reporting mechanism.

Because WebCore adds "native" errors which do not inherit from any JSC native error,
appending the error properties as a seperate call after construction of the error is required
to avoid having to manually truncate the stack and gather local source information due to
the stack being extended by a nested call to construct one of the native jsc error.

* interpreter/Interpreter.cpp:
(JSC::Interpreter::execute):
* interpreter/Interpreter.h:
* parser/ParserError.h:
(JSC::ParserError::toErrorObject):
* runtime/CommonIdentifiers.h:
* runtime/Error.cpp:
(JSC::createError):
(JSC::createEvalError):
(JSC::createRangeError):
(JSC::createReferenceError):
(JSC::createSyntaxError):
(JSC::createTypeError):
(JSC::createNotEnoughArgumentsError):
(JSC::createURIError):
(JSC::createOutOfMemoryError):
(JSC::FindFirstCallerFrameWithCodeblockFunctor::FindFirstCallerFrameWithCodeblockFunctor):
(JSC::FindFirstCallerFrameWithCodeblockFunctor::operator()):
(JSC::FindFirstCallerFrameWithCodeblockFunctor::foundCallFrame):
(JSC::FindFirstCallerFrameWithCodeblockFunctor::index):
(JSC::addErrorInfoAndGetBytecodeOffset):  Added.
(JSC::addErrorInfo): Added special case for appending complete error info
to a newly constructed error object.
* runtime/Error.h:
* runtime/ErrorConstructor.cpp:
(JSC::Interpreter::constructWithErrorConstructor):
(JSC::Interpreter::callErrorConstructor):
* runtime/ErrorInstance.cpp:
(JSC::appendSourceToError): Moved from VM.cpp
(JSC::FindFirstCallerFrameWithCodeblockFunctor::FindFirstCallerFrameWithCodeblockFunctor):
(JSC::FindFirstCallerFrameWithCodeblockFunctor::operator()):
(JSC::FindFirstCallerFrameWithCodeblockFunctor::foundCallFrame):
(JSC::FindFirstCallerFrameWithCodeblockFunctor::index):
(JSC::addErrorInfoAndGetBytecodeOffset):
(JSC::ErrorInstance::finishCreation):
* runtime/ErrorInstance.h:
(JSC::ErrorInstance::create):
* runtime/ErrorPrototype.cpp:
(JSC::ErrorPrototype::finishCreation):
* runtime/ExceptionFuzz.cpp:
(JSC::doExceptionFuzzing):
* runtime/ExceptionHelpers.cpp:
(JSC::createError):
(JSC::createInvalidFunctionApplyParameterError):
(JSC::createInvalidInParameterError):
(JSC::createInvalidInstanceofParameterError):
(JSC::createNotAConstructorError):
(JSC::createNotAFunctionError):
(JSC::createNotAnObjectError):
(JSC::throwOutOfMemoryError):
(JSC::createStackOverflowError): Deleted.
(JSC::createOutOfMemoryError): Deleted.
* runtime/ExceptionHelpers.h:
* runtime/JSArrayBufferConstructor.cpp:
(JSC::constructArrayBuffer):
* runtime/JSArrayBufferPrototype.cpp:
(JSC::arrayBufferProtoFuncSlice):
* runtime/JSGenericTypedArrayViewInlines.h:
(JSC::JSGenericTypedArrayView<Adaptor>::create):
(JSC::JSGenericTypedArrayView<Adaptor>::createUninitialized):
* runtime/NativeErrorConstructor.cpp:
(JSC::Interpreter::constructWithNativeErrorConstructor):
(JSC::Interpreter::callNativeErrorConstructor):
* runtime/VM.cpp:
(JSC::VM::throwException):
(JSC::appendSourceToError): Moved to Error.cpp
(JSC::FindFirstCallerFrameWithCodeblockFunctor::FindFirstCallerFrameWithCodeblockFunctor): Deleted.
(JSC::FindFirstCallerFrameWithCodeblockFunctor::operator()): Deleted.
(JSC::FindFirstCallerFrameWithCodeblockFunctor::foundCallFrame): Deleted.
(JSC::FindFirstCallerFrameWithCodeblockFunctor::index): Deleted.
* tests/stress/freeze_leek.js: Added.

Source/WebCore:

and should be added directly after construction rather than when thrown.
This fixes frozen objects being unfrozen when thrown while conforming to
ecma script standard and other browser behavior.
rdar://problem/19927293
https://bugs.webkit.org/show_bug.cgi?id=141871

Reviewed by Geoffrey Garen.

Covered by existing tests.

Sets line, column, source and stack information for DOMExceptions as
expected by the webinspector for native errors.

* bindings/js/JSDOMBinding.cpp:
(WebCore::setDOMException):

LayoutTests:

and should be added after construction rather than when thrown.
This fixes frozen objects being unfrozen when thrown while conforming to
ecma script standard and other browser behavior.
rdar://problem/19927293
https://bugs.webkit.org/show_bug.cgi?id=141871

Reviewed by Geoffrey Garen.

Fixes tests to throw new Errors such that they will contain line, column, and stack information
as expected, and fixes the column in the error in the expected output.

* http/tests/w3c/resources/testharness.js:  Other browsers don't expect stack information
with this test, but we do, and so the AssertionError should include stack information gathered from Error.
This could also have been fixed by changing expectations, but its a good idea to check the stack anyway.
* js/dom/exception-linenums-in-html-1.html: Throw "new Error()" rather than "{}".
* js/dom/exception-linenums-in-html-2.html: ditto.
* js/dom/exception-linenums-in-html-3.html: ditto.
* js/dom/script-tests/stack-trace.js: ditto.
(throwError): ditto.
(h): ditto.
(inlineableThrow): ditto.
(dfgThing.get willThrow): ditto.
(dfgThing.willThrowFunc): ditto.
* js/dom/stack-trace-expected.txt: fixed error column expectation.
* js/exception-properties-expected.txt: ditto.
* js/script-tests/exception-linenums.js:
(exceptionInFunction): throw "new Error()" rather than "{}".
(firstPropIsGetter.get getter): ditto
(secondPropIsGetter.get getter): ditto
(firstPropIsSetter.set setter): ditto
(secondPropIsSetter.set setter): ditto
* js/script-tests/exception-properties.js: now checking that column, line, and sourceURL are existant on a "new Error"
since we now add these at error construction rather than at error throwing.
* platform/mac/http/tests/media/media-source/mediasource-addsourcebuffer-expected.txt: fixed expectation to match.
* platform/mac/http/tests/media/media-source/mediasource-sourcebuffer-mode-expected.txt: ditto.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (182494 => 182495)


--- trunk/LayoutTests/ChangeLog	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/LayoutTests/ChangeLog	2015-04-07 21:34:05 UTC (rev 182495)
@@ -1,3 +1,42 @@
+2015-04-07  Matthew Mirman  <[email protected]>
+
+        Source and stack information should get appended only to native errors
+        and should be added after construction rather than when thrown.
+        This fixes frozen objects being unfrozen when thrown while conforming to 
+        ecma script standard and other browser behavior.
+        rdar://problem/19927293
+        https://bugs.webkit.org/show_bug.cgi?id=141871
+        
+        Reviewed by Geoffrey Garen.
+
+        Fixes tests to throw new Errors such that they will contain line, column, and stack information 
+        as expected, and fixes the column in the error in the expected output.
+        
+        * http/tests/w3c/resources/testharness.js:  Other browsers don't expect stack information
+        with this test, but we do, and so the AssertionError should include stack information gathered from Error. 
+        This could also have been fixed by changing expectations, but its a good idea to check the stack anyway.
+        * js/dom/exception-linenums-in-html-1.html: Throw "new Error()" rather than "{}".
+        * js/dom/exception-linenums-in-html-2.html: ditto.
+        * js/dom/exception-linenums-in-html-3.html: ditto.
+        * js/dom/script-tests/stack-trace.js: ditto.
+        (throwError): ditto.
+        (h): ditto.
+        (inlineableThrow): ditto.
+        (dfgThing.get willThrow): ditto.
+        (dfgThing.willThrowFunc): ditto.
+        * js/dom/stack-trace-expected.txt: fixed error column expectation. 
+        * js/exception-properties-expected.txt: ditto.
+        * js/script-tests/exception-linenums.js:
+        (exceptionInFunction): throw "new Error()" rather than "{}".
+        (firstPropIsGetter.get getter): ditto
+        (secondPropIsGetter.get getter): ditto
+        (firstPropIsSetter.set setter): ditto
+        (secondPropIsSetter.set setter): ditto
+        * js/script-tests/exception-properties.js: now checking that column, line, and sourceURL are existant on a "new Error"
+        since we now add these at error construction rather than at error throwing.
+        * platform/mac/http/tests/media/media-source/mediasource-addsourcebuffer-expected.txt: fixed expectation to match. 
+        * platform/mac/http/tests/media/media-source/mediasource-sourcebuffer-mode-expected.txt: ditto.
+
 2015-04-07  Joseph Pecoraro  <[email protected]>
 
         Web Inspector: ES6: Show Symbol properties on Objects

Modified: trunk/LayoutTests/http/tests/w3c/resources/testharness.js (182494 => 182495)


--- trunk/LayoutTests/http/tests/w3c/resources/testharness.js	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/LayoutTests/http/tests/w3c/resources/testharness.js	2015-04-07 21:34:05 UTC (rev 182495)
@@ -2064,6 +2064,8 @@
 
     function AssertionError(message)
     {
+        var e = new Error();
+        this.stack = e.stack.substring(e.stack.indexOf('\n')+1, e.stack.length);
         this.message = message;
     }
 

Modified: trunk/LayoutTests/js/dom/exception-linenums-in-html-1.html (182494 => 182495)


--- trunk/LayoutTests/js/dom/exception-linenums-in-html-1.html	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/LayoutTests/js/dom/exception-linenums-in-html-1.html	2015-04-07 21:34:05 UTC (rev 182495)
@@ -8,7 +8,7 @@
 
 function exceptionInFunction()
 {
-    throw Exception();
+    throw new Error();
 }
 
 var e = undefined;

Modified: trunk/LayoutTests/js/dom/exception-linenums-in-html-2.html (182494 => 182495)


--- trunk/LayoutTests/js/dom/exception-linenums-in-html-2.html	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/LayoutTests/js/dom/exception-linenums-in-html-2.html	2015-04-07 21:34:05 UTC (rev 182495)
@@ -8,7 +8,7 @@
 
 function exceptionInFunction()
 {
-    throw Exception();
+    throw new Error();
 }
 
 var e = undefined;

Modified: trunk/LayoutTests/js/dom/exception-linenums-in-html-3.html (182494 => 182495)


--- trunk/LayoutTests/js/dom/exception-linenums-in-html-3.html	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/LayoutTests/js/dom/exception-linenums-in-html-3.html	2015-04-07 21:34:05 UTC (rev 182495)
@@ -10,7 +10,7 @@
 
 function exceptionInFunction()
 {
-    throw Exception();
+    throw new Error();
 }
 
 var e = undefined;

Modified: trunk/LayoutTests/js/dom/script-tests/stack-trace.js (182494 => 182495)


--- trunk/LayoutTests/js/dom/script-tests/stack-trace.js	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/LayoutTests/js/dom/script-tests/stack-trace.js	2015-04-07 21:34:05 UTC (rev 182495)
@@ -136,7 +136,7 @@
 var callCount = 0;
 
 function throwError() {
-    throw {};
+    throw new Error();
 }
 
 var object = {
@@ -210,7 +210,7 @@
 
 function h() {
     if (callCount++ == 1000)
-        throw {};
+        throw new Error();
     if (callCount > 1000) {
         [].map.apply(undefined, throwError);
     }
@@ -299,18 +299,18 @@
 }
 
 function inlineableThrow() {
-    if (dfgCount > 500) throw {};
+    if (dfgCount > 500) throw new Error();
 }
 
 var dfgThing = {
     get willThrow() {
         if (dfgCount > 500)
-            throw {};
+            throw new Error();
     },
     get willThrowEventually() {
         inlineableThrow();
     },
-    willThrowFunc: function () { if (dfgCount > 500) throw {}; },
+    willThrowFunc: function () { if (dfgCount > 500) throw new Error(); },
     willThrowEventuallyFunc: function () { inlineableThrow(); }
 }
 dfgThing.__defineGetter__("hostWillThrow", hostThrower);

Modified: trunk/LayoutTests/js/dom/stack-trace-expected.txt (182494 => 182495)


--- trunk/LayoutTests/js/dom/stack-trace-expected.txt	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/LayoutTests/js/dom/stack-trace-expected.txt	2015-04-07 21:34:05 UTC (rev 182495)
@@ -258,7 +258,7 @@
     2   selfRecursive3 at stack-trace.js
 
 --> Stack Trace:
-    0   throwError at stack-trace.js:139:13
+    0   throwError at stack-trace.js:139:20
     1   valueOf at stack-trace.js:146:27
     2   getter1 at stack-trace.js:149:11
     3   nonInlineable at stack-trace.js:175:17
@@ -270,7 +270,7 @@
     9   global code at stack-trace.js:205:16
 
 --> Stack Trace:
-    0   throwError at stack-trace.js:139:13
+    0   throwError at stack-trace.js:139:20
     1   getter2 at stack-trace.js:155:11
     2   nonInlineable at stack-trace.js:177:17
     3   inlineable at stack-trace.js:183:27
@@ -281,7 +281,7 @@
     8   global code at stack-trace.js:205:16
 
 --> Stack Trace:
-    0   throwError at stack-trace.js:139:13
+    0   throwError at stack-trace.js:139:20
     1   getter3 at stack-trace.js:167:16
     2   nonInlineable at stack-trace.js:179:17
     3   inlineable at stack-trace.js:183:27
@@ -292,7 +292,7 @@
     8   global code at stack-trace.js:205:16
 
 --> Stack Trace:
-    0   throwError at stack-trace.js:139:13
+    0   throwError at stack-trace.js:139:20
     1   valueOf at stack-trace.js:163:27
     2   getter3 at stack-trace.js:169:16
     3   nonInlineable at stack-trace.js:179:17
@@ -304,7 +304,7 @@
     9   global code at stack-trace.js:205:16
 
 --> Stack Trace:
-    0   h at stack-trace.js:213:17
+    0   h at stack-trace.js:213:24
     1   map at [native code]
     2   mapTest at stack-trace.js:220:10
     3   mapTestDriver at stack-trace.js:226:16
@@ -319,19 +319,19 @@
     5   global code at stack-trace.js:237:18
 
 --> Stack Trace:
-    0   throwError at stack-trace.js:139:13
+    0   throwError at stack-trace.js:139:20
     1   dfgFunction at stack-trace.js:246:19
     2   map at [native code]
     3   global code at stack-trace.js:255:18
 
 --> Stack Trace:
-    0   throwError at stack-trace.js:139:13
+    0   throwError at stack-trace.js:139:20
     1   dfgFunction at stack-trace.js:246:19
     2   f at stack-trace.js:264:10
     3   global code at stack-trace.js:270:6
 
 --> Stack Trace:
-    0   willThrow at stack-trace.js:308:21
+    0   willThrow at stack-trace.js:308:28
     1   dfg1 at stack-trace.js:319:13
     2   dfg2 at stack-trace.js:323:9
     3   dfg3 at stack-trace.js:327:9
@@ -339,7 +339,7 @@
     5   global code at stack-trace.js:366:8
 
 --> Stack Trace:
-    0   willThrowFunc at stack-trace.js:313:62
+    0   willThrowFunc at stack-trace.js:313:69
     1   dfg4 at stack-trace.js:331:27
     2   dfg5 at stack-trace.js:335:9
     3   dfg6 at stack-trace.js:339:9
@@ -347,7 +347,7 @@
     5   global code at stack-trace.js:367:8
 
 --> Stack Trace:
-    0   inlineableThrow at stack-trace.js:302:33
+    0   inlineableThrow at stack-trace.js:302:40
     1   willThrowEventually at stack-trace.js:311:24
     2   dfg7 at stack-trace.js:343:13
     3   dfg8 at stack-trace.js:347:9
@@ -356,7 +356,7 @@
     6   global code at stack-trace.js:368:8
 
 --> Stack Trace:
-    0   inlineableThrow at stack-trace.js:302:33
+    0   inlineableThrow at stack-trace.js:302:40
     1   willThrowEventuallyFunc at stack-trace.js:314:59
     2   dfga at stack-trace.js:355:37
     3   dfgb at stack-trace.js:359:9

Modified: trunk/LayoutTests/js/exception-properties-expected.txt (182494 => 182495)


--- trunk/LayoutTests/js/exception-properties-expected.txt	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/LayoutTests/js/exception-properties-expected.txt	2015-04-07 21:34:05 UTC (rev 182495)
@@ -3,7 +3,7 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS enumerableProperties(error) is []
+PASS enumerableProperties(error).sort() is ["column", "line", "sourceURL"]
 PASS enumerableProperties(nativeError).sort() is ["column", "line", "sourceURL"]
 PASS Object.getPrototypeOf(nativeError).name is "RangeError"
 PASS Object.getPrototypeOf(nativeError).message is ""

Modified: trunk/LayoutTests/js/script-tests/exception-linenums.js (182494 => 182495)


--- trunk/LayoutTests/js/script-tests/exception-linenums.js	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/LayoutTests/js/script-tests/exception-linenums.js	2015-04-07 21:34:05 UTC (rev 182495)
@@ -2,7 +2,7 @@
 
 function exceptionInFunction()
 {
-    throw Exception();
+    throw new Error();
 }
 
 var e = undefined;
@@ -71,18 +71,18 @@
 shouldBe("e.line", '64');
 
 var firstPropIsGetter = {
-    get getter() { throw {} }
+    get getter() { throw new Error() }
 };
 var secondPropIsGetter = {
     prop: 1,
-    get getter() { throw {} }
+    get getter() { throw new Error() }
 };
 var firstPropIsSetter = {
-    set setter(a) { throw {} }
+    set setter(a) { throw new Error() }
 };
 var secondPropIsSetter = {
     prop: 1,
-    set setter(a) { throw {} }
+    set setter(a) { throw new Error() }
 };
 
 try {

Modified: trunk/LayoutTests/js/script-tests/exception-properties.js (182494 => 182495)


--- trunk/LayoutTests/js/script-tests/exception-properties.js	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/LayoutTests/js/script-tests/exception-properties.js	2015-04-07 21:34:05 UTC (rev 182495)
@@ -15,7 +15,7 @@
     var nativeError = rangeError;
     var error = new Error("message");
 
-    shouldBe('enumerableProperties(error)', '[]');
+    shouldBe('enumerableProperties(error).sort()', '["column", "line", "sourceURL"]');
     shouldBe('enumerableProperties(nativeError).sort()', '["column", "line", "sourceURL"]');
 
     shouldBe('Object.getPrototypeOf(nativeError).name', '"RangeError"');

Modified: trunk/LayoutTests/platform/mac/http/tests/media/media-source/mediasource-addsourcebuffer-expected.txt (182494 => 182495)


--- trunk/LayoutTests/platform/mac/http/tests/media/media-source/mediasource-addsourcebuffer-expected.txt	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/LayoutTests/platform/mac/http/tests/media/media-source/mediasource-addsourcebuffer-expected.txt	2015-04-07 21:34:05 UTC (rev 182495)
@@ -1,14 +1,14 @@
  
 PASS Test addSourceBuffer() with empty type 
 PASS Test addSourceBuffer() with unsupported type 
-FAIL Test addSourceBuffer() with Vorbis and VP8 assert_true: video/webm;codecs="vp8,vorbis" is supported expected true got false(stack: assert@http://127.0.0.1:8000/w3c/resources/testharness.js:2061:73
+FAIL Test addSourceBuffer() with Vorbis and VP8 assert_true: video/webm;codecs="vp8,vorbis" is supported expected true got false(stack: assert@http://127.0.0.1:8000/w3c/resources/testharness.js:2060:37
 assert_true@http://127.0.0.1:8000/w3c/resources/testharness.js:663:15
 http://127.0.0.1:8000/media/media-source/mediasource-addsourcebuffer.html:32:26
 http://127.0.0.1:8000/media/media-source/mediasource-util.js:339:29
 onSourceOpen@http://127.0.0.1:8000/media/media-source/mediasource-util.js:149:21
 step@http://127.0.0.1:8000/w3c/resources/testharness.js:1160:30
 http://127.0.0.1:8000/w3c/resources/testharness.js:1189:33)
-FAIL Test addSourceBuffer() with Vorbis and VP8 in separate SourceBuffers assert_true: video/webm;codecs="vp8" is supported expected true got false(stack: assert@http://127.0.0.1:8000/w3c/resources/testharness.js:2061:73
+FAIL Test addSourceBuffer() with Vorbis and VP8 in separate SourceBuffers assert_true: video/webm;codecs="vp8" is supported expected true got false(stack: assert@http://127.0.0.1:8000/w3c/resources/testharness.js:2060:37
 assert_true@http://127.0.0.1:8000/w3c/resources/testharness.js:663:15
 http://127.0.0.1:8000/media/media-source/mediasource-addsourcebuffer.html:46:26
 http://127.0.0.1:8000/media/media-source/mediasource-util.js:339:29

Modified: trunk/LayoutTests/platform/mac/http/tests/media/media-source/mediasource-sourcebuffer-mode-expected.txt (182494 => 182495)


--- trunk/LayoutTests/platform/mac/http/tests/media/media-source/mediasource-sourcebuffer-mode-expected.txt	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/LayoutTests/platform/mac/http/tests/media/media-source/mediasource-sourcebuffer-mode-expected.txt	2015-04-07 21:34:05 UTC (rev 182495)
@@ -4,7 +4,7 @@
 PASS Test setting a removed SourceBuffer's mode 
 PASS Test setting SourceBuffer.mode while still updating 
 PASS Test setting SourceBuffer.mode triggers parent MediaSource 'ended' to 'open' transition. 
-FAIL Test setting SourceBuffer.mode and SourceBuffer.timestampOffset while parsing media segment. assert_throws: Setting valid sourceBuffer.mode while still parsing media segment threw InvalidStateError. function "function () { sourceBuffer.mode = 'segments'; }" did not throw(stack: assert@http://127.0.0.1:8000/w3c/resources/testharness.js:2061:73
+FAIL Test setting SourceBuffer.mode and SourceBuffer.timestampOffset while parsing media segment. assert_throws: Setting valid sourceBuffer.mode while still parsing media segment threw InvalidStateError. function "function () { sourceBuffer.mode = 'segments'; }" did not throw(stack: assert@http://127.0.0.1:8000/w3c/resources/testharness.js:2060:37
 assert_throws@http://127.0.0.1:8000/w3c/resources/testharness.js:947:19
 http://127.0.0.1:8000/media/media-source/mediasource-sourcebuffer-mode.html:114:32
 handleWaitCallback_@http://127.0.0.1:8000/media/media-source/mediasource-util.js:97:17

Modified: trunk/Source/_javascript_Core/ChangeLog (182494 => 182495)


--- trunk/Source/_javascript_Core/ChangeLog	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-04-07 21:34:05 UTC (rev 182495)
@@ -1,3 +1,98 @@
+2015-04-07  Matthew Mirman  <[email protected]>
+
+        Source and stack information should get appended only to native errors
+        and should be added directly after construction rather than when thrown. 
+        This fixes frozen objects being unfrozen when thrown while conforming to 
+        ecma script standard and other browser behavior.
+        rdar://problem/19927293
+        https://bugs.webkit.org/show_bug.cgi?id=141871
+        
+        Reviewed by Geoffrey Garen.
+
+        Appending stack, source, line, and column information to an object whenever that object is thrown 
+        is incorrect because it violates the ecma script standard for the behavior of throw.  Suppose for example
+        that the object being thrown already has one of these properties or is frozen.  Adding the properties 
+        would then violate the frozen contract or overwrite those properties.  Other browsers do not do this,
+        and doing this causes unnecessary performance hits in code with heavy use of the throw construct as
+        a control flow construct rather than just an error reporting mechanism.  
+        
+        Because WebCore adds "native" errors which do not inherit from any JSC native error, 
+        appending the error properties as a seperate call after construction of the error is required 
+        to avoid having to manually truncate the stack and gather local source information due to 
+        the stack being extended by a nested call to construct one of the native jsc error.
+        
+        * interpreter/Interpreter.cpp:
+        (JSC::Interpreter::execute):
+        * interpreter/Interpreter.h:
+        * parser/ParserError.h:
+        (JSC::ParserError::toErrorObject):
+        * runtime/CommonIdentifiers.h:
+        * runtime/Error.cpp:
+        (JSC::createError):
+        (JSC::createEvalError):
+        (JSC::createRangeError):
+        (JSC::createReferenceError):
+        (JSC::createSyntaxError):
+        (JSC::createTypeError):
+        (JSC::createNotEnoughArgumentsError):
+        (JSC::createURIError):
+        (JSC::createOutOfMemoryError):
+        (JSC::FindFirstCallerFrameWithCodeblockFunctor::FindFirstCallerFrameWithCodeblockFunctor):
+        (JSC::FindFirstCallerFrameWithCodeblockFunctor::operator()):
+        (JSC::FindFirstCallerFrameWithCodeblockFunctor::foundCallFrame):
+        (JSC::FindFirstCallerFrameWithCodeblockFunctor::index):
+        (JSC::addErrorInfoAndGetBytecodeOffset):  Added.
+        (JSC::addErrorInfo): Added special case for appending complete error info 
+        to a newly constructed error object.
+        * runtime/Error.h:
+        * runtime/ErrorConstructor.cpp:
+        (JSC::Interpreter::constructWithErrorConstructor):
+        (JSC::Interpreter::callErrorConstructor):
+        * runtime/ErrorInstance.cpp:
+        (JSC::appendSourceToError): Moved from VM.cpp
+        (JSC::FindFirstCallerFrameWithCodeblockFunctor::FindFirstCallerFrameWithCodeblockFunctor):
+        (JSC::FindFirstCallerFrameWithCodeblockFunctor::operator()):
+        (JSC::FindFirstCallerFrameWithCodeblockFunctor::foundCallFrame):
+        (JSC::FindFirstCallerFrameWithCodeblockFunctor::index):
+        (JSC::addErrorInfoAndGetBytecodeOffset):
+        (JSC::ErrorInstance::finishCreation):
+        * runtime/ErrorInstance.h:
+        (JSC::ErrorInstance::create):
+        * runtime/ErrorPrototype.cpp:
+        (JSC::ErrorPrototype::finishCreation):
+        * runtime/ExceptionFuzz.cpp:
+        (JSC::doExceptionFuzzing):
+        * runtime/ExceptionHelpers.cpp:
+        (JSC::createError):
+        (JSC::createInvalidFunctionApplyParameterError):
+        (JSC::createInvalidInParameterError):
+        (JSC::createInvalidInstanceofParameterError):
+        (JSC::createNotAConstructorError):
+        (JSC::createNotAFunctionError):
+        (JSC::createNotAnObjectError):
+        (JSC::throwOutOfMemoryError):
+        (JSC::createStackOverflowError): Deleted.
+        (JSC::createOutOfMemoryError): Deleted.
+        * runtime/ExceptionHelpers.h:
+        * runtime/JSArrayBufferConstructor.cpp:
+        (JSC::constructArrayBuffer):
+        * runtime/JSArrayBufferPrototype.cpp:
+        (JSC::arrayBufferProtoFuncSlice):
+        * runtime/JSGenericTypedArrayViewInlines.h:
+        (JSC::JSGenericTypedArrayView<Adaptor>::create):
+        (JSC::JSGenericTypedArrayView<Adaptor>::createUninitialized):
+        * runtime/NativeErrorConstructor.cpp:
+        (JSC::Interpreter::constructWithNativeErrorConstructor):
+        (JSC::Interpreter::callNativeErrorConstructor):
+        * runtime/VM.cpp:
+        (JSC::VM::throwException):
+        (JSC::appendSourceToError): Moved to Error.cpp
+        (JSC::FindFirstCallerFrameWithCodeblockFunctor::FindFirstCallerFrameWithCodeblockFunctor): Deleted.
+        (JSC::FindFirstCallerFrameWithCodeblockFunctor::operator()): Deleted.
+        (JSC::FindFirstCallerFrameWithCodeblockFunctor::foundCallFrame): Deleted.
+        (JSC::FindFirstCallerFrameWithCodeblockFunctor::index): Deleted.
+        * tests/stress/freeze_leek.js: Added.
+
 2015-04-07  Joseph Pecoraro  <[email protected]>
 
         Web Inspector: ES6: Show Symbol properties on Objects

Modified: trunk/Source/_javascript_Core/interpreter/Interpreter.cpp (182494 => 182495)


--- trunk/Source/_javascript_Core/interpreter/Interpreter.cpp	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/Source/_javascript_Core/interpreter/Interpreter.cpp	2015-04-07 21:34:05 UTC (rev 182495)
@@ -763,7 +763,7 @@
                         PropertySlot slot(globalObject);
                         if (!globalObject->getPropertySlot(callFrame, JSONPPath[i].m_pathEntryName, slot)) {
                             if (entry)
-                                return callFrame->vm().throwException(callFrame, createUndefinedVariableError(globalObject->globalExec(), JSONPPath[i].m_pathEntryName));
+                                return callFrame->vm().throwException(callFrame, createUndefinedVariableError(callFrame, JSONPPath[i].m_pathEntryName));
                             goto failedJSONP;
                         }
                         baseObject = slot.getValue(callFrame, JSONPPath[i].m_pathEntryName);

Modified: trunk/Source/_javascript_Core/interpreter/Interpreter.h (182494 => 182495)


--- trunk/Source/_javascript_Core/interpreter/Interpreter.h	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/Source/_javascript_Core/interpreter/Interpreter.h	2015-04-07 21:34:05 UTC (rev 182495)
@@ -267,6 +267,8 @@
 
         JS_EXPORT_PRIVATE void dumpCallFrame(CallFrame*);
 
+        void getStackTrace(Vector<StackFrame>& results, size_t maxStackSize = std::numeric_limits<size_t>::max());
+
     private:
         enum ExecutionFlag { Normal, InitializeAndReturn };
 
@@ -274,8 +276,8 @@
 
         JSValue execute(CallFrameClosure&);
 
-        void getStackTrace(Vector<StackFrame>& results, size_t maxStackSize = std::numeric_limits<size_t>::max());
 
+
         void dumpRegisters(CallFrame*);
         
         bool isCallBytecode(Opcode opcode) { return opcode == getOpcode(op_call) || opcode == getOpcode(op_construct) || opcode == getOpcode(op_call_eval); }

Modified: trunk/Source/_javascript_Core/parser/ParserError.h (182494 => 182495)


--- trunk/Source/_javascript_Core/parser/ParserError.h	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/Source/_javascript_Core/parser/ParserError.h	2015-04-07 21:34:05 UTC (rev 182495)
@@ -89,22 +89,23 @@
         JSGlobalObject* globalObject, const SourceCode& source, 
         int overrideLineNumber = -1)
     {
+        ExecState* exec = globalObject->globalExec();
         switch (m_type) {
         case ErrorNone:
             return nullptr;
         case SyntaxError:
             return addErrorInfo(
-                globalObject->globalExec(), 
-                createSyntaxError(globalObject, m_message), 
+                exec, 
+                createSyntaxError(exec, m_message), 
                 overrideLineNumber == -1 ? m_line : overrideLineNumber, source);
         case EvalError:
-            return createSyntaxError(globalObject, m_message);
+            return createSyntaxError(exec, m_message);
         case StackOverflow: {
             ErrorHandlingScope errorScope(globalObject->vm());
-            return createStackOverflowError(globalObject);
+            return createStackOverflowError(exec);
         }
         case OutOfMemory:
-            return createOutOfMemoryError(globalObject);
+            return createOutOfMemoryError(exec);
         }
         CRASH();
         return nullptr;

Modified: trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h (182494 => 182495)


--- trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h	2015-04-07 21:34:05 UTC (rev 182495)
@@ -82,6 +82,7 @@
     macro(clear) \
     macro(close) \
     macro(closed) \
+    macro(column) \
     macro(compilationKind) \
     macro(compilations) \
     macro(compile) \
@@ -127,6 +128,7 @@
     macro(keys) \
     macro(lastIndex) \
     macro(length) \
+    macro(line) \
     macro(message) \
     macro(multiline) \
     macro(name) \
@@ -153,6 +155,7 @@
     macro(size) \
     macro(slice) \
     macro(source) \
+    macro(sourceURL) \
     macro(sourceCode) \
     macro(stack) \
     macro(subarray) \

Modified: trunk/Source/_javascript_Core/runtime/Error.cpp (182494 => 182495)


--- trunk/Source/_javascript_Core/runtime/Error.cpp	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/Source/_javascript_Core/runtime/Error.cpp	2015-04-07 21:34:05 UTC (rev 182495)
@@ -44,91 +44,150 @@
 static const char* linePropertyName = "line";
 static const char* sourceURLPropertyName = "sourceURL";
 
-JSObject* createError(JSGlobalObject* globalObject, const String& message)
+JSObject* createError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender)
 {
     ASSERT(!message.isEmpty());
-    return ErrorInstance::create(globalObject->vm(), globalObject->errorStructure(), message);
+    JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+    return ErrorInstance::create(exec, globalObject->vm(), globalObject->errorStructure(), message, appender, TypeNothing, true);
 }
 
-JSObject* createEvalError(JSGlobalObject* globalObject, const String& message)
+JSObject* createEvalError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender)
 {
     ASSERT(!message.isEmpty());
-    return ErrorInstance::create(globalObject->vm(), globalObject->evalErrorConstructor()->errorStructure(), message);
+    JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+    return ErrorInstance::create(exec, globalObject->vm(), globalObject->evalErrorConstructor()->errorStructure(), message, appender, TypeNothing, true);
 }
 
-JSObject* createRangeError(JSGlobalObject* globalObject, const String& message)
+JSObject* createRangeError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender)
 {
     ASSERT(!message.isEmpty());
-    return ErrorInstance::create(globalObject->vm(), globalObject->rangeErrorConstructor()->errorStructure(), message);
+    JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+    return ErrorInstance::create(exec, globalObject->vm(), globalObject->rangeErrorConstructor()->errorStructure(), message, appender, TypeNothing, true);
 }
 
-JSObject* createReferenceError(JSGlobalObject* globalObject, const String& message)
+JSObject* createReferenceError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender)
 {
     ASSERT(!message.isEmpty());
-    return ErrorInstance::create(globalObject->vm(), globalObject->referenceErrorConstructor()->errorStructure(), message);
+    JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+    return ErrorInstance::create(exec, globalObject->vm(), globalObject->referenceErrorConstructor()->errorStructure(), message, appender, TypeNothing, true);
 }
 
-JSObject* createSyntaxError(JSGlobalObject* globalObject, const String& message)
+JSObject* createSyntaxError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender)
 {
     ASSERT(!message.isEmpty());
-    return ErrorInstance::create(globalObject->vm(), globalObject->syntaxErrorConstructor()->errorStructure(), message);
+    JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+    return ErrorInstance::create(exec, globalObject->vm(), globalObject->syntaxErrorConstructor()->errorStructure(), message, appender, TypeNothing, true);
 }
 
-JSObject* createTypeError(JSGlobalObject* globalObject, const String& message)
+JSObject* createTypeError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender, RuntimeType type)
 {
     ASSERT(!message.isEmpty());
-    return ErrorInstance::create(globalObject->vm(), globalObject->typeErrorConstructor()->errorStructure(), message);
+    JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+    return ErrorInstance::create(exec, globalObject->vm(), globalObject->typeErrorConstructor()->errorStructure(), message, appender, type, true);
 }
 
-JSObject* createNotEnoughArgumentsError(JSGlobalObject* globalObject)
+JSObject* createNotEnoughArgumentsError(ExecState* exec, ErrorInstance::SourceAppender appender)
 {
-    return createTypeError(globalObject, ASCIILiteral("Not enough arguments"));
+    return createTypeError(exec, ASCIILiteral("Not enough arguments"), appender, TypeNothing);
 }
 
-JSObject* createURIError(JSGlobalObject* globalObject, const String& message)
+JSObject* createURIError(ExecState* exec, const String& message, ErrorInstance::SourceAppender appender)
 {
     ASSERT(!message.isEmpty());
-    return ErrorInstance::create(globalObject->vm(), globalObject->URIErrorConstructor()->errorStructure(), message);
+    JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+    return ErrorInstance::create(exec, globalObject->vm(), globalObject->URIErrorConstructor()->errorStructure(), message, appender, TypeNothing, true);
 }
 
-JSObject* createError(ExecState* exec, const String& message)
+JSObject* createOutOfMemoryError(ExecState* exec, ErrorInstance::SourceAppender appender) 
 {
-    return createError(exec->lexicalGlobalObject(), message);
+    return createError(exec, ASCIILiteral("Out of memory"), appender);
 }
 
-JSObject* createEvalError(ExecState* exec, const String& message)
-{
-    return createEvalError(exec->lexicalGlobalObject(), message);
-}
 
-JSObject* createRangeError(ExecState* exec, const String& message)
-{
-    return createRangeError(exec->lexicalGlobalObject(), message);
-}
+class FindFirstCallerFrameWithCodeblockFunctor {
+public:
+    FindFirstCallerFrameWithCodeblockFunctor(CallFrame* startCallFrame)
+        : m_startCallFrame(startCallFrame)
+        , m_foundCallFrame(nullptr)
+        , m_foundStartCallFrame(false)
+        , m_index(0)
+    { }
 
-JSObject* createReferenceError(ExecState* exec, const String& message)
-{
-    return createReferenceError(exec->lexicalGlobalObject(), message);
-}
+    StackVisitor::Status operator()(StackVisitor& visitor)
+    {
+        if (!m_foundStartCallFrame && (visitor->callFrame() == m_startCallFrame))
+            m_foundStartCallFrame = true;
 
-JSObject* createSyntaxError(ExecState* exec, const String& message)
-{
-    return createSyntaxError(exec->lexicalGlobalObject(), message);
-}
+        if (m_foundStartCallFrame) {
+            if (visitor->callFrame()->codeBlock()) {
+                m_foundCallFrame = visitor->callFrame();
+                return StackVisitor::Done;
+            }
+            m_index++;
+        }
 
-JSObject* createTypeError(ExecState* exec, const String& message)
+        return StackVisitor::Continue;
+    }
+
+    CallFrame* foundCallFrame() const { return m_foundCallFrame; }
+    unsigned index() const { return m_index; }
+
+private:
+    CallFrame* m_startCallFrame;
+    CallFrame* m_foundCallFrame;
+    bool m_foundStartCallFrame;
+    unsigned m_index;
+};
+
+bool addErrorInfoAndGetBytecodeOffset(ExecState* exec, VM& vm, JSObject* obj, bool useCurrentFrame, CallFrame*& callFrame, unsigned &bytecodeOffset) 
 {
-    return createTypeError(exec->lexicalGlobalObject(), message);
-}
+    Vector<StackFrame> stackTrace = Vector<StackFrame>();
 
-JSObject* createNotEnoughArgumentsError(ExecState* exec)
-{
-    return createNotEnoughArgumentsError(exec->lexicalGlobalObject());
+    if (exec && stackTrace.isEmpty())
+        vm.interpreter->getStackTrace(stackTrace);
+
+    if (!stackTrace.isEmpty()) {
+
+        ASSERT(exec == vm.topCallFrame || exec == exec->lexicalGlobalObject()->globalExec() || exec == exec->vmEntryGlobalObject()->globalExec());
+
+        StackFrame* stackFrame;
+        for (unsigned i = 0 ; i < stackTrace.size(); ++i) {
+            stackFrame = &stackTrace.at(i);
+            if (stackFrame->bytecodeOffset)
+                break;
+        }
+
+        if (bytecodeOffset) {
+            FindFirstCallerFrameWithCodeblockFunctor functor(exec);
+            vm.topCallFrame->iterate(functor);
+            callFrame = functor.foundCallFrame();
+            unsigned stackIndex = functor.index();
+            bytecodeOffset = stackTrace.at(stackIndex).bytecodeOffset;
+        }
+        
+        unsigned line;
+        unsigned column;
+        stackFrame->computeLineAndColumn(line, column);
+        obj->putDirect(vm, vm.propertyNames->line, jsNumber(line), ReadOnly | DontDelete);
+        obj->putDirect(vm, vm.propertyNames->column, jsNumber(column), ReadOnly | DontDelete);
+
+        if (!stackFrame->sourceURL.isEmpty())
+            obj->putDirect(vm, vm.propertyNames->sourceURL, jsString(&vm, stackFrame->sourceURL), ReadOnly | DontDelete);
+    
+        if (!useCurrentFrame)
+            stackTrace.remove(0);
+        obj->putDirect(vm, vm.propertyNames->stack, vm.interpreter->stackTraceAsString(vm.topCallFrame, stackTrace), DontEnum);
+
+        return true;
+    }
+    return false;
 }
 
-JSObject* createURIError(ExecState* exec, const String& message)
+void addErrorInfo(ExecState* exec, JSObject* obj, bool useCurrentFrame)
 {
-    return createURIError(exec->lexicalGlobalObject(), message);
+    CallFrame* callFrame = nullptr;
+    unsigned bytecodeOffset = 0;
+    addErrorInfoAndGetBytecodeOffset(exec, exec->vm(), obj, useCurrentFrame, callFrame, bytecodeOffset);
 }
 
 JSObject* addErrorInfo(CallFrame* callFrame, JSObject* error, int line, const SourceCode& source)
@@ -160,6 +219,53 @@
     return exec->vm().throwException(exec, createSyntaxError(exec, ASCIILiteral("Syntax error")));
 }
 
+
+JSObject* createError(ExecState* exec, const String& message)
+{
+    return createError(exec, message, nullptr);
+}
+
+JSObject* createEvalError(ExecState* exec, const String& message)
+{
+    return createEvalError(exec, message, nullptr);
+}
+
+JSObject* createRangeError(ExecState* exec, const String& message)
+{
+    return createRangeError(exec, message, nullptr);
+}
+
+JSObject* createReferenceError(ExecState* exec, const String& message)
+{
+    return createReferenceError(exec, message, nullptr);
+}
+
+JSObject* createSyntaxError(ExecState* exec, const String& message)
+{
+    return createSyntaxError(exec, message, nullptr);
+}
+
+JSObject* createTypeError(ExecState* exec, const String& message)
+{
+    return createTypeError(exec, message, nullptr, TypeNothing);
+}
+
+JSObject* createNotEnoughArgumentsError(ExecState* exec)
+{
+    return createNotEnoughArgumentsError(exec, nullptr);
+}
+
+JSObject* createURIError(ExecState* exec, const String& message)
+{
+    return createURIError(exec, message, nullptr);
+}
+
+JSObject* createOutOfMemoryError(ExecState* exec)
+{
+    return createOutOfMemoryError(exec, nullptr);
+}
+
+
 const ClassInfo StrictModeTypeErrorFunction::s_info = { "Function", &Base::s_info, 0, CREATE_METHOD_TABLE(StrictModeTypeErrorFunction) };
 
 void StrictModeTypeErrorFunction::destroy(JSCell* cell)

Modified: trunk/Source/_javascript_Core/runtime/Error.h (182494 => 182495)


--- trunk/Source/_javascript_Core/runtime/Error.h	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/Source/_javascript_Core/runtime/Error.h	2015-04-07 21:34:05 UTC (rev 182495)
@@ -23,11 +23,13 @@
 #ifndef Error_h
 #define Error_h
 
+#include "ErrorInstance.h"
 #include "InternalFunction.h"
 #include "Interpreter.h"
 #include "JSObject.h"
 #include <stdint.h>
 
+
 namespace JSC {
 
 class ExecState;
@@ -37,28 +39,33 @@
 class SourceCode;
 class Structure;
 
-// Methods to create a range of internal errors.
-JSObject* createError(JSGlobalObject*, const String&);
-JSObject* createEvalError(JSGlobalObject*, const String&);
-JSObject* createRangeError(JSGlobalObject*, const String&);
-JSObject* createReferenceError(JSGlobalObject*, const String&);
-JSObject* createSyntaxError(JSGlobalObject*, const String&);
-JSObject* createTypeError(JSGlobalObject*, const String&);
-JSObject* createNotEnoughArgumentsError(JSGlobalObject*);
-JSObject* createURIError(JSGlobalObject*, const String&);
 // ExecState wrappers.
+JSObject* createError(ExecState*, const String&, ErrorInstance::SourceAppender);
+JSObject* createEvalError(ExecState*, const String&, ErrorInstance::SourceAppender);
+JSObject* createRangeError(ExecState*, const String&, ErrorInstance::SourceAppender);
+JSObject* createReferenceError(ExecState*, const String&, ErrorInstance::SourceAppender);
+JSObject* createSyntaxError(ExecState*, const String&, ErrorInstance::SourceAppender);
+JSObject* createTypeError(ExecState*, const String&, ErrorInstance::SourceAppender, RuntimeType);
+JSObject* createNotEnoughArgumentsError(ExecState*, ErrorInstance::SourceAppender);
+JSObject* createURIError(ExecState*, const String&, ErrorInstance::SourceAppender);
+JSObject* createOutOfMemoryError(ExecState*, ErrorInstance::SourceAppender);
+
+
 JS_EXPORT_PRIVATE JSObject* createError(ExecState*, const String&);
-JSObject* createEvalError(ExecState*, const String&);
+JS_EXPORT_PRIVATE JSObject* createEvalError(ExecState*, const String&);
 JS_EXPORT_PRIVATE JSObject* createRangeError(ExecState*, const String&);
 JS_EXPORT_PRIVATE JSObject* createReferenceError(ExecState*, const String&);
 JS_EXPORT_PRIVATE JSObject* createSyntaxError(ExecState*, const String&);
 JS_EXPORT_PRIVATE JSObject* createTypeError(ExecState*, const String&);
 JS_EXPORT_PRIVATE JSObject* createNotEnoughArgumentsError(ExecState*);
-JSObject* createURIError(ExecState*, const String&);
+JS_EXPORT_PRIVATE JSObject* createURIError(ExecState*, const String&);
+JS_EXPORT_PRIVATE JSObject* createOutOfMemoryError(ExecState*);
 
-// Methods to add 
+
+bool addErrorInfoAndGetBytecodeOffset(ExecState*, VM&, JSObject*, bool, CallFrame*&, unsigned&);
+
 bool hasErrorInfo(ExecState*, JSObject* error);
-// ExecState wrappers.
+JS_EXPORT_PRIVATE void addErrorInfo(ExecState*, JSObject*, bool); 
 JSObject* addErrorInfo(ExecState*, JSObject* error, int line, const SourceCode&);
 
 // Methods to throw Errors.

Modified: trunk/Source/_javascript_Core/runtime/ErrorConstructor.cpp (182494 => 182495)


--- trunk/Source/_javascript_Core/runtime/ErrorConstructor.cpp	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/Source/_javascript_Core/runtime/ErrorConstructor.cpp	2015-04-07 21:34:05 UTC (rev 182495)
@@ -52,10 +52,7 @@
 {
     JSValue message = exec->argumentCount() ? exec->argument(0) : jsUndefined();
     Structure* errorStructure = asInternalFunction(exec->callee())->globalObject()->errorStructure();
-    Vector<StackFrame> stackTrace;
-    exec->vm().interpreter->getStackTrace(stackTrace, std::numeric_limits<size_t>::max());
-    stackTrace.remove(0);
-    return JSValue::encode(ErrorInstance::create(exec, errorStructure, message, stackTrace));
+    return JSValue::encode(ErrorInstance::create(exec, errorStructure, message, nullptr, TypeNothing, false));
 }
 
 ConstructType ErrorConstructor::getConstructData(JSCell*, ConstructData& constructData)
@@ -68,10 +65,7 @@
 {
     JSValue message = exec->argumentCount() ? exec->argument(0) : jsUndefined();
     Structure* errorStructure = asInternalFunction(exec->callee())->globalObject()->errorStructure();
-    Vector<StackFrame> stackTrace;
-    exec->vm().interpreter->getStackTrace(stackTrace, std::numeric_limits<size_t>::max());
-    stackTrace.remove(0);
-    return JSValue::encode(ErrorInstance::create(exec, errorStructure, message, stackTrace));
+    return JSValue::encode(ErrorInstance::create(exec, errorStructure, message, nullptr, TypeNothing, false));
 }
 
 CallType ErrorConstructor::getCallData(JSCell*, CallData& callData)

Modified: trunk/Source/_javascript_Core/runtime/ErrorInstance.cpp (182494 => 182495)


--- trunk/Source/_javascript_Core/runtime/ErrorInstance.cpp	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/Source/_javascript_Core/runtime/ErrorInstance.cpp	2015-04-07 21:34:05 UTC (rev 182495)
@@ -23,6 +23,8 @@
 
 #include "JSScope.h"
 #include "JSCInlines.h"
+#include "JSGlobalObjectFunctions.h"
+#include <wtf/Vector.h>
 
 namespace JSC {
 
@@ -35,15 +37,156 @@
 {
 }
 
-void ErrorInstance::finishCreation(VM& vm, const String& message, Vector<StackFrame> stackTrace)
+static void appendSourceToError(CallFrame* callFrame, ErrorInstance* exception, unsigned bytecodeOffset)
 {
+    ErrorInstance::SourceAppender appender = exception->sourceAppender();
+    exception->clearSourceAppender();
+    RuntimeType type = exception->runtimeTypeForCause();
+    exception->clearRuntimeTypeForCause();
+
+    if (!callFrame->codeBlock()->hasExpressionInfo())
+        return;
+    
+    int startOffset = 0;
+    int endOffset = 0;
+    int divotPoint = 0;
+    unsigned line = 0;
+    unsigned column = 0;
+    
+    CodeBlock* codeBlock = callFrame->codeBlock();
+    codeBlock->expressionRangeForBytecodeOffset(bytecodeOffset, divotPoint, startOffset, endOffset, line, column);
+    
+    int expressionStart = divotPoint - startOffset;
+    int expressionStop = divotPoint + endOffset;
+
+    const String& sourceString = codeBlock->source()->source();
+    if (!expressionStop || expressionStart > static_cast<int>(sourceString.length()))
+        return;
+    
+    VM* vm = &callFrame->vm();
+    JSValue jsMessage = exception->getDirect(*vm, vm->propertyNames->message);
+    if (!jsMessage || !jsMessage.isString())
+        return;
+    
+    String message = asString(jsMessage)->value(callFrame);
+    if (expressionStart < expressionStop)
+        message = appender(message, codeBlock->source()->getRange(expressionStart, expressionStop) , type, ErrorInstance::FoundExactSource);
+    else {
+        // No range information, so give a few characters of context.
+        const StringImpl* data = ""
+        int dataLength = sourceString.length();
+        int start = expressionStart;
+        int stop = expressionStart;
+        // Get up to 20 characters of context to the left and right of the divot, clamping to the line.
+        // Then strip whitespace.
+        while (start > 0 && (expressionStart - start < 20) && (*data)[start - 1] != '\n')
+            start--;
+        while (start < (expressionStart - 1) && isStrWhiteSpace((*data)[start]))
+            start++;
+        while (stop < dataLength && (stop - expressionStart < 20) && (*data)[stop] != '\n')
+            stop++;
+        while (stop > expressionStart && isStrWhiteSpace((*data)[stop - 1]))
+            stop--;
+        message = appender(message, codeBlock->source()->getRange(start, stop), type, ErrorInstance::FoundApproximateSource);
+    }
+    exception->putDirect(*vm, vm->propertyNames->message, jsString(vm, message));
+
+}
+
+class FindFirstCallerFrameWithCodeblockFunctor {
+public:
+    FindFirstCallerFrameWithCodeblockFunctor(CallFrame* startCallFrame)
+        : m_startCallFrame(startCallFrame)
+        , m_foundCallFrame(nullptr)
+        , m_foundStartCallFrame(false)
+        , m_index(0)
+    { }
+
+    StackVisitor::Status operator()(StackVisitor& visitor)
+    {
+        if (!m_foundStartCallFrame && (visitor->callFrame() == m_startCallFrame))
+            m_foundStartCallFrame = true;
+
+        if (m_foundStartCallFrame) {
+            if (visitor->callFrame()->codeBlock()) {
+                m_foundCallFrame = visitor->callFrame();
+                return StackVisitor::Done;
+            }
+            m_index++;
+        }
+
+        return StackVisitor::Continue;
+    }
+
+    CallFrame* foundCallFrame() const { return m_foundCallFrame; }
+    unsigned index() const { return m_index; }
+
+private:
+    CallFrame* m_startCallFrame;
+    CallFrame* m_foundCallFrame;
+    bool m_foundStartCallFrame;
+    unsigned m_index;
+};
+
+static bool addErrorInfoAndGetBytecodeOffset(ExecState* exec, VM& vm, JSObject* obj, bool useCurrentFrame, CallFrame*& callFrame, unsigned &bytecodeOffset)
+{
+    Vector<StackFrame> stackTrace = Vector<StackFrame>();
+
+    if (exec && stackTrace.isEmpty())
+        vm.interpreter->getStackTrace(stackTrace);
+
+    if (!stackTrace.isEmpty()) {
+
+        ASSERT(exec == vm.topCallFrame || exec == exec->lexicalGlobalObject()->globalExec() || exec == exec->vmEntryGlobalObject()->globalExec());
+
+        StackFrame* stackFrame;
+        for (unsigned i = 0 ; i < stackTrace.size(); ++i) {
+            stackFrame = &stackTrace.at(i);
+            if (stackFrame->bytecodeOffset)
+                break;
+        }
+
+        if (bytecodeOffset) {
+            FindFirstCallerFrameWithCodeblockFunctor functor(exec);
+            vm.topCallFrame->iterate(functor);
+            callFrame = functor.foundCallFrame();
+            unsigned stackIndex = functor.index();
+            bytecodeOffset = stackTrace.at(stackIndex).bytecodeOffset;
+        }
+        
+        unsigned line;
+        unsigned column;
+        stackFrame->computeLineAndColumn(line, column);
+        obj->putDirect(vm, vm.propertyNames->line, jsNumber(line), ReadOnly | DontDelete);
+        obj->putDirect(vm, vm.propertyNames->column, jsNumber(column), ReadOnly | DontDelete);
+
+        if (!stackFrame->sourceURL.isEmpty())
+            obj->putDirect(vm, vm.propertyNames->sourceURL, jsString(&vm, stackFrame->sourceURL), ReadOnly | DontDelete);
+    
+        if (!useCurrentFrame)
+            stackTrace.remove(0);
+        obj->putDirect(vm, vm.propertyNames->stack, vm.interpreter->stackTraceAsString(vm.topCallFrame, stackTrace), DontEnum);
+
+        return true;
+    }
+    return false;
+}
+
+void ErrorInstance::finishCreation(ExecState* exec, VM& vm, const String& message, bool useCurrentFrame)
+{
     Base::finishCreation(vm);
     ASSERT(inherits(info()));
     if (!message.isNull())
         putDirect(vm, vm.propertyNames->message, jsString(&vm, message), DontEnum);
-    
-    if (!stackTrace.isEmpty())
-        putDirect(vm, vm.propertyNames->stack, vm.interpreter->stackTraceAsString(vm.topCallFrame, stackTrace), DontEnum);
+
+    unsigned bytecodeOffset = hasSourceAppender();
+    CallFrame* callFrame = nullptr;
+    bool hasTrace = addErrorInfoAndGetBytecodeOffset(exec, vm, this, useCurrentFrame, callFrame, bytecodeOffset);
+
+    if (hasTrace && callFrame && hasSourceAppender()) {
+        if (callFrame && callFrame->codeBlock()) 
+            appendSourceToError(callFrame, this, bytecodeOffset);
+    }
 }
     
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/ErrorInstance.h (182494 => 182495)


--- trunk/Source/_javascript_Core/runtime/ErrorInstance.h	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/Source/_javascript_Core/runtime/ErrorInstance.h	2015-04-07 21:34:05 UTC (rev 182495)
@@ -24,6 +24,7 @@
 #include "Interpreter.h"
 #include "RuntimeType.h"
 #include "SourceProvider.h"
+#include <wtf/Vector.h>
 
 namespace JSC {
 
@@ -31,6 +32,9 @@
 public:
     typedef JSNonFinalObject Base;
 
+    enum SourceTextWhereErrorOccurred { FoundExactSource, FoundApproximateSource };
+    typedef String (*SourceAppender) (const String& originalMessage, const String& sourceText, RuntimeType, SourceTextWhereErrorOccurred);
+
     DECLARE_INFO;
 
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
@@ -38,20 +42,21 @@
         return Structure::create(vm, globalObject, prototype, TypeInfo(ErrorInstanceType, StructureFlags), info());
     }
 
-    static ErrorInstance* create(VM& vm, Structure* structure, const String& message, Vector<StackFrame> stackTrace = Vector<StackFrame>())
+    static ErrorInstance* create(ExecState* exec, VM& vm, Structure* structure, const String& message, SourceAppender appender = nullptr, RuntimeType type = TypeNothing, bool useCurrentFrame = true)
     {
         ErrorInstance* instance = new (NotNull, allocateCell<ErrorInstance>(vm.heap)) ErrorInstance(vm, structure);
-        instance->finishCreation(vm, message, stackTrace);
+        instance->m_sourceAppender = appender;
+        instance->m_runtimeTypeForCause = type;
+        instance->finishCreation(exec, vm, message, useCurrentFrame);
         return instance;
     }
 
-    static ErrorInstance* create(ExecState* exec, Structure* structure, JSValue message, Vector<StackFrame> stackTrace = Vector<StackFrame>())
+    static ErrorInstance* create(ExecState* exec, Structure* structure, JSValue message, SourceAppender appender = nullptr, RuntimeType type = TypeNothing, bool useCurrentFrame = true)
     {
-        return create(exec->vm(), structure, message.isUndefined() ? String() : message.toString(exec)->value(exec), stackTrace);
+        return create(exec, exec->vm(), structure, message.isUndefined() ? String() : message.toString(exec)->value(exec), appender, type, useCurrentFrame);
     }
 
-    enum SourceTextWhereErrorOccurred { FoundExactSource, FoundApproximateSource };
-    typedef String (*SourceAppender) (const String& originalMessage, const String& sourceText, RuntimeType, SourceTextWhereErrorOccurred);
+    static void addErrorInfo(ExecState*, VM&, JSObject*, bool = true);
 
     bool hasSourceAppender() const { return !!m_sourceAppender; }
     SourceAppender sourceAppender() const { return m_sourceAppender; }
@@ -64,7 +69,7 @@
 protected:
     explicit ErrorInstance(VM&, Structure*);
 
-    void finishCreation(VM&, const String&, Vector<StackFrame> = Vector<StackFrame>());
+    void finishCreation(ExecState*, VM&, const String&, bool useCurrentFrame = true);
 
     SourceAppender m_sourceAppender { nullptr };
     RuntimeType m_runtimeTypeForCause { TypeNothing };

Modified: trunk/Source/_javascript_Core/runtime/ErrorPrototype.cpp (182494 => 182495)


--- trunk/Source/_javascript_Core/runtime/ErrorPrototype.cpp	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/Source/_javascript_Core/runtime/ErrorPrototype.cpp	2015-04-07 21:34:05 UTC (rev 182495)
@@ -54,9 +54,9 @@
 {
 }
 
-void ErrorPrototype::finishCreation(VM& vm, JSGlobalObject*)
+void ErrorPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
 {
-    Base::finishCreation(vm, "");
+    Base::finishCreation(globalObject->globalExec(), vm, "");
     ASSERT(inherits(info()));
     putDirect(vm, vm.propertyNames->name, jsNontrivialString(&vm, String(ASCIILiteral("Error"))), DontEnum);
 }

Modified: trunk/Source/_javascript_Core/runtime/ExceptionFuzz.cpp (182494 => 182495)


--- trunk/Source/_javascript_Core/runtime/ExceptionFuzz.cpp	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/Source/_javascript_Core/runtime/ExceptionFuzz.cpp	2015-04-07 21:34:05 UTC (rev 182495)
@@ -48,7 +48,7 @@
     if (fireTarget == s_numberOfExceptionFuzzChecks) {
         printf("JSC EXCEPTION FUZZ: Throwing fuzz exception with call frame %p, seen in %s and return address %p.\n", exec, where, returnPC);
         exec->vm().throwException(
-            exec, createError(exec->lexicalGlobalObject(), ASCIILiteral("Exception Fuzz")));
+            exec, createError(exec, ASCIILiteral("Exception Fuzz")));
     }
 }
 

Modified: trunk/Source/_javascript_Core/runtime/ExceptionHelpers.cpp (182494 => 182495)


--- trunk/Source/_javascript_Core/runtime/ExceptionHelpers.cpp	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/Source/_javascript_Core/runtime/ExceptionHelpers.cpp	2015-04-07 21:34:05 UTC (rev 182495)
@@ -75,11 +75,6 @@
     return createRangeError(exec, ASCIILiteral("Maximum call stack size exceeded."));
 }
 
-JSObject* createStackOverflowError(JSGlobalObject* globalObject)
-{
-    return createRangeError(globalObject, ASCIILiteral("Maximum call stack size exceeded."));
-}
-
 JSObject* createUndefinedVariableError(ExecState* exec, const Identifier& ident)
 {
     if (exec->propertyNames().isPrivateName(ident)) {
@@ -239,48 +234,44 @@
     return makeString(rightHandSide, " is not a function. (evaluating '", sourceText, "')");
 }
 
-JSObject* createError(ExecState* exec, ErrorFactory errorFactory, JSValue value, const String& message, ErrorInstance::SourceAppender appender)
+JSObject* createError(ExecState* exec, JSValue value, const String& message, ErrorInstance::SourceAppender appender)
 {
     String errorMessage = makeString(errorDescriptionForValue(exec, value)->value(exec), ' ', message);
-    JSObject* exception = errorFactory(exec, errorMessage);
+    JSObject* exception = createTypeError(exec, errorMessage, appender, runtimeTypeForValue(value));
     ASSERT(exception->isErrorInstance());
-    static_cast<ErrorInstance*>(exception)->setSourceAppender(appender);
-    static_cast<ErrorInstance*>(exception)->setRuntimeTypeForCause(runtimeTypeForValue(value));
     return exception;
 }
 
 JSObject* createInvalidFunctionApplyParameterError(ExecState* exec, JSValue value)
 {
-    JSObject* exception = createTypeError(exec, makeString("second argument to Function.prototype.apply must be an Array-like object"));
+    JSObject* exception = createTypeError(exec, makeString("second argument to Function.prototype.apply must be an Array-like object"), defaultSourceAppender, runtimeTypeForValue(value));
     ASSERT(exception->isErrorInstance());
-    static_cast<ErrorInstance*>(exception)->setSourceAppender(defaultSourceAppender);
-    static_cast<ErrorInstance*>(exception)->setRuntimeTypeForCause(runtimeTypeForValue(value));
     return exception;
 }
 
 JSObject* createInvalidInParameterError(ExecState* exec, JSValue value)
 {
-    return createError(exec, createTypeError, value, makeString("is not an Object."), invalidParameterInSourceAppender);
+    return createError(exec, value, makeString("is not an Object."), invalidParameterInSourceAppender);
 }
 
 JSObject* createInvalidInstanceofParameterError(ExecState* exec, JSValue value)
 {
-    return createError(exec, createTypeError, value, makeString("is not a function."), invalidParameterInstanceofSourceAppender);
+    return createError(exec, value, makeString("is not a function."), invalidParameterInstanceofSourceAppender);
 }
 
 JSObject* createNotAConstructorError(ExecState* exec, JSValue value)
 {
-    return createError(exec, createTypeError, value, ASCIILiteral("is not a constructor"), defaultSourceAppender);
+    return createError(exec, value, ASCIILiteral("is not a constructor"), defaultSourceAppender);
 }
 
 JSObject* createNotAFunctionError(ExecState* exec, JSValue value)
 {
-    return createError(exec, createTypeError, value, ASCIILiteral("is not a function"), notAFunctionSourceAppender);
+    return createError(exec, value, ASCIILiteral("is not a function"), notAFunctionSourceAppender);
 }
 
 JSObject* createNotAnObjectError(ExecState* exec, JSValue value)
 {
-    return createError(exec, createTypeError, value, ASCIILiteral("is not an object"), defaultSourceAppender);
+    return createError(exec, value, ASCIILiteral("is not an object"), defaultSourceAppender);
 }
 
 JSObject* createErrorForInvalidGlobalAssignment(ExecState* exec, const String& propertyName)
@@ -288,14 +279,9 @@
     return createReferenceError(exec, makeString("Strict mode forbids implicit creation of global property '", propertyName, '\''));
 }
 
-JSObject* createOutOfMemoryError(JSGlobalObject* globalObject)
-{
-    return createError(globalObject, ASCIILiteral("Out of memory"));
-}
-
 JSObject* throwOutOfMemoryError(ExecState* exec)
 {
-    return exec->vm().throwException(exec, createOutOfMemoryError(exec->lexicalGlobalObject()));
+    return exec->vm().throwException(exec, createOutOfMemoryError(exec));
 }
 
 JSObject* throwStackOverflowError(ExecState* exec)

Modified: trunk/Source/_javascript_Core/runtime/ExceptionHelpers.h (182494 => 182495)


--- trunk/Source/_javascript_Core/runtime/ExceptionHelpers.h	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/Source/_javascript_Core/runtime/ExceptionHelpers.h	2015-04-07 21:34:05 UTC (rev 182495)
@@ -34,15 +34,13 @@
 
 namespace JSC {
 
-typedef JSObject* (*ErrorFactory)(ExecState*, const String&);
+typedef JSObject* (*ErrorFactory)(ExecState*, const String&, ErrorInstance::SourceAppender);
 
 JSObject* createTerminatedExecutionException(VM*);
 bool isTerminatedExecutionException(JSObject*);
 JS_EXPORT_PRIVATE bool isTerminatedExecutionException(JSValue);
-JS_EXPORT_PRIVATE JSObject* createError(ExecState*, ErrorFactory, JSValue, const String&, ErrorInstance::SourceAppender);
+JS_EXPORT_PRIVATE JSObject* createError(ExecState*, JSValue, const String&, ErrorInstance::SourceAppender);
 JS_EXPORT_PRIVATE JSObject* createStackOverflowError(ExecState*);
-JSObject* createStackOverflowError(JSGlobalObject*);
-JSObject* createOutOfMemoryError(JSGlobalObject*);
 JSObject* createUndefinedVariableError(ExecState*, const Identifier&);
 JSObject* createNotAnObjectError(ExecState*, JSValue);
 JSObject* createInvalidFunctionApplyParameterError(ExecState*, JSValue);

Modified: trunk/Source/_javascript_Core/runtime/JSArrayBufferConstructor.cpp (182494 => 182495)


--- trunk/Source/_javascript_Core/runtime/JSArrayBufferConstructor.cpp	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/Source/_javascript_Core/runtime/JSArrayBufferConstructor.cpp	2015-04-07 21:34:05 UTC (rev 182495)
@@ -92,7 +92,7 @@
     
     RefPtr<ArrayBuffer> buffer = ArrayBuffer::create(length, 1);
     if (!buffer)
-        return throwVMError(exec, createOutOfMemoryError(constructor->globalObject()));
+        return throwVMError(exec, createOutOfMemoryError(exec));
     
     JSArrayBuffer* result = JSArrayBuffer::create(
         exec->vm(), constructor->globalObject()->arrayBufferStructure(), buffer);

Modified: trunk/Source/_javascript_Core/runtime/JSArrayBufferPrototype.cpp (182494 => 182495)


--- trunk/Source/_javascript_Core/runtime/JSArrayBufferPrototype.cpp	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/Source/_javascript_Core/runtime/JSArrayBufferPrototype.cpp	2015-04-07 21:34:05 UTC (rev 182495)
@@ -60,7 +60,7 @@
     
     RefPtr<ArrayBuffer> newBuffer = thisObject->impl()->slice(begin, end);
     if (!newBuffer)
-        return throwVMError(exec, createOutOfMemoryError(callee->globalObject()));
+        return throwVMError(exec, createOutOfMemoryError(exec));
     
     Structure* structure = callee->globalObject()->arrayBufferStructure();
     

Modified: trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewInlines.h (182494 => 182495)


--- trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewInlines.h	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/Source/_javascript_Core/runtime/JSGenericTypedArrayViewInlines.h	2015-04-07 21:34:05 UTC (rev 182495)
@@ -49,7 +49,7 @@
 {
     ConstructionContext context(exec->vm(), structure, length, sizeof(typename Adaptor::Type));
     if (!context) {
-        exec->vm().throwException(exec, createOutOfMemoryError(structure->globalObject()));
+        exec->vm().throwException(exec, createOutOfMemoryError(exec));
         return 0;
     }
     JSGenericTypedArrayView* result =
@@ -67,7 +67,7 @@
         exec->vm(), structure, length, sizeof(typename Adaptor::Type),
         ConstructionContext::DontInitialize);
     if (!context) {
-        exec->vm().throwException(exec, createOutOfMemoryError(structure->globalObject()));
+        exec->vm().throwException(exec, createOutOfMemoryError(exec));
         return 0;
     }
     JSGenericTypedArrayView* result =

Modified: trunk/Source/_javascript_Core/runtime/NativeErrorConstructor.cpp (182494 => 182495)


--- trunk/Source/_javascript_Core/runtime/NativeErrorConstructor.cpp	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/Source/_javascript_Core/runtime/NativeErrorConstructor.cpp	2015-04-07 21:34:05 UTC (rev 182495)
@@ -65,10 +65,7 @@
     JSValue message = exec->argument(0);
     Structure* errorStructure = static_cast<NativeErrorConstructor*>(exec->callee())->errorStructure();
     ASSERT(errorStructure);
-    Vector<StackFrame> stackTrace;
-    exec->vm().interpreter->getStackTrace(stackTrace, std::numeric_limits<size_t>::max());
-    stackTrace.remove(0);
-    return JSValue::encode(ErrorInstance::create(exec, errorStructure, message, stackTrace));
+    return JSValue::encode(ErrorInstance::create(exec, errorStructure, message, nullptr, TypeNothing, false));
 }
 
 ConstructType NativeErrorConstructor::getConstructData(JSCell*, ConstructData& constructData)
@@ -81,10 +78,7 @@
 {
     JSValue message = exec->argument(0);
     Structure* errorStructure = static_cast<NativeErrorConstructor*>(exec->callee())->errorStructure();
-    Vector<StackFrame> stackTrace;
-    exec->vm().interpreter->getStackTrace(stackTrace, std::numeric_limits<size_t>::max());
-    stackTrace.remove(0);
-    return JSValue::encode(ErrorInstance::create(exec, errorStructure, message, stackTrace));
+    return JSValue::encode(ErrorInstance::create(exec, errorStructure, message, nullptr, TypeNothing, false));
 }
 
 CallType NativeErrorConstructor::getCallData(JSCell*, CallData& callData)

Modified: trunk/Source/_javascript_Core/runtime/VM.cpp (182494 => 182495)


--- trunk/Source/_javascript_Core/runtime/VM.cpp	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/Source/_javascript_Core/runtime/VM.cpp	2015-04-07 21:34:05 UTC (rev 182495)
@@ -540,98 +540,6 @@
     heap.collectAllGarbage();
 }
 
-static void appendSourceToError(CallFrame* callFrame, ErrorInstance* exception, unsigned bytecodeOffset)
-{
-    ErrorInstance::SourceAppender appender = exception->sourceAppender();
-    exception->clearSourceAppender();
-    RuntimeType type = exception->runtimeTypeForCause();
-    exception->clearRuntimeTypeForCause();
-    
-    if (!callFrame->codeBlock()->hasExpressionInfo())
-        return;
-    
-    int startOffset = 0;
-    int endOffset = 0;
-    int divotPoint = 0;
-    unsigned line = 0;
-    unsigned column = 0;
-    
-    CodeBlock* codeBlock = callFrame->codeBlock();
-    codeBlock->expressionRangeForBytecodeOffset(bytecodeOffset, divotPoint, startOffset, endOffset, line, column);
-    
-    int expressionStart = divotPoint - startOffset;
-    int expressionStop = divotPoint + endOffset;
-    
-    const String& sourceString = codeBlock->source()->source();
-    if (!expressionStop || expressionStart > static_cast<int>(sourceString.length()))
-        return;
-    
-    VM* vm = &callFrame->vm();
-    JSValue jsMessage = exception->getDirect(*vm, vm->propertyNames->message);
-    if (!jsMessage || !jsMessage.isString())
-        return;
-    
-    String message = asString(jsMessage)->value(callFrame);
-    
-    if (expressionStart < expressionStop)
-        message = appender(message, codeBlock->source()->getRange(expressionStart, expressionStop), type, ErrorInstance::FoundExactSource);
-    else {
-        // No range information, so give a few characters of context.
-        const StringImpl* data = ""
-        int dataLength = sourceString.length();
-        int start = expressionStart;
-        int stop = expressionStart;
-        // Get up to 20 characters of context to the left and right of the divot, clamping to the line.
-        // Then strip whitespace.
-        while (start > 0 && (expressionStart - start < 20) && (*data)[start - 1] != '\n')
-            start--;
-        while (start < (expressionStart - 1) && isStrWhiteSpace((*data)[start]))
-            start++;
-        while (stop < dataLength && (stop - expressionStart < 20) && (*data)[stop] != '\n')
-            stop++;
-        while (stop > expressionStart && isStrWhiteSpace((*data)[stop - 1]))
-            stop--;
-        message = appender(message, codeBlock->source()->getRange(start, stop), type, ErrorInstance::FoundApproximateSource);
-    }
-    
-    exception->putDirect(*vm, vm->propertyNames->message, jsString(vm, message));
-}
-
-class FindFirstCallerFrameWithCodeblockFunctor {
-public:
-    FindFirstCallerFrameWithCodeblockFunctor(CallFrame* startCallFrame)
-        : m_startCallFrame(startCallFrame)
-        , m_foundCallFrame(nullptr)
-        , m_foundStartCallFrame(false)
-        , m_index(0)
-    { }
-
-    StackVisitor::Status operator()(StackVisitor& visitor)
-    {
-        if (!m_foundStartCallFrame && (visitor->callFrame() == m_startCallFrame))
-            m_foundStartCallFrame = true;
-
-        if (m_foundStartCallFrame) {
-            if (visitor->callFrame()->codeBlock()) {
-                m_foundCallFrame = visitor->callFrame();
-                return StackVisitor::Done;
-            }
-            m_index++;
-        }
-
-        return StackVisitor::Continue;
-    }
-
-    CallFrame* foundCallFrame() const { return m_foundCallFrame; }
-    unsigned index() const { return m_index; }
-
-private:
-    CallFrame* m_startCallFrame;
-    CallFrame* m_foundCallFrame;
-    bool m_foundStartCallFrame;
-    unsigned m_index;
-};
-
 JSValue VM::throwException(ExecState* exec, JSValue error)
 {
     if (Options::breakOnThrow()) {
@@ -645,44 +553,7 @@
     interpreter->getStackTrace(stackTrace);
     m_exceptionStack = RefCountedArray<StackFrame>(stackTrace);
     m_exception = error;
-    
-    if (stackTrace.isEmpty() || !error.isObject())
-        return error;
-    JSObject* exception = asObject(error);
-    
-    StackFrame stackFrame;
-    for (unsigned i = 0 ; i < stackTrace.size(); ++i) {
-        stackFrame = stackTrace.at(i);
-        if (stackFrame.bytecodeOffset)
-            break;
-    }
-    if (!hasErrorInfo(exec, exception)) {
-        // FIXME: We should only really be adding these properties to VM generated exceptions,
-        // but the inspector currently requires these for all thrown objects.
-        unsigned line;
-        unsigned column;
-        stackFrame.computeLineAndColumn(line, column);
-        exception->putDirect(*this, Identifier::fromString(this, "line"), jsNumber(line), ReadOnly | DontDelete);
-        exception->putDirect(*this, Identifier::fromString(this, "column"), jsNumber(column), ReadOnly | DontDelete);
-        if (!stackFrame.sourceURL.isEmpty())
-            exception->putDirect(*this, Identifier::fromString(this, "sourceURL"), jsString(this, stackFrame.sourceURL), ReadOnly | DontDelete);
-    }
-    if (exception->isErrorInstance() && static_cast<ErrorInstance*>(exception)->hasSourceAppender()) {
-        FindFirstCallerFrameWithCodeblockFunctor functor(exec);
-        topCallFrame->iterate(functor);
-        CallFrame* callFrame = functor.foundCallFrame();
-        unsigned stackIndex = functor.index();
 
-        if (callFrame && callFrame->codeBlock()) {
-            stackFrame = stackTrace.at(stackIndex);
-            appendSourceToError(callFrame, static_cast<ErrorInstance*>(exception), stackFrame.bytecodeOffset);
-        }
-    }
-
-    if (exception->hasProperty(exec, this->propertyNames->stack))
-        return error;
-    
-    exception->putDirect(*this, propertyNames->stack, interpreter->stackTraceAsString(topCallFrame, stackTrace), DontEnum);
     return error;
 }
     

Added: trunk/Source/_javascript_Core/tests/stress/freeze_leek.js (0 => 182495)


--- trunk/Source/_javascript_Core/tests/stress/freeze_leek.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/freeze_leek.js	2015-04-07 21:34:05 UTC (rev 182495)
@@ -0,0 +1,41 @@
+var o = Object.freeze([]),
+    leak = {};
+
+try { 
+  throw o; 
+} catch (ex) {}
+
+if(o.stack !== undefined)
+    throw new Error("the stack was leaked.");
+
+o.stack = leak;
+
+if(o.stack === leak)
+    throw new Error("the object wasn't frozen.");
+
+o.other = "wrong";
+
+if(o.other === "wrong")
+    throw new Error("the object wasn't frozen.");
+
+
+o = Object.freeze({"hi": "other"});
+
+try { 
+  throw o; 
+} catch (ex) {}
+o.stack = leak;
+
+
+if(o.stack !== undefined)
+    throw new Error("the stack was leaked.");
+
+o.stack = leak;
+
+if(o.stack === leak)
+    throw new Error("the object wasn't frozen.");
+
+o.other = "wrong";
+
+if(o.other === "wrong")
+    throw new Error("the object wasn't frozen.");

Modified: trunk/Source/WebCore/ChangeLog (182494 => 182495)


--- trunk/Source/WebCore/ChangeLog	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/Source/WebCore/ChangeLog	2015-04-07 21:34:05 UTC (rev 182495)
@@ -1,3 +1,22 @@
+2015-04-07  Matthew Mirman  <[email protected]>
+
+        Source and stack information should get appended only to native errors
+        and should be added directly after construction rather than when thrown.
+        This fixes frozen objects being unfrozen when thrown while conforming to 
+        ecma script standard and other browser behavior.
+        rdar://problem/19927293
+        https://bugs.webkit.org/show_bug.cgi?id=141871
+        
+        Reviewed by Geoffrey Garen.
+
+        Covered by existing tests.
+        
+        Sets line, column, source and stack information for DOMExceptions as 
+        expected by the webinspector for native errors.
+        
+        * bindings/js/JSDOMBinding.cpp:
+        (WebCore::setDOMException):
+
 2015-04-07  Brady Eidson  <[email protected]>
 
         ContextMenuItem refactoring

Modified: trunk/Source/WebCore/bindings/js/JSDOMBinding.cpp (182494 => 182495)


--- trunk/Source/WebCore/bindings/js/JSDOMBinding.cpp	2015-04-07 21:29:00 UTC (rev 182494)
+++ trunk/Source/WebCore/bindings/js/JSDOMBinding.cpp	2015-04-07 21:34:05 UTC (rev 182495)
@@ -214,8 +214,9 @@
     switch (description.type) {
         DOM_EXCEPTION_INTERFACES_FOR_EACH(TRY_TO_CREATE_EXCEPTION)
     }
-
+    
     ASSERT(errorObject);
+    addErrorInfo(exec, asObject(errorObject), true);
     exec->vm().throwException(exec, errorObject);
 }
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to