Fix Error.prototype.toString to be ES5 conform.

R=lrn@chromium.org
TEST=test262/15.11.4.4-8-1,mjsunit/error-tostring

Review URL: http://codereview.chromium.org/8341021

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9790 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 2d4bb180
......@@ -83,7 +83,7 @@ function IsNativeErrorObject(obj) {
// objects between script tags in a browser setting.
function ToStringCheckErrorObject(obj) {
if (IsNativeErrorObject(obj)) {
return %_CallFunction(obj, errorToString);
return %_CallFunction(obj, ErrorToString);
} else {
return ToString(obj);
}
......@@ -1146,42 +1146,43 @@ $Error.captureStackTrace = captureStackTrace;
%SetProperty($Error.prototype, 'message', '', DONT_ENUM);
// Global list of error objects visited during errorToString. This is
// Global list of error objects visited during ErrorToString. This is
// used to detect cycles in error toString formatting.
const visited_errors = new InternalArray();
const cyclic_error_marker = new $Object();
function errorToStringDetectCycle(error) {
function ErrorToStringDetectCycle(error) {
if (!%PushIfAbsent(visited_errors, error)) throw cyclic_error_marker;
try {
var type = error.type;
var name = error.name
name = IS_UNDEFINED(name) ? "Error" : TO_STRING_INLINE(name);
var message = error.message;
var hasMessage = %_CallFunction(error, "message", ObjectHasOwnProperty);
if (type && !hasMessage) {
var formatted = FormatMessage(%NewMessageObject(type, error.arguments));
return error.name + ": " + formatted;
message = FormatMessage(%NewMessageObject(type, error.arguments));
}
var message = hasMessage ? (": " + error.message) : "";
return error.name + message;
message = IS_UNDEFINED(message) ? "" : TO_STRING_INLINE(message);
if (name === "") return message;
if (message === "") return name;
return name + ": " + message;
} finally {
visited_errors.length = visited_errors.length - 1;
}
}
function errorToString() {
function ErrorToString() {
if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
throw MakeTypeError("called_on_null_or_undefined",
["Error.prototype.toString"]);
}
// This helper function is needed because access to properties on
// the builtins object do not work inside of a catch clause.
function isCyclicErrorMarker(o) { return o === cyclic_error_marker; }
try {
return errorToStringDetectCycle(this);
return ErrorToStringDetectCycle(this);
} catch(e) {
// If this error message was encountered already return the empty
// string for it instead of recursively formatting it.
if (isCyclicErrorMarker(e)) {
if (e === cyclic_error_marker) {
return '';
}
throw e;
......@@ -1189,7 +1190,7 @@ function errorToString() {
}
InstallFunctions($Error.prototype, DONT_ENUM, ['toString', errorToString]);
InstallFunctions($Error.prototype, DONT_ENUM, ['toString', ErrorToString]);
// Boilerplate for exceptions for stack overflows. Used from
// Isolate::StackOverflow().
......
......@@ -1087,7 +1087,7 @@ ErrorMirror.prototype.toText = function() {
// Use the same text representation as in messages.js.
var text;
try {
str = %_CallFunction(this.value_, builtins.errorToString);
str = %_CallFunction(this.value_, builtins.ErrorToString);
} catch (e) {
str = '#<Error>';
}
......
......@@ -25,22 +25,61 @@
// (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 printing of cyclic errors which return the empty string for
// compatibility with Safari and Firefox.
// Test default string representation of an Error object.
var e = new Error();
assertEquals('Error', e + '');
assertEquals('Error', e.toString());
// Test printing of cyclic errors which return the empty string for
// compatibility with Safari and Firefox.
e = new Error();
e.name = e;
e.message = e;
e.stack = e;
e.arguments = e;
assertEquals(': ', e + '');
e.stack = "Does not occur in output";
e.arguments = "Does not occur in output";
e.type = "Does not occur in output";
assertEquals('', e.toString());
e = new Error();
e.name = [ e ];
e.message = [ e ];
e.stack = [ e ];
e.arguments = [ e ];
assertEquals(': ', e + '');
e.stack = "Does not occur in output";
e.arguments = "Does not occur in output";
e.type = "Does not occur in output";
assertEquals('', e.toString());
// Test the sequence in which getters and toString operations are called
// on a given Error object. Verify the produced string representation.
function testErrorToString(nameValue, messageValue) {
var seq = [];
var e = {
get name() {
seq.push(1);
return (nameValue === undefined) ? nameValue : {
toString: function() { seq.push(2); return nameValue; }
};
},
get message() {
seq.push(3);
return (messageValue === undefined) ? messageValue : {
toString: function() { seq.push(4); return messageValue; }
};
}
};
var string = Error.prototype.toString.call(e);
return [string,seq];
}
assertEquals(["Error",[1,3]], testErrorToString(undefined, undefined));
assertEquals(["e1",[1,2,3]], testErrorToString("e1", undefined));
assertEquals(["e1: null",[1,2,3,4]], testErrorToString("e1", null));
assertEquals(["e1",[1,2,3,4]], testErrorToString("e1", ""));
assertEquals(["Error: e2",[1,3,4]], testErrorToString(undefined, "e2"));
assertEquals(["null: e2",[1,2,3,4]], testErrorToString(null, "e2"));
assertEquals(["e2",[1,2,3,4]], testErrorToString("", "e2"));
assertEquals(["e1: e2",[1,2,3,4]], testErrorToString("e1", "e2"));
......@@ -502,9 +502,6 @@ S15.4.4.3_A2_T1: FAIL_OK
# Bug? Date.prototype.toISOString - value of year is Infinity
# Date.prototype.toISOString throw the RangeError
15.9.5.43-0-15: FAIL
# Bug? Error.prototype.toString return the value of 'msg' when 'name' is empty
# string and 'msg' isn't undefined
15.11.4.4-8-1: FAIL
############################ SKIPPED TESTS #############################
......
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