Commit 37276389 authored by yangguo@chromium.org's avatar yangguo@chromium.org

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).

R=mstarzinger@chromium.org
BUG=v8:2559

Review URL: https://codereview.chromium.org/20692002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15902 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 4bf2e5be
...@@ -1078,7 +1078,26 @@ function GetStackFrames(raw_stack) { ...@@ -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(); var lines = new InternalArray();
lines.push(error_string); lines.push(error_string);
for (var i = 0; i < frames.length; i++) { for (var i = 0; i < frames.length; i++) {
...@@ -1115,10 +1134,6 @@ function GetTypeName(receiver, requireConstructor) { ...@@ -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) { function captureStackTrace(obj, cons_opt) {
var stackTraceLimit = $Error.stackTraceLimit; var stackTraceLimit = $Error.stackTraceLimit;
if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return; if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return;
...@@ -1129,21 +1144,6 @@ function captureStackTrace(obj, cons_opt) { ...@@ -1129,21 +1144,6 @@ function captureStackTrace(obj, cons_opt) {
cons_opt ? cons_opt : captureStackTrace, cons_opt ? cons_opt : captureStackTrace,
stackTraceLimit); 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); var error_string = FormatErrorString(obj);
// The holder of this getter ('obj') may not be the receiver ('this'). // 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 // When this getter is called the first time, we use the context values to
...@@ -1151,7 +1151,7 @@ function captureStackTrace(obj, cons_opt) { ...@@ -1151,7 +1151,7 @@ function captureStackTrace(obj, cons_opt) {
// property (on the holder). // property (on the holder).
var getter = function() { var getter = function() {
// Stack is still a raw array awaiting to be formatted. // 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. // Turn this accessor into a data property.
%DefineOrRedefineDataProperty(obj, 'stack', result, NONE); %DefineOrRedefineDataProperty(obj, 'stack', result, NONE);
// Release context values. // Release context values.
...@@ -1321,7 +1321,7 @@ function SetUpStackOverflowBoilerplate() { ...@@ -1321,7 +1321,7 @@ function SetUpStackOverflowBoilerplate() {
// We may not have captured any stack trace. // We may not have captured any stack trace.
if (IS_UNDEFINED(stack)) return stack; 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. // Replace this accessor with a data property.
%DefineOrRedefineDataProperty(holder, 'stack', result, NONE); %DefineOrRedefineDataProperty(holder, 'stack', result, NONE);
return result; return result;
......
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
function testPrepareStackTrace(closure) {
var error = undefined;
try {
closure();
assertUnreachable();
} catch (e) {
error = e;
}
// 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(); });
...@@ -315,7 +315,11 @@ assertTrue(fired); ...@@ -315,7 +315,11 @@ assertTrue(fired);
Error.prepareStackTrace = function() { throw new Error("abc"); }; Error.prepareStackTrace = function() { throw new Error("abc"); };
var message; var message;
try { try {
throw new Error(); try {
throw new Error();
} catch (e) {
e.stack;
}
} catch (e) { } catch (e) {
message = e.message; message = e.message;
} }
...@@ -324,6 +328,6 @@ assertEquals("abc", message); ...@@ -324,6 +328,6 @@ assertEquals("abc", message);
// Test that modifying Error.prepareStackTrace by itself works. // Test that modifying Error.prepareStackTrace by itself works.
Error.prepareStackTrace = function() { Error.prepareStackTrace = "custom"; }; Error.prepareStackTrace = function() { Error.prepareStackTrace = "custom"; };
new Error(); new Error().stack;
assertEquals("custom", Error.prepareStackTrace); assertEquals("custom", Error.prepareStackTrace);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment