Reviewers: Michael Starzinger,

Description:
Lazy call to custom stack trace formatting using Error.prepareStackTrace.

This enables custom stack trace formatting for stack overflow.
A consequence is that stack trace formatting is now easily observable,
but we already established that the default stack trace formatting can
be observed anyways. It is only triggered by the .stack getter, and
it has to be explicitly called, (e.g. not implicitly after GC).

[email protected]
BUG=v8:2559

Please review this at https://codereview.chromium.org/20692002/

SVN Base: https://v8.googlecode.com/svn/branches/bleeding_edge

Affected files:
  M src/messages.js
  A + test/mjsunit/stack-traces-custom-lazy.js


Index: src/messages.js
diff --git a/src/messages.js b/src/messages.js
index 8b647dd20584fcd761f65b04f636738a53e557ba..5ca9648557ecafec89292adf5b2de0da32b226b5 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -1078,7 +1078,26 @@ function GetStackFrames(raw_stack) {
 }


-function FormatStackTrace(error_string, frames) {
+//Flag to prevent recursive call of Error.prepareStackTrace.
+var formatting_custom_stack_trace = false;
+
+
+function FormatStackTrace(obj, error_string, frames) {
+ if (IS_FUNCTION($Error.prepareStackTrace) && !formatting_custom_stack_trace) {
+    var array = [];
+    %MoveArrayContents(frames, array);
+    formatting_custom_stack_trace = true;
+    var stack_trace = void 0;
+    try {
+      stack_trace = $Error.prepareStackTrace(obj, array);
+    } catch (e) {
+      throw e;  // The custom formatting function threw.  Rethrow.
+    } finally {
+      formatting_custom_stack_trace = false;
+    }
+    return stack_trace;
+  }
+
   var lines = new InternalArray();
   lines.push(error_string);
   for (var i = 0; i < frames.length; i++) {
@@ -1115,10 +1134,6 @@ function GetTypeName(receiver, requireConstructor) {
 }


-// Flag to prevent recursive call of Error.prepareStackTrace.
-var formatting_custom_stack_trace = false;
-
-
 function captureStackTrace(obj, cons_opt) {
   var stackTraceLimit = $Error.stackTraceLimit;
   if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return;
@@ -1129,21 +1144,6 @@ function captureStackTrace(obj, cons_opt) {
                                  cons_opt ? cons_opt : captureStackTrace,
                                  stackTraceLimit);

-  // Don't be lazy if the error stack formatting is custom (observable).
- if (IS_FUNCTION($Error.prepareStackTrace) && !formatting_custom_stack_trace) {
-    var array = [];
-    %MoveArrayContents(GetStackFrames(stack), array);
-    formatting_custom_stack_trace = true;
-    try {
-      obj.stack = $Error.prepareStackTrace(obj, array);
-    } catch (e) {
-      throw e;  // The custom formatting function threw.  Rethrow.
-    } finally {
-      formatting_custom_stack_trace = false;
-    }
-    return;
-  }
-
   var error_string = FormatErrorString(obj);
   // The holder of this getter ('obj') may not be the receiver ('this').
// When this getter is called the first time, we use the context values to
@@ -1151,7 +1151,7 @@ function captureStackTrace(obj, cons_opt) {
   // property (on the holder).
   var getter = function() {
     // Stack is still a raw array awaiting to be formatted.
-    var result = FormatStackTrace(error_string, GetStackFrames(stack));
+ var result = FormatStackTrace(obj, error_string, GetStackFrames(stack));
     // Turn this accessor into a data property.
     %DefineOrRedefineDataProperty(obj, 'stack', result, NONE);
     // Release context values.
@@ -1321,7 +1321,7 @@ function SetUpStackOverflowBoilerplate() {
     // We may not have captured any stack trace.
     if (IS_UNDEFINED(stack)) return stack;

-    var result = FormatStackTrace(error_string, GetStackFrames(stack));
+ var result = FormatStackTrace(holder, error_string, GetStackFrames(stack));
     // Replace this accessor with a data property.
     %DefineOrRedefineDataProperty(holder, 'stack', result, NONE);
     return result;
Index: test/mjsunit/stack-traces-custom-lazy.js
diff --git a/test/intl/date-format/format-test.js b/test/mjsunit/stack-traces-custom-lazy.js
similarity index 76%
copy from test/intl/date-format/format-test.js
copy to test/mjsunit/stack-traces-custom-lazy.js
index 9817c97ed975283f2313e7b1ece8a0b110365e84..91d97f3739dc746434731352a0ec7ade0d839484 100644
--- a/test/intl/date-format/format-test.js
+++ b/test/mjsunit/stack-traces-custom-lazy.js
@@ -25,22 +25,25 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

-// Test formatting method with specified date, invalid input.
-
-var dtf = new Intl.DateTimeFormat('en-US', {timeZone: 'UTC'});
-
-var someDate = dtf.format(144313200000);
-assertEquals('7/29/1974', someDate);
-
-var invalidValues = [NaN, Infinity, -Infinity];
-invalidValues.forEach(function(value) {
-  var error;
+function testPrepareStackTrace(closure) {
+  var error = undefined;
   try {
-    dtf.format(value);
+    closure();
+    assertUnreachable();
   } catch (e) {
     error = e;
   }

-  assertTrue(error !== undefined);
-  assertEquals('RangeError', error.name);
-});
+  // We expect custom formatting to be lazy. Setting the custom
+  // function right before calling error.stack should be fine.
+  Error.prepareStackTrace = function(e, frames) {
+    return "bar";
+  }
+
+  assertEquals("bar", error.stack);
+  Error.prepareStackTrace = undefined;
+}
+
+testPrepareStackTrace(function() { throw new Error("foo"); });
+testPrepareStackTrace(function f() { f(); });
+


--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to