Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1119)

Side by Side Diff: src/js/messages.js

Issue 1507273002: Make Error.prototype.toString spec compliant; and fix various side-effect-free error printing metho… (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/isolate.cc ('k') | src/messages.h » ('j') | src/messages.cc » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // ------------------------------------------------------------------- 5 // -------------------------------------------------------------------
6 6
7 (function(global, utils) { 7 (function(global, utils) {
8 8
9 %CheckIsBootstrapping(); 9 %CheckIsBootstrapping();
10 10
11 // ------------------------------------------------------------------- 11 // -------------------------------------------------------------------
12 // Imports 12 // Imports
13 13
14 var ArrayJoin; 14 var ArrayJoin;
15 var Bool16x8ToString; 15 var Bool16x8ToString;
16 var Bool32x4ToString; 16 var Bool32x4ToString;
17 var Bool8x16ToString; 17 var Bool8x16ToString;
18 var callSiteReceiverSymbol = 18 var callSiteReceiverSymbol =
19 utils.ImportNow("call_site_receiver_symbol"); 19 utils.ImportNow("call_site_receiver_symbol");
20 var callSiteFunctionSymbol = 20 var callSiteFunctionSymbol =
21 utils.ImportNow("call_site_function_symbol"); 21 utils.ImportNow("call_site_function_symbol");
22 var callSitePositionSymbol = 22 var callSitePositionSymbol =
23 utils.ImportNow("call_site_position_symbol"); 23 utils.ImportNow("call_site_position_symbol");
24 var callSiteStrictSymbol = 24 var callSiteStrictSymbol =
25 utils.ImportNow("call_site_strict_symbol"); 25 utils.ImportNow("call_site_strict_symbol");
26 var FLAG_harmony_tostring;
26 var Float32x4ToString; 27 var Float32x4ToString;
27 var formattedStackTraceSymbol = 28 var formattedStackTraceSymbol =
28 utils.ImportNow("formatted_stack_trace_symbol"); 29 utils.ImportNow("formatted_stack_trace_symbol");
29 var FunctionSourceString 30 var FunctionSourceString
30 var GlobalObject = global.Object; 31 var GlobalObject = global.Object;
31 var Int16x8ToString; 32 var Int16x8ToString;
32 var Int32x4ToString; 33 var Int32x4ToString;
33 var Int8x16ToString; 34 var Int8x16ToString;
34 var InternalArray = utils.InternalArray; 35 var InternalArray = utils.InternalArray;
35 var internalErrorSymbol = utils.ImportNow("internal_error_symbol"); 36 var internalErrorSymbol = utils.ImportNow("internal_error_symbol");
36 var ObjectDefineProperty; 37 var ObjectDefineProperty;
37 var ObjectToString; 38 var ObjectToString;
38 var Script = utils.ImportNow("Script"); 39 var Script = utils.ImportNow("Script");
39 var stackTraceSymbol = utils.ImportNow("stack_trace_symbol"); 40 var stackTraceSymbol = utils.ImportNow("stack_trace_symbol");
40 var StringCharAt; 41 var StringCharAt;
41 var StringIndexOf; 42 var StringIndexOf;
42 var StringSubstring; 43 var StringSubstring;
43 var SymbolToString; 44 var SymbolToString;
45 var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
44 var Uint16x8ToString; 46 var Uint16x8ToString;
45 var Uint32x4ToString; 47 var Uint32x4ToString;
46 var Uint8x16ToString; 48 var Uint8x16ToString;
47 49
48 utils.Import(function(from) { 50 utils.Import(function(from) {
49 ArrayJoin = from.ArrayJoin; 51 ArrayJoin = from.ArrayJoin;
50 Bool16x8ToString = from.Bool16x8ToString; 52 Bool16x8ToString = from.Bool16x8ToString;
51 Bool32x4ToString = from.Bool32x4ToString; 53 Bool32x4ToString = from.Bool32x4ToString;
52 Bool8x16ToString = from.Bool8x16ToString; 54 Bool8x16ToString = from.Bool8x16ToString;
53 Float32x4ToString = from.Float32x4ToString; 55 Float32x4ToString = from.Float32x4ToString;
54 FunctionSourceString = from.FunctionSourceString; 56 FunctionSourceString = from.FunctionSourceString;
55 Int16x8ToString = from.Int16x8ToString; 57 Int16x8ToString = from.Int16x8ToString;
56 Int32x4ToString = from.Int32x4ToString; 58 Int32x4ToString = from.Int32x4ToString;
57 Int8x16ToString = from.Int8x16ToString; 59 Int8x16ToString = from.Int8x16ToString;
58 ObjectDefineProperty = from.ObjectDefineProperty; 60 ObjectDefineProperty = from.ObjectDefineProperty;
59 ObjectToString = from.ObjectToString; 61 ObjectToString = from.ObjectToString;
60 StringCharAt = from.StringCharAt; 62 StringCharAt = from.StringCharAt;
61 StringIndexOf = from.StringIndexOf; 63 StringIndexOf = from.StringIndexOf;
62 StringSubstring = from.StringSubstring; 64 StringSubstring = from.StringSubstring;
63 SymbolToString = from.SymbolToString; 65 SymbolToString = from.SymbolToString;
64 Uint16x8ToString = from.Uint16x8ToString; 66 Uint16x8ToString = from.Uint16x8ToString;
65 Uint32x4ToString = from.Uint32x4ToString; 67 Uint32x4ToString = from.Uint32x4ToString;
66 Uint8x16ToString = from.Uint8x16ToString; 68 Uint8x16ToString = from.Uint8x16ToString;
67 }); 69 });
68 70
71 utils.ImportFromExperimental(function(from) {
72 FLAG_harmony_tostring = from.FLAG_harmony_tostring;
73 });
74
69 // ------------------------------------------------------------------- 75 // -------------------------------------------------------------------
70 76
71 var GlobalError; 77 var GlobalError;
72 var GlobalTypeError; 78 var GlobalTypeError;
73 var GlobalRangeError; 79 var GlobalRangeError;
74 var GlobalURIError; 80 var GlobalURIError;
75 var GlobalSyntaxError; 81 var GlobalSyntaxError;
76 var GlobalReferenceError; 82 var GlobalReferenceError;
77 var GlobalEvalError; 83 var GlobalEvalError;
78 84
79 85
80 function NoSideEffectsObjectToString() { 86 function NoSideEffectsObjectToString() {
81 if (IS_UNDEFINED(this)) return "[object Undefined]"; 87 if (IS_UNDEFINED(this)) return "[object Undefined]";
82 if (IS_NULL(this)) return "[object Null]"; 88 if (IS_NULL(this)) return "[object Null]";
83 return "[object " + %_ClassOf(TO_OBJECT(this)) + "]"; 89 var O = TO_OBJECT(this);
90 var builtinTag = %_ClassOf(O);
91 var tag;
92 if (FLAG_harmony_tostring) {
93 tag = %GetDataProperty(O, toStringTagSymbol);
94 if (!IS_STRING(tag)) {
95 tag = builtinTag;
96 }
97 } else {
98 tag = builtinTag;
99 }
100 return `[object ${tag}]`;
84 } 101 }
85 102
103 function IsErrorObject(obj) {
104 return HAS_PRIVATE(obj, stackTraceSymbol);
105 }
86 106
87 function NoSideEffectToString(obj) { 107 function NoSideEffectsErrorToString() {
108 var name = %GetDataProperty(this, "name");
109 var message = %GetDataProperty(this, "message");
110 name = IS_UNDEFINED(name) ? "Error" : NoSideEffectsToString(name);
111 message = IS_UNDEFINED(message) ? "" : NoSideEffectsToString(message);
112 if (name == "") return message;
113 if (message == "") return name;
114 return `${name}: ${message}`;
115 }
116
117 function NoSideEffectsToString(obj) {
88 if (IS_STRING(obj)) return obj; 118 if (IS_STRING(obj)) return obj;
89 if (IS_NUMBER(obj)) return %_NumberToString(obj); 119 if (IS_NUMBER(obj)) return %_NumberToString(obj);
90 if (IS_BOOLEAN(obj)) return obj ? 'true' : 'false'; 120 if (IS_BOOLEAN(obj)) return obj ? 'true' : 'false';
91 if (IS_UNDEFINED(obj)) return 'undefined'; 121 if (IS_UNDEFINED(obj)) return 'undefined';
92 if (IS_NULL(obj)) return 'null'; 122 if (IS_NULL(obj)) return 'null';
93 if (IS_FUNCTION(obj)) { 123 if (IS_FUNCTION(obj)) {
94 var str = %_Call(FunctionSourceString, obj, obj); 124 var str = %_Call(FunctionSourceString, obj, obj);
95 if (str.length > 128) { 125 if (str.length > 128) {
96 str = %_SubString(str, 0, 111) + "...<omitted>..." + 126 str = %_SubString(str, 0, 111) + "...<omitted>..." +
97 %_SubString(str, str.length - 2, str.length); 127 %_SubString(str, str.length - 2, str.length);
98 } 128 }
99 return str; 129 return str;
100 } 130 }
101 if (IS_SYMBOL(obj)) return %_Call(SymbolToString, obj); 131 if (IS_SYMBOL(obj)) return %_Call(SymbolToString, obj);
102 if (IS_SIMD_VALUE(obj)) { 132 if (IS_SIMD_VALUE(obj)) {
103 switch (typeof(obj)) { 133 switch (typeof(obj)) {
104 case 'float32x4': return %_Call(Float32x4ToString, obj); 134 case 'float32x4': return %_Call(Float32x4ToString, obj);
105 case 'int32x4': return %_Call(Int32x4ToString, obj); 135 case 'int32x4': return %_Call(Int32x4ToString, obj);
106 case 'int16x8': return %_Call(Int16x8ToString, obj); 136 case 'int16x8': return %_Call(Int16x8ToString, obj);
107 case 'int8x16': return %_Call(Int8x16ToString, obj); 137 case 'int8x16': return %_Call(Int8x16ToString, obj);
108 case 'uint32x4': return %_Call(Uint32x4ToString, obj); 138 case 'uint32x4': return %_Call(Uint32x4ToString, obj);
109 case 'uint16x8': return %_Call(Uint16x8ToString, obj); 139 case 'uint16x8': return %_Call(Uint16x8ToString, obj);
110 case 'uint8x16': return %_Call(Uint8x16ToString, obj); 140 case 'uint8x16': return %_Call(Uint8x16ToString, obj);
111 case 'bool32x4': return %_Call(Bool32x4ToString, obj); 141 case 'bool32x4': return %_Call(Bool32x4ToString, obj);
112 case 'bool16x8': return %_Call(Bool16x8ToString, obj); 142 case 'bool16x8': return %_Call(Bool16x8ToString, obj);
113 case 'bool8x16': return %_Call(Bool8x16ToString, obj); 143 case 'bool8x16': return %_Call(Bool8x16ToString, obj);
114 } 144 }
115 } 145 }
116 if (IS_OBJECT(obj) 146
117 && %GetDataProperty(obj, "toString") === ObjectToString) { 147 if (IS_SPEC_OBJECT(obj)) {
118 var constructor = %GetDataProperty(obj, "constructor"); 148 // When internally formatting error objects, use a side-effects-free version
119 if (typeof constructor == "function") { 149 // of Error.prototype.toString independent of the actually installed
120 var constructorName = constructor.name; 150 // toString method.
121 if (IS_STRING(constructorName) && constructorName !== "") { 151 if (IsErrorObject(obj) ||
122 return "#<" + constructorName + ">"; 152 %GetDataProperty(obj, "toString") === ErrorToString) {
153 return %_Call(NoSideEffectsErrorToString, obj);
154 }
155
156 if (%GetDataProperty(obj, "toString") === ObjectToString) {
157 var constructor = %GetDataProperty(obj, "constructor");
158 if (IS_FUNCTION(constructor)) {
159 var constructor_name = %FunctionGetName(constructor);
160 if (constructor_name != "") return `#<${constructor_name}>`;
123 } 161 }
124 } 162 }
125 } 163 }
126 if (CanBeSafelyTreatedAsAnErrorObject(obj)) {
127 return %_Call(ErrorToString, obj);
128 }
129 164
130 return %_Call(NoSideEffectsObjectToString, obj); 165 return %_Call(NoSideEffectsObjectToString, obj);
131 } 166 }
132 167
133 // To determine whether we can safely stringify an object using ErrorToString
134 // without the risk of side-effects, we need to check whether the object is
135 // either an instance of a native error type (via '%_ClassOf'), or has Error
136 // in its prototype chain and hasn't overwritten 'toString' with something
137 // strange and unusual.
138 function CanBeSafelyTreatedAsAnErrorObject(obj) {
139 switch (%_ClassOf(obj)) {
140 case 'Error':
141 case 'EvalError':
142 case 'RangeError':
143 case 'ReferenceError':
144 case 'SyntaxError':
145 case 'TypeError':
146 case 'URIError':
147 return true;
148 }
149 168
150 var objToString = %GetDataProperty(obj, "toString");
151 return obj instanceof GlobalError && objToString === ErrorToString;
152 }
153
154
155 // When formatting internally created error messages, do not
156 // invoke overwritten error toString methods but explicitly use
157 // the error to string method. This is to avoid leaking error
158 // objects between script tags in a browser setting.
159 function ToStringCheckErrorObject(obj) {
160 if (CanBeSafelyTreatedAsAnErrorObject(obj)) {
161 return %_Call(ErrorToString, obj);
162 } else {
163 return TO_STRING(obj);
164 }
165 }
166
167
168 function ToDetailString(obj) {
169 if (obj != null && IS_OBJECT(obj) && obj.toString === ObjectToString) {
170 var constructor = obj.constructor;
171 if (typeof constructor == "function") {
172 var constructorName = constructor.name;
173 if (IS_STRING(constructorName) && constructorName !== "") {
174 return "#<" + constructorName + ">";
175 }
176 }
177 }
178 return ToStringCheckErrorObject(obj);
179 }
180
181
182 function MakeGenericError(constructor, type, arg0, arg1, arg2) { 169 function MakeGenericError(constructor, type, arg0, arg1, arg2) {
183 var error = new constructor(FormatMessage(type, arg0, arg1, arg2)); 170 var error = new constructor(FormatMessage(type, arg0, arg1, arg2));
184 error[internalErrorSymbol] = true; 171 error[internalErrorSymbol] = true;
185 return error; 172 return error;
186 } 173 }
187 174
188 175
189 /** 176 /**
190 * Set up the Script function and constructor. 177 * Set up the Script function and constructor.
191 */ 178 */
192 %FunctionSetInstanceClassName(Script, 'Script'); 179 %FunctionSetInstanceClassName(Script, 'Script');
193 %AddNamedProperty(Script.prototype, 'constructor', Script, 180 %AddNamedProperty(Script.prototype, 'constructor', Script,
194 DONT_ENUM | DONT_DELETE | READ_ONLY); 181 DONT_ENUM | DONT_DELETE | READ_ONLY);
195 %SetCode(Script, function(x) { 182 %SetCode(Script, function(x) {
196 // Script objects can only be created by the VM. 183 // Script objects can only be created by the VM.
197 throw MakeError(kUnsupported); 184 throw MakeError(kUnsupported);
198 }); 185 });
199 186
200 187
201 // Helper functions; called from the runtime system. 188 // Helper functions; called from the runtime system.
202 function FormatMessage(type, arg0, arg1, arg2) { 189 function FormatMessage(type, arg0, arg1, arg2) {
203 var arg0 = NoSideEffectToString(arg0); 190 var arg0 = NoSideEffectsToString(arg0);
204 var arg1 = NoSideEffectToString(arg1); 191 var arg1 = NoSideEffectsToString(arg1);
205 var arg2 = NoSideEffectToString(arg2); 192 var arg2 = NoSideEffectsToString(arg2);
206 try { 193 try {
207 return %FormatMessageString(type, arg0, arg1, arg2); 194 return %FormatMessageString(type, arg0, arg1, arg2);
208 } catch (e) { 195 } catch (e) {
209 return "<error>"; 196 return "<error>";
210 } 197 }
211 } 198 }
212 199
213 200
214 function GetLineNumber(message) { 201 function GetLineNumber(message) {
215 var start_position = %MessageGetStartPosition(message); 202 var start_position = %MessageGetStartPosition(message);
(...skipping 626 matching lines...) Expand 10 before | Expand all | Expand 10 after
842 } 829 }
843 } 830 }
844 lines.push(" at " + line); 831 lines.push(" at " + line);
845 } 832 }
846 return %_Call(ArrayJoin, lines, "\n"); 833 return %_Call(ArrayJoin, lines, "\n");
847 } 834 }
848 835
849 836
850 function GetTypeName(receiver, requireConstructor) { 837 function GetTypeName(receiver, requireConstructor) {
851 if (IS_NULL_OR_UNDEFINED(receiver)) return null; 838 if (IS_NULL_OR_UNDEFINED(receiver)) return null;
852 if (%_IsJSProxy(receiver)) { 839 if (%_IsJSProxy(receiver)) return "Proxy";
853 return "Proxy"; 840
854 }; 841 var constructor = %GetDataProperty(TO_OBJECT(receiver), "constructor");
855 var constructor = receiver.constructor; 842 if (!IS_FUNCTION(constructor)) {
856 if (!constructor) { 843 return requireConstructor ? null : %_Call(NoSideEffectsToString, receiver);
857 return requireConstructor ? null :
858 %_Call(NoSideEffectsObjectToString, receiver);
859 } 844 }
860 var constructorName = constructor.name; 845 return %FunctionGetName(constructor);
861 if (!constructorName) {
862 return requireConstructor ? null :
863 %_Call(NoSideEffectsObjectToString, receiver);
864 }
865 return constructorName;
866 } 846 }
867 847
868 848
869 // Format the stack trace if not yet done, and return it. 849 // Format the stack trace if not yet done, and return it.
870 // Cache the formatted stack trace on the holder. 850 // Cache the formatted stack trace on the holder.
871 var StackTraceGetter = function() { 851 var StackTraceGetter = function() {
872 var formatted_stack_trace = UNDEFINED; 852 var formatted_stack_trace = UNDEFINED;
873 var holder = this; 853 var holder = this;
874 while (holder) { 854 while (holder) {
875 var formatted_stack_trace = 855 var formatted_stack_trace =
(...skipping 13 matching lines...) Expand all
889 } 869 }
890 return formatted_stack_trace; 870 return formatted_stack_trace;
891 } 871 }
892 return UNDEFINED; 872 return UNDEFINED;
893 }; 873 };
894 874
895 875
896 // If the receiver equals the holder, set the formatted stack trace that the 876 // If the receiver equals the holder, set the formatted stack trace that the
897 // getter returns. 877 // getter returns.
898 var StackTraceSetter = function(v) { 878 var StackTraceSetter = function(v) {
899 if (HAS_PRIVATE(this, stackTraceSymbol)) { 879 if (IsErrorObject(this)) {
900 SET_PRIVATE(this, stackTraceSymbol, UNDEFINED); 880 SET_PRIVATE(this, stackTraceSymbol, UNDEFINED);
901 SET_PRIVATE(this, formattedStackTraceSymbol, v); 881 SET_PRIVATE(this, formattedStackTraceSymbol, v);
902 } 882 }
903 }; 883 };
904 884
905 885
906 // Use a dummy function since we do not actually want to capture a stack trace 886 // Use a dummy function since we do not actually want to capture a stack trace
907 // when constructing the initial Error prototytpes. 887 // when constructing the initial Error prototytpes.
908 var captureStackTrace = function() {}; 888 var captureStackTrace = function() {};
909 889
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
949 GlobalURIError = SetUpError(global.URIError); 929 GlobalURIError = SetUpError(global.URIError);
950 930
951 utils.InstallFunctions(GlobalError.prototype, DONT_ENUM, 931 utils.InstallFunctions(GlobalError.prototype, DONT_ENUM,
952 ['toString', ErrorToString]); 932 ['toString', ErrorToString]);
953 933
954 function ErrorToString() { 934 function ErrorToString() {
955 if (!IS_SPEC_OBJECT(this)) { 935 if (!IS_SPEC_OBJECT(this)) {
956 throw MakeTypeError(kCalledOnNonObject, "Error.prototype.toString"); 936 throw MakeTypeError(kCalledOnNonObject, "Error.prototype.toString");
957 } 937 }
958 938
959 return %ErrorToStringRT(this); 939 var name = this.name;
940 name = IS_UNDEFINED(name) ? "Error" : TO_STRING(name);
941
942 var message = this.message;
943 message = IS_UNDEFINED(message) ? "" : TO_STRING(message);
944
945 if (name == "") return message;
946 if (message == "") return name;
947 return `${name}: ${message}`
960 } 948 }
961 949
962 function MakeError(type, arg0, arg1, arg2) { 950 function MakeError(type, arg0, arg1, arg2) {
963 return MakeGenericError(GlobalError, type, arg0, arg1, arg2); 951 return MakeGenericError(GlobalError, type, arg0, arg1, arg2);
964 } 952 }
965 953
966 function MakeRangeError(type, arg0, arg1, arg2) { 954 function MakeRangeError(type, arg0, arg1, arg2) {
967 return MakeGenericError(GlobalRangeError, type, arg0, arg1, arg2); 955 return MakeGenericError(GlobalRangeError, type, arg0, arg1, arg2);
968 } 956 }
969 957
(...skipping 27 matching lines...) Expand all
997 GlobalError.captureStackTrace = captureStackTrace; 985 GlobalError.captureStackTrace = captureStackTrace;
998 986
999 %InstallToContext([ 987 %InstallToContext([
1000 "get_stack_trace_line_fun", GetStackTraceLine, 988 "get_stack_trace_line_fun", GetStackTraceLine,
1001 "make_error_function", MakeGenericError, 989 "make_error_function", MakeGenericError,
1002 "make_range_error", MakeRangeError, 990 "make_range_error", MakeRangeError,
1003 "make_type_error", MakeTypeError, 991 "make_type_error", MakeTypeError,
1004 "message_get_column_number", GetColumnNumber, 992 "message_get_column_number", GetColumnNumber,
1005 "message_get_line_number", GetLineNumber, 993 "message_get_line_number", GetLineNumber,
1006 "message_get_source_line", GetSourceLine, 994 "message_get_source_line", GetSourceLine,
1007 "no_side_effect_to_string_fun", NoSideEffectToString, 995 "no_side_effects_to_string_fun", NoSideEffectsToString,
1008 "stack_overflow_boilerplate", StackOverflowBoilerplate, 996 "stack_overflow_boilerplate", StackOverflowBoilerplate,
1009 "to_detail_string_fun", ToDetailString,
1010 ]); 997 ]);
1011 998
1012 utils.Export(function(to) { 999 utils.Export(function(to) {
1013 to.ErrorToString = ErrorToString; 1000 to.ErrorToString = ErrorToString;
1014 to.MakeError = MakeError; 1001 to.MakeError = MakeError;
1015 to.MakeRangeError = MakeRangeError; 1002 to.MakeRangeError = MakeRangeError;
1016 to.MakeSyntaxError = MakeSyntaxError; 1003 to.MakeSyntaxError = MakeSyntaxError;
1017 to.MakeTypeError = MakeTypeError; 1004 to.MakeTypeError = MakeTypeError;
1018 to.MakeURIError = MakeURIError; 1005 to.MakeURIError = MakeURIError;
1019 }); 1006 });
1020 1007
1021 }); 1008 });
OLDNEW
« no previous file with comments | « src/isolate.cc ('k') | src/messages.h » ('j') | src/messages.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698