Index: src/js/messages.js |
diff --git a/src/js/messages.js b/src/js/messages.js |
index d0305412b74896a7971e4e435032b5f9a8ee3a05..dc845ea97adc855fa7d0847374dad1af99e7551a 100644 |
--- a/src/js/messages.js |
+++ b/src/js/messages.js |
@@ -23,7 +23,6 @@ |
utils.ImportNow("call_site_position_symbol"); |
var callSiteStrictSymbol = |
utils.ImportNow("call_site_strict_symbol"); |
-var FLAG_harmony_tostring; |
var Float32x4ToString; |
var formattedStackTraceSymbol = |
utils.ImportNow("formatted_stack_trace_symbol"); |
@@ -42,7 +41,6 @@ |
var StringIndexOf; |
var StringSubstring; |
var SymbolToString; |
-var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol"); |
var Uint16x8ToString; |
var Uint32x4ToString; |
var Uint8x16ToString; |
@@ -68,10 +66,6 @@ |
Uint8x16ToString = from.Uint8x16ToString; |
}); |
-utils.ImportFromExperimental(function(from) { |
- FLAG_harmony_tostring = from.FLAG_harmony_tostring; |
-}); |
- |
// ------------------------------------------------------------------- |
var GlobalError; |
@@ -86,35 +80,11 @@ |
function NoSideEffectsObjectToString() { |
if (IS_UNDEFINED(this)) return "[object Undefined]"; |
if (IS_NULL(this)) return "[object Null]"; |
- var O = TO_OBJECT(this); |
- var builtinTag = %_ClassOf(O); |
- var tag; |
- if (FLAG_harmony_tostring) { |
- tag = %GetDataProperty(O, toStringTagSymbol); |
- if (!IS_STRING(tag)) { |
- tag = builtinTag; |
- } |
- } else { |
- tag = builtinTag; |
- } |
- return `[object ${tag}]`; |
-} |
- |
-function IsErrorObject(obj) { |
- return HAS_PRIVATE(obj, stackTraceSymbol); |
-} |
- |
-function NoSideEffectsErrorToString() { |
- var name = %GetDataProperty(this, "name"); |
- var message = %GetDataProperty(this, "message"); |
- name = IS_UNDEFINED(name) ? "Error" : NoSideEffectsToString(name); |
- message = IS_UNDEFINED(message) ? "" : NoSideEffectsToString(message); |
- if (name == "") return message; |
- if (message == "") return name; |
- return `${name}: ${message}`; |
-} |
- |
-function NoSideEffectsToString(obj) { |
+ return "[object " + %_ClassOf(TO_OBJECT(this)) + "]"; |
+} |
+ |
+ |
+function NoSideEffectToString(obj) { |
if (IS_STRING(obj)) return obj; |
if (IS_NUMBER(obj)) return %_NumberToString(obj); |
if (IS_BOOLEAN(obj)) return obj ? 'true' : 'false'; |
@@ -143,26 +113,69 @@ |
case 'bool8x16': return %_Call(Bool8x16ToString, obj); |
} |
} |
- |
- if (IS_SPEC_OBJECT(obj)) { |
- // When internally formatting error objects, use a side-effects-free version |
- // of Error.prototype.toString independent of the actually installed |
- // toString method. |
- if (IsErrorObject(obj) || |
- %GetDataProperty(obj, "toString") === ErrorToString) { |
- return %_Call(NoSideEffectsErrorToString, obj); |
- } |
- |
- if (%GetDataProperty(obj, "toString") === ObjectToString) { |
- var constructor = %GetDataProperty(obj, "constructor"); |
- if (IS_FUNCTION(constructor)) { |
- var constructor_name = %FunctionGetName(constructor); |
- if (constructor_name != "") return `#<${constructor_name}>`; |
+ if (IS_OBJECT(obj) |
+ && %GetDataProperty(obj, "toString") === ObjectToString) { |
+ var constructor = %GetDataProperty(obj, "constructor"); |
+ if (typeof constructor == "function") { |
+ var constructorName = constructor.name; |
+ if (IS_STRING(constructorName) && constructorName !== "") { |
+ return "#<" + constructorName + ">"; |
} |
} |
} |
+ if (CanBeSafelyTreatedAsAnErrorObject(obj)) { |
+ return %_Call(ErrorToString, obj); |
+ } |
return %_Call(NoSideEffectsObjectToString, obj); |
+} |
+ |
+// To determine whether we can safely stringify an object using ErrorToString |
+// without the risk of side-effects, we need to check whether the object is |
+// either an instance of a native error type (via '%_ClassOf'), or has Error |
+// in its prototype chain and hasn't overwritten 'toString' with something |
+// strange and unusual. |
+function CanBeSafelyTreatedAsAnErrorObject(obj) { |
+ switch (%_ClassOf(obj)) { |
+ case 'Error': |
+ case 'EvalError': |
+ case 'RangeError': |
+ case 'ReferenceError': |
+ case 'SyntaxError': |
+ case 'TypeError': |
+ case 'URIError': |
+ return true; |
+ } |
+ |
+ var objToString = %GetDataProperty(obj, "toString"); |
+ return obj instanceof GlobalError && objToString === ErrorToString; |
+} |
+ |
+ |
+// When formatting internally created error messages, do not |
+// invoke overwritten error toString methods but explicitly use |
+// the error to string method. This is to avoid leaking error |
+// objects between script tags in a browser setting. |
+function ToStringCheckErrorObject(obj) { |
+ if (CanBeSafelyTreatedAsAnErrorObject(obj)) { |
+ return %_Call(ErrorToString, obj); |
+ } else { |
+ return TO_STRING(obj); |
+ } |
+} |
+ |
+ |
+function ToDetailString(obj) { |
+ if (obj != null && IS_OBJECT(obj) && obj.toString === ObjectToString) { |
+ var constructor = obj.constructor; |
+ if (typeof constructor == "function") { |
+ var constructorName = constructor.name; |
+ if (IS_STRING(constructorName) && constructorName !== "") { |
+ return "#<" + constructorName + ">"; |
+ } |
+ } |
+ } |
+ return ToStringCheckErrorObject(obj); |
} |
@@ -187,9 +200,9 @@ |
// Helper functions; called from the runtime system. |
function FormatMessage(type, arg0, arg1, arg2) { |
- var arg0 = NoSideEffectsToString(arg0); |
- var arg1 = NoSideEffectsToString(arg1); |
- var arg2 = NoSideEffectsToString(arg2); |
+ var arg0 = NoSideEffectToString(arg0); |
+ var arg1 = NoSideEffectToString(arg1); |
+ var arg2 = NoSideEffectToString(arg2); |
try { |
return %FormatMessageString(type, arg0, arg1, arg2); |
} catch (e) { |
@@ -836,13 +849,20 @@ |
function GetTypeName(receiver, requireConstructor) { |
if (IS_NULL_OR_UNDEFINED(receiver)) return null; |
- if (%_IsJSProxy(receiver)) return "Proxy"; |
- |
- var constructor = %GetDataProperty(TO_OBJECT(receiver), "constructor"); |
- if (!IS_FUNCTION(constructor)) { |
- return requireConstructor ? null : %_Call(NoSideEffectsToString, receiver); |
- } |
- return %FunctionGetName(constructor); |
+ if (%_IsJSProxy(receiver)) { |
+ return "Proxy"; |
+ }; |
+ var constructor = receiver.constructor; |
+ if (!constructor) { |
+ return requireConstructor ? null : |
+ %_Call(NoSideEffectsObjectToString, receiver); |
+ } |
+ var constructorName = constructor.name; |
+ if (!constructorName) { |
+ return requireConstructor ? null : |
+ %_Call(NoSideEffectsObjectToString, receiver); |
+ } |
+ return constructorName; |
} |
@@ -876,7 +896,7 @@ |
// If the receiver equals the holder, set the formatted stack trace that the |
// getter returns. |
var StackTraceSetter = function(v) { |
- if (IsErrorObject(this)) { |
+ if (HAS_PRIVATE(this, stackTraceSymbol)) { |
SET_PRIVATE(this, stackTraceSymbol, UNDEFINED); |
SET_PRIVATE(this, formattedStackTraceSymbol, v); |
} |
@@ -936,15 +956,7 @@ |
throw MakeTypeError(kCalledOnNonObject, "Error.prototype.toString"); |
} |
- var name = this.name; |
- name = IS_UNDEFINED(name) ? "Error" : TO_STRING(name); |
- |
- var message = this.message; |
- message = IS_UNDEFINED(message) ? "" : TO_STRING(message); |
- |
- if (name == "") return message; |
- if (message == "") return name; |
- return `${name}: ${message}` |
+ return %ErrorToStringRT(this); |
} |
function MakeError(type, arg0, arg1, arg2) { |
@@ -992,8 +1004,9 @@ |
"message_get_column_number", GetColumnNumber, |
"message_get_line_number", GetLineNumber, |
"message_get_source_line", GetSourceLine, |
- "no_side_effects_to_string_fun", NoSideEffectsToString, |
+ "no_side_effect_to_string_fun", NoSideEffectToString, |
"stack_overflow_boilerplate", StackOverflowBoilerplate, |
+ "to_detail_string_fun", ToDetailString, |
]); |
utils.Export(function(to) { |