blob: 4da38051f9200746250867e23f9cc4228c524178 [file] [log] [blame]
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000028// -------------------------------------------------------------------
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000029//
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000030// If this object gets passed to an error constructor the error will
31// get an accessor for .message that constructs a descriptive error
32// message on access.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000033var kAddMessageAccessorsMarker = { };
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000034
fschneider@chromium.org1805e212011-09-05 10:49:12 +000035// This will be lazily initialized when first needed (and forcibly
36// overwritten even though it's const).
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000037var kMessages = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000039function FormatString(format, message) {
40 var args = %MessageGetArguments(message);
41 var result = "";
42 var arg_num = 0;
43 for (var i = 0; i < format.length; i++) {
44 var str = format[i];
fschneider@chromium.org1805e212011-09-05 10:49:12 +000045 if (str.length == 2 && %_StringCharCodeAt(str, 0) == 0x25) {
46 // Two-char string starts with "%".
47 var arg_num = (%_StringCharCodeAt(str, 1) - 0x30) >>> 0;
48 if (arg_num < 4) {
49 // str is one of %0, %1, %2 or %3.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000050 try {
51 str = ToDetailString(args[arg_num]);
52 } catch (e) {
danno@chromium.org81cac2b2012-07-10 11:28:27 +000053 if (%IsJSModule(args[arg_num]))
54 str = "module";
55 else if (IS_SPEC_OBJECT(args[arg_num]))
56 str = "object";
57 else
58 str = "#<error>";
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000059 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000060 }
ager@chromium.org378b34e2011-01-28 08:04:38 +000061 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000062 result += str;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000063 }
64 return result;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000065}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000066
67
ager@chromium.org0ee099b2011-01-25 14:06:47 +000068// To check if something is a native error we need to check the
ulan@chromium.orgd6899c32012-05-18 14:12:25 +000069// concrete native error types. It is not sufficient to use instanceof
70// since it possible to create an object that has Error.prototype on
71// its prototype chain. This is the case for DOMException for example.
ager@chromium.org0ee099b2011-01-25 14:06:47 +000072function IsNativeErrorObject(obj) {
ulan@chromium.orgd6899c32012-05-18 14:12:25 +000073 switch (%_ClassOf(obj)) {
74 case 'Error':
75 case 'EvalError':
76 case 'RangeError':
77 case 'ReferenceError':
78 case 'SyntaxError':
79 case 'TypeError':
80 case 'URIError':
81 return true;
82 }
83 return false;
ager@chromium.org0ee099b2011-01-25 14:06:47 +000084}
85
86
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000087// When formatting internally created error messages, do not
88// invoke overwritten error toString methods but explicitly use
89// the error to string method. This is to avoid leaking error
90// objects between script tags in a browser setting.
91function ToStringCheckErrorObject(obj) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +000092 if (IsNativeErrorObject(obj)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000093 return %_CallFunction(obj, ErrorToString);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000094 } else {
95 return ToString(obj);
96 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000097}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000098
99
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000100function ToDetailString(obj) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000101 if (obj != null && IS_OBJECT(obj) && obj.toString === ObjectToString) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000102 var constructor = obj.constructor;
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000103 if (typeof constructor == "function") {
104 var constructorName = constructor.name;
105 if (IS_STRING(constructorName) && constructorName !== "") {
106 return "#<" + constructorName + ">";
107 }
ager@chromium.org378b34e2011-01-28 08:04:38 +0000108 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000109 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000110 return ToStringCheckErrorObject(obj);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000111}
112
113
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000114function MakeGenericError(constructor, type, args) {
ager@chromium.org3e875802009-06-29 08:26:34 +0000115 if (IS_UNDEFINED(args)) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000116 args = [];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000117 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000118 var e = new constructor(kAddMessageAccessorsMarker);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000119 e.type = type;
120 e.arguments = args;
121 return e;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000122}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000123
124
125/**
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000126 * Set up the Script function and constructor.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000127 */
128%FunctionSetInstanceClassName(Script, 'Script');
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000129%SetProperty(Script.prototype, 'constructor', Script,
130 DONT_ENUM | DONT_DELETE | READ_ONLY);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000131%SetCode(Script, function(x) {
132 // Script objects can only be created by the VM.
133 throw new $Error("Not supported");
134});
135
136
137// Helper functions; called from the runtime system.
138function FormatMessage(message) {
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000139 if (kMessages === 0) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000140 var messagesDictionary = [
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000141 // Error
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000142 "cyclic_proto", ["Cyclic __proto__ value"],
143 "code_gen_from_strings", ["Code generation from strings disallowed for this context"],
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000144 // TypeError
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000145 "unexpected_token", ["Unexpected token ", "%0"],
146 "unexpected_token_number", ["Unexpected number"],
147 "unexpected_token_string", ["Unexpected string"],
148 "unexpected_token_identifier", ["Unexpected identifier"],
149 "unexpected_reserved", ["Unexpected reserved word"],
150 "unexpected_strict_reserved", ["Unexpected strict mode reserved word"],
151 "unexpected_eos", ["Unexpected end of input"],
152 "malformed_regexp", ["Invalid regular expression: /", "%0", "/: ", "%1"],
153 "unterminated_regexp", ["Invalid regular expression: missing /"],
154 "regexp_flags", ["Cannot supply flags when constructing one RegExp from another"],
155 "incompatible_method_receiver", ["Method ", "%0", " called on incompatible receiver ", "%1"],
156 "invalid_lhs_in_assignment", ["Invalid left-hand side in assignment"],
157 "invalid_lhs_in_for_in", ["Invalid left-hand side in for-in"],
158 "invalid_lhs_in_postfix_op", ["Invalid left-hand side expression in postfix operation"],
159 "invalid_lhs_in_prefix_op", ["Invalid left-hand side expression in prefix operation"],
160 "multiple_defaults_in_switch", ["More than one default clause in switch statement"],
161 "newline_after_throw", ["Illegal newline after throw"],
162 "redeclaration", ["%0", " '", "%1", "' has already been declared"],
163 "no_catch_or_finally", ["Missing catch or finally after try"],
164 "unknown_label", ["Undefined label '", "%0", "'"],
165 "uncaught_exception", ["Uncaught ", "%0"],
166 "stack_trace", ["Stack Trace:\n", "%0"],
167 "called_non_callable", ["%0", " is not a function"],
168 "undefined_method", ["Object ", "%1", " has no method '", "%0", "'"],
169 "property_not_function", ["Property '", "%0", "' of object ", "%1", " is not a function"],
170 "cannot_convert_to_primitive", ["Cannot convert object to primitive value"],
171 "not_constructor", ["%0", " is not a constructor"],
172 "not_defined", ["%0", " is not defined"],
173 "non_object_property_load", ["Cannot read property '", "%0", "' of ", "%1"],
174 "non_object_property_store", ["Cannot set property '", "%0", "' of ", "%1"],
175 "non_object_property_call", ["Cannot call method '", "%0", "' of ", "%1"],
176 "with_expression", ["%0", " has no properties"],
177 "illegal_invocation", ["Illegal invocation"],
178 "no_setter_in_callback", ["Cannot set property ", "%0", " of ", "%1", " which has only a getter"],
179 "apply_non_function", ["Function.prototype.apply was called on ", "%0", ", which is a ", "%1", " and not a function"],
180 "apply_wrong_args", ["Function.prototype.apply: Arguments list has wrong type"],
181 "invalid_in_operator_use", ["Cannot use 'in' operator to search for '", "%0", "' in ", "%1"],
182 "instanceof_function_expected", ["Expecting a function in instanceof check, but got ", "%0"],
183 "instanceof_nonobject_proto", ["Function has non-object prototype '", "%0", "' in instanceof check"],
184 "null_to_object", ["Cannot convert null to object"],
185 "reduce_no_initial", ["Reduce of empty array with no initial value"],
186 "getter_must_be_callable", ["Getter must be a function: ", "%0"],
187 "setter_must_be_callable", ["Setter must be a function: ", "%0"],
188 "value_and_accessor", ["Invalid property. A property cannot both have accessors and be writable or have a value, ", "%0"],
189 "proto_object_or_null", ["Object prototype may only be an Object or null"],
190 "property_desc_object", ["Property description must be an object: ", "%0"],
191 "redefine_disallowed", ["Cannot redefine property: ", "%0"],
192 "define_disallowed", ["Cannot define property:", "%0", ", object is not extensible."],
193 "non_extensible_proto", ["%0", " is not extensible"],
194 "handler_non_object", ["Proxy.", "%0", " called with non-object as handler"],
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000195 "proto_non_object", ["Proxy.", "%0", " called with non-object as prototype"],
196 "trap_function_expected", ["Proxy.", "%0", " called with non-function for '", "%1", "' trap"],
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000197 "handler_trap_missing", ["Proxy handler ", "%0", " has no '", "%1", "' trap"],
198 "handler_trap_must_be_callable", ["Proxy handler ", "%0", " has non-callable '", "%1", "' trap"],
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000199 "handler_returned_false", ["Proxy handler ", "%0", " returned false from '", "%1", "' trap"],
200 "handler_returned_undefined", ["Proxy handler ", "%0", " returned undefined from '", "%1", "' trap"],
201 "proxy_prop_not_configurable", ["Proxy handler ", "%0", " returned non-configurable descriptor for property '", "%2", "' from '", "%1", "' trap"],
202 "proxy_non_object_prop_names", ["Trap '", "%1", "' returned non-object ", "%0"],
203 "proxy_repeated_prop_name", ["Trap '", "%1", "' returned repeated property name '", "%2", "'"],
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000204 "invalid_weakmap_key", ["Invalid value used as weak map key"],
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000205 // RangeError
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000206 "invalid_array_length", ["Invalid array length"],
207 "stack_overflow", ["Maximum call stack size exceeded"],
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000208 "invalid_time_value", ["Invalid time value"],
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000209 // SyntaxError
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000210 "unable_to_parse", ["Parse error"],
211 "invalid_regexp_flags", ["Invalid flags supplied to RegExp constructor '", "%0", "'"],
212 "invalid_regexp", ["Invalid RegExp pattern /", "%0", "/"],
213 "illegal_break", ["Illegal break statement"],
214 "illegal_continue", ["Illegal continue statement"],
215 "illegal_return", ["Illegal return statement"],
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000216 "illegal_let", ["Illegal let declaration outside extended mode"],
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000217 "error_loading_debugger", ["Error loading debugger"],
218 "no_input_to_regexp", ["No input to ", "%0"],
219 "invalid_json", ["String '", "%0", "' is not valid JSON"],
220 "circular_structure", ["Converting circular structure to JSON"],
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000221 "called_on_non_object", ["%0", " called on non-object"],
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000222 "called_on_null_or_undefined", ["%0", " called on null or undefined"],
223 "array_indexof_not_defined", ["Array.getIndexOf: Argument undefined"],
224 "object_not_extensible", ["Can't add property ", "%0", ", object is not extensible"],
225 "illegal_access", ["Illegal access"],
226 "invalid_preparser_data", ["Invalid preparser data for function ", "%0"],
227 "strict_mode_with", ["Strict mode code may not include a with statement"],
228 "strict_catch_variable", ["Catch variable may not be eval or arguments in strict mode"],
229 "too_many_arguments", ["Too many arguments in function call (only 32766 allowed)"],
230 "too_many_parameters", ["Too many parameters in function definition (only 32766 allowed)"],
231 "too_many_variables", ["Too many variables declared (only 32767 allowed)"],
232 "strict_param_name", ["Parameter name eval or arguments is not allowed in strict mode"],
233 "strict_param_dupe", ["Strict mode function may not have duplicate parameter names"],
234 "strict_var_name", ["Variable name may not be eval or arguments in strict mode"],
235 "strict_function_name", ["Function name may not be eval or arguments in strict mode"],
236 "strict_octal_literal", ["Octal literals are not allowed in strict mode."],
237 "strict_duplicate_property", ["Duplicate data property in object literal not allowed in strict mode"],
238 "accessor_data_property", ["Object literal may not have data and accessor property with the same name"],
239 "accessor_get_set", ["Object literal may not have multiple get/set accessors with the same name"],
240 "strict_lhs_assignment", ["Assignment to eval or arguments is not allowed in strict mode"],
241 "strict_lhs_postfix", ["Postfix increment/decrement may not have eval or arguments operand in strict mode"],
242 "strict_lhs_prefix", ["Prefix increment/decrement may not have eval or arguments operand in strict mode"],
243 "strict_reserved_word", ["Use of future reserved word in strict mode"],
244 "strict_delete", ["Delete of an unqualified identifier in strict mode."],
245 "strict_delete_property", ["Cannot delete property '", "%0", "' of ", "%1"],
246 "strict_const", ["Use of const in strict mode."],
247 "strict_function", ["In strict mode code, functions can only be declared at top level or immediately within another function." ],
248 "strict_read_only_property", ["Cannot assign to read only property '", "%0", "' of ", "%1"],
249 "strict_cannot_assign", ["Cannot assign to read only '", "%0", "' in strict mode"],
250 "strict_poison_pill", ["'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them"],
251 "strict_caller", ["Illegal access to a strict mode caller function."],
252 "unprotected_let", ["Illegal let declaration in unprotected statement context."],
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000253 "unprotected_const", ["Illegal const declaration in unprotected statement context."],
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000254 "cant_prevent_ext_external_array_elements", ["Cannot prevent extension of an object with external array elements"],
255 "redef_external_array_element", ["Cannot redefine a property of an object with external array elements"],
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000256 "harmony_const_assign", ["Assignment to constant variable."],
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000257 "invalid_module_path", ["Module does not export '", "%0", "', or export is not itself a module"],
258 "module_type_error", ["Module '", "%0", "' used improperly"],
danno@chromium.org81cac2b2012-07-10 11:28:27 +0000259 "module_export_undefined", ["Export '", "%0", "' is not defined in module"],
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000260 ];
261 var messages = { __proto__ : null };
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000262 for (var i = 0; i < messagesDictionary.length; i += 2) {
263 var key = messagesDictionary[i];
264 var format = messagesDictionary[i + 1];
ricow@chromium.org93720df2011-11-07 11:02:21 +0000265
266 for (var j = 0; j < format.length; j++) {
267 %IgnoreAttributesAndSetProperty(format, %_NumberToString(j), format[j],
268 DONT_DELETE | READ_ONLY | DONT_ENUM);
269 }
270 %IgnoreAttributesAndSetProperty(format, 'length', format.length,
271 DONT_DELETE | READ_ONLY | DONT_ENUM);
272 %PreventExtensions(format);
273 %IgnoreAttributesAndSetProperty(messages,
274 key,
275 format,
276 DONT_DELETE | DONT_ENUM | READ_ONLY);
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000277 }
278 %PreventExtensions(messages);
279 %IgnoreAttributesAndSetProperty(builtins, "kMessages",
280 messages,
281 DONT_DELETE | DONT_ENUM | READ_ONLY);
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000282 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000283 var message_type = %MessageGetType(message);
284 var format = kMessages[message_type];
285 if (!format) return "<unknown message " + message_type + ">";
286 return FormatString(format, message);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000287}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000288
289
290function GetLineNumber(message) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000291 var start_position = %MessageGetStartPosition(message);
292 if (start_position == -1) return kNoLineNumberInfo;
293 var script = %MessageGetScript(message);
294 var location = script.locationFromPosition(start_position, true);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000295 if (location == null) return kNoLineNumberInfo;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000296 return location.line + 1;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000297}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000298
299
300// Returns the source code line containing the given source
301// position, or the empty string if the position is invalid.
302function GetSourceLine(message) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000303 var script = %MessageGetScript(message);
304 var start_position = %MessageGetStartPosition(message);
305 var location = script.locationFromPosition(start_position, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000306 if (location == null) return "";
307 location.restrict();
308 return location.sourceText();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000309}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000310
311
312function MakeTypeError(type, args) {
313 return MakeGenericError($TypeError, type, args);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000314}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000315
316
317function MakeRangeError(type, args) {
318 return MakeGenericError($RangeError, type, args);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000319}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000320
321
322function MakeSyntaxError(type, args) {
323 return MakeGenericError($SyntaxError, type, args);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000324}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000325
326
327function MakeReferenceError(type, args) {
328 return MakeGenericError($ReferenceError, type, args);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000329}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000330
331
332function MakeEvalError(type, args) {
333 return MakeGenericError($EvalError, type, args);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000334}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000335
336
337function MakeError(type, args) {
338 return MakeGenericError($Error, type, args);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000339}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000340
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000341/**
342 * Find a line number given a specific source position.
343 * @param {number} position The source position.
344 * @return {number} 0 if input too small, -1 if input too large,
345 else the line number.
346 */
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000347function ScriptLineFromPosition(position) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000348 var lower = 0;
349 var upper = this.lineCount() - 1;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000350 var line_ends = this.line_ends;
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000351
352 // We'll never find invalid positions so bail right away.
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000353 if (position > line_ends[upper]) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000354 return -1;
355 }
356
357 // This means we don't have to safe-guard indexing line_ends[i - 1].
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000358 if (position <= line_ends[0]) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000359 return 0;
360 }
361
362 // Binary search to find line # from position range.
363 while (upper >= 1) {
364 var i = (lower + upper) >> 1;
365
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000366 if (position > line_ends[i]) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000367 lower = i + 1;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000368 } else if (position <= line_ends[i - 1]) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000369 upper = i - 1;
370 } else {
371 return i;
372 }
373 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000374
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000375 return -1;
376}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000377
378/**
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000379 * Get information on a specific source position.
380 * @param {number} position The source position
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000381 * @param {boolean} include_resource_offset Set to true to have the resource
382 * offset added to the location
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000383 * @return {SourceLocation}
384 * If line is negative or not in the source null is returned.
385 */
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000386function ScriptLocationFromPosition(position,
387 include_resource_offset) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000388 var line = this.lineFromPosition(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000389 if (line == -1) return null;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000390
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000391 // Determine start, end and column.
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000392 var line_ends = this.line_ends;
393 var start = line == 0 ? 0 : line_ends[line - 1] + 1;
394 var end = line_ends[line];
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000395 if (end > 0 && %_CallFunction(this.source, end - 1, StringCharAt) == '\r') {
396 end--;
397 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000398 var column = position - start;
399
400 // Adjust according to the offset within the resource.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000401 if (include_resource_offset) {
402 line += this.line_offset;
403 if (line == this.line_offset) {
404 column += this.column_offset;
405 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000406 }
407
408 return new SourceLocation(this, position, line, column, start, end);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000409}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000410
411
412/**
413 * Get information on a specific source line and column possibly offset by a
414 * fixed source position. This function is used to find a source position from
415 * a line and column position. The fixed source position offset is typically
416 * used to find a source position in a function based on a line and column in
417 * the source for the function alone. The offset passed will then be the
418 * start position of the source for the function within the full script source.
419 * @param {number} opt_line The line within the source. Default value is 0
420 * @param {number} opt_column The column in within the line. Default value is 0
421 * @param {number} opt_offset_position The offset from the begining of the
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000422 * source from where the line and column calculation starts.
423 * Default value is 0
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000424 * @return {SourceLocation}
425 * If line is negative or not in the source null is returned.
426 */
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000427function ScriptLocationFromLine(opt_line, opt_column, opt_offset_position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000428 // Default is the first line in the script. Lines in the script is relative
429 // to the offset within the resource.
430 var line = 0;
431 if (!IS_UNDEFINED(opt_line)) {
432 line = opt_line - this.line_offset;
433 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000434
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000435 // Default is first column. If on the first line add the offset within the
436 // resource.
437 var column = opt_column || 0;
438 if (line == 0) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000439 column -= this.column_offset;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000440 }
441
442 var offset_position = opt_offset_position || 0;
443 if (line < 0 || column < 0 || offset_position < 0) return null;
444 if (line == 0) {
ager@chromium.org3a6061e2009-03-12 14:24:36 +0000445 return this.locationFromPosition(offset_position + column, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000446 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000447 // Find the line where the offset position is located.
448 var offset_line = this.lineFromPosition(offset_position);
449
450 if (offset_line == -1 || offset_line + line >= this.lineCount()) {
451 return null;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000452 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000453
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000454 return this.locationFromPosition(
455 this.line_ends[offset_line + line - 1] + 1 + column); // line > 0 here.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000456 }
457}
458
459
460/**
461 * Get a slice of source code from the script. The boundaries for the slice is
462 * specified in lines.
463 * @param {number} opt_from_line The first line (zero bound) in the slice.
464 * Default is 0
465 * @param {number} opt_to_column The last line (zero bound) in the slice (non
466 * inclusive). Default is the number of lines in the script
467 * @return {SourceSlice} The source slice or null of the parameters where
468 * invalid
469 */
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000470function ScriptSourceSlice(opt_from_line, opt_to_line) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000471 var from_line = IS_UNDEFINED(opt_from_line) ? this.line_offset
472 : opt_from_line;
473 var to_line = IS_UNDEFINED(opt_to_line) ? this.line_offset + this.lineCount()
474 : opt_to_line;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000475
476 // Adjust according to the offset within the resource.
477 from_line -= this.line_offset;
478 to_line -= this.line_offset;
479 if (from_line < 0) from_line = 0;
480 if (to_line > this.lineCount()) to_line = this.lineCount();
481
iposva@chromium.org245aa852009-02-10 00:49:54 +0000482 // Check parameters.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000483 if (from_line >= this.lineCount() ||
484 to_line < 0 ||
485 from_line > to_line) {
486 return null;
487 }
488
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000489 var line_ends = this.line_ends;
490 var from_position = from_line == 0 ? 0 : line_ends[from_line - 1] + 1;
491 var to_position = to_line == 0 ? 0 : line_ends[to_line - 1] + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000492
493 // Return a source slice with line numbers re-adjusted to the resource.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000494 return new SourceSlice(this,
495 from_line + this.line_offset,
496 to_line + this.line_offset,
497 from_position, to_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000498}
499
500
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000501function ScriptSourceLine(opt_line) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000502 // Default is the first line in the script. Lines in the script are relative
503 // to the offset within the resource.
504 var line = 0;
505 if (!IS_UNDEFINED(opt_line)) {
506 line = opt_line - this.line_offset;
507 }
iposva@chromium.org245aa852009-02-10 00:49:54 +0000508
509 // Check parameter.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000510 if (line < 0 || this.lineCount() <= line) {
511 return null;
512 }
513
iposva@chromium.org245aa852009-02-10 00:49:54 +0000514 // Return the source line.
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000515 var line_ends = this.line_ends;
516 var start = line == 0 ? 0 : line_ends[line - 1] + 1;
517 var end = line_ends[line];
whesse@chromium.org7a392b32011-01-31 11:30:36 +0000518 return %_CallFunction(this.source, start, end, StringSubstring);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000519}
520
521
522/**
523 * Returns the number of source lines.
524 * @return {number}
525 * Number of source lines.
526 */
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000527function ScriptLineCount() {
iposva@chromium.org245aa852009-02-10 00:49:54 +0000528 // Return number of source lines.
529 return this.line_ends.length;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000530}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000531
532
533/**
lrn@chromium.org25156de2010-04-06 13:10:27 +0000534 * Returns the name of script if available, contents of sourceURL comment
vegorov@chromium.org42841962010-10-18 11:18:59 +0000535 * otherwise. See
lrn@chromium.org25156de2010-04-06 13:10:27 +0000536 * http://fbug.googlecode.com/svn/branches/firebug1.1/docs/ReleaseNotes_1.1.txt
537 * for details on using //@ sourceURL comment to identify scritps that don't
538 * have name.
vegorov@chromium.org42841962010-10-18 11:18:59 +0000539 *
lrn@chromium.org25156de2010-04-06 13:10:27 +0000540 * @return {?string} script name if present, value for //@ sourceURL comment
541 * otherwise.
542 */
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000543function ScriptNameOrSourceURL() {
544 if (this.name) {
lrn@chromium.org25156de2010-04-06 13:10:27 +0000545 return this.name;
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000546 }
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000547
548 // The result is cached as on long scripts it takes noticable time to search
549 // for the sourceURL.
550 if (this.hasCachedNameOrSourceURL)
551 return this.cachedNameOrSourceURL;
552 this.hasCachedNameOrSourceURL = true;
553
vegorov@chromium.org42841962010-10-18 11:18:59 +0000554 // TODO(608): the spaces in a regexp below had to be escaped as \040
lrn@chromium.org25156de2010-04-06 13:10:27 +0000555 // because this file is being processed by js2c whose handling of spaces
556 // in regexps is broken. Also, ['"] are excluded from allowed URLs to
557 // avoid matches against sources that invoke evals with sourceURL.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000558 // A better solution would be to detect these special comments in
559 // the scanner/parser.
560 var source = ToString(this.source);
561 var sourceUrlPos = %StringIndexOf(source, "sourceURL=", 0);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000562 this.cachedNameOrSourceURL = this.name;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000563 if (sourceUrlPos > 4) {
564 var sourceUrlPattern =
565 /\/\/@[\040\t]sourceURL=[\040\t]*([^\s\'\"]*)[\040\t]*$/gm;
566 // Don't reuse lastMatchInfo here, so we create a new array with room
567 // for four captures (array with length one longer than the index
568 // of the fourth capture, where the numbering is zero-based).
569 var matchInfo = new InternalArray(CAPTURE(3) + 1);
570 var match =
571 %_RegExpExec(sourceUrlPattern, source, sourceUrlPos - 4, matchInfo);
572 if (match) {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000573 this.cachedNameOrSourceURL =
574 SubString(source, matchInfo[CAPTURE(2)], matchInfo[CAPTURE(3)]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000575 }
576 }
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000577 return this.cachedNameOrSourceURL;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000578}
579
580
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000581SetUpLockedPrototype(Script,
ulan@chromium.org9a21ec42012-03-06 08:42:24 +0000582 $Array("source", "name", "line_ends", "line_offset", "column_offset",
583 "cachedNameOrSourceURL", "hasCachedNameOrSourceURL" ),
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000584 $Array(
585 "lineFromPosition", ScriptLineFromPosition,
586 "locationFromPosition", ScriptLocationFromPosition,
587 "locationFromLine", ScriptLocationFromLine,
588 "sourceSlice", ScriptSourceSlice,
589 "sourceLine", ScriptSourceLine,
590 "lineCount", ScriptLineCount,
591 "nameOrSourceURL", ScriptNameOrSourceURL
592 )
593);
594
595
lrn@chromium.org25156de2010-04-06 13:10:27 +0000596/**
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000597 * Class for source location. A source location is a position within some
598 * source with the following properties:
599 * script : script object for the source
600 * line : source line number
601 * column : source column within the line
602 * position : position within the source
603 * start : position of start of source context (inclusive)
604 * end : position of end of source context (not inclusive)
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000605 * Source text for the source context is the character interval
606 * [start, end[. In most cases end will point to a newline character.
607 * It might point just past the final position of the source if the last
608 * source line does not end with a newline character.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000609 * @param {Script} script The Script object for which this is a location
610 * @param {number} position Source position for the location
611 * @param {number} line The line number for the location
612 * @param {number} column The column within the line for the location
613 * @param {number} start Source position for start of source context
614 * @param {number} end Source position for end of source context
615 * @constructor
616 */
617function SourceLocation(script, position, line, column, start, end) {
618 this.script = script;
619 this.position = position;
620 this.line = line;
621 this.column = column;
622 this.start = start;
623 this.end = end;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000624}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000625
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000626var kLineLengthLimit = 78;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000627
628/**
629 * Restrict source location start and end positions to make the source slice
630 * no more that a certain number of characters wide.
631 * @param {number} opt_limit The with limit of the source text with a default
632 * of 78
633 * @param {number} opt_before The number of characters to prefer before the
634 * position with a default value of 10 less that the limit
635 */
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000636function SourceLocationRestrict(opt_limit, opt_before) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000637 // Find the actual limit to use.
638 var limit;
639 var before;
640 if (!IS_UNDEFINED(opt_limit)) {
641 limit = opt_limit;
642 } else {
643 limit = kLineLengthLimit;
644 }
645 if (!IS_UNDEFINED(opt_before)) {
646 before = opt_before;
647 } else {
648 // If no before is specified center for small limits and perfer more source
649 // before the the position that after for longer limits.
650 if (limit <= 20) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000651 before = $floor(limit / 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000652 } else {
653 before = limit - 10;
654 }
655 }
656 if (before >= limit) {
657 before = limit - 1;
658 }
659
660 // If the [start, end[ interval is too big we restrict
661 // it in one or both ends. We make sure to always produce
662 // restricted intervals of maximum allowed size.
663 if (this.end - this.start > limit) {
664 var start_limit = this.position - before;
665 var end_limit = this.position + limit - before;
666 if (this.start < start_limit && end_limit < this.end) {
667 this.start = start_limit;
668 this.end = end_limit;
669 } else if (this.start < start_limit) {
670 this.start = this.end - limit;
671 } else {
672 this.end = this.start + limit;
673 }
674 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000675}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000676
677
678/**
679 * Get the source text for a SourceLocation
680 * @return {String}
681 * Source text for this location.
682 */
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000683function SourceLocationSourceText() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000684 return %_CallFunction(this.script.source,
685 this.start,
686 this.end,
687 StringSubstring);
688}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000689
690
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000691SetUpLockedPrototype(SourceLocation,
692 $Array("script", "position", "line", "column", "start", "end"),
693 $Array(
694 "restrict", SourceLocationRestrict,
695 "sourceText", SourceLocationSourceText
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000696 )
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000697);
698
699
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000700/**
701 * Class for a source slice. A source slice is a part of a script source with
702 * the following properties:
703 * script : script object for the source
704 * from_line : line number for the first line in the slice
705 * to_line : source line number for the last line in the slice
706 * from_position : position of the first character in the slice
707 * to_position : position of the last character in the slice
708 * The to_line and to_position are not included in the slice, that is the lines
709 * in the slice are [from_line, to_line[. Likewise the characters in the slice
710 * are [from_position, to_position[.
711 * @param {Script} script The Script object for the source slice
712 * @param {number} from_line
713 * @param {number} to_line
714 * @param {number} from_position
715 * @param {number} to_position
716 * @constructor
717 */
718function SourceSlice(script, from_line, to_line, from_position, to_position) {
719 this.script = script;
720 this.from_line = from_line;
721 this.to_line = to_line;
722 this.from_position = from_position;
723 this.to_position = to_position;
724}
725
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000726/**
727 * Get the source text for a SourceSlice
728 * @return {String} Source text for this slice. The last line will include
729 * the line terminating characters (if any)
730 */
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000731function SourceSliceSourceText() {
whesse@chromium.org7a392b32011-01-31 11:30:36 +0000732 return %_CallFunction(this.script.source,
733 this.from_position,
734 this.to_position,
735 StringSubstring);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000736}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000737
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000738SetUpLockedPrototype(SourceSlice,
739 $Array("script", "from_line", "to_line", "from_position", "to_position"),
740 $Array("sourceText", SourceSliceSourceText)
741);
742
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000743
744// Returns the offset of the given position within the containing
745// line.
746function GetPositionInLine(message) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000747 var script = %MessageGetScript(message);
748 var start_position = %MessageGetStartPosition(message);
749 var location = script.locationFromPosition(start_position, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000750 if (location == null) return -1;
751 location.restrict();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000752 return start_position - location.start;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000753}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000754
755
756function GetStackTraceLine(recv, fun, pos, isGlobal) {
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +0000757 return new CallSite(recv, fun, pos).toString();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000758}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000759
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000760// ----------------------------------------------------------------------------
761// Error implementation
762
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000763// Defines accessors for a property that is calculated the first time
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000764// the property is read.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000765function DefineOneShotAccessor(obj, name, fun) {
766 // Note that the accessors consistently operate on 'obj', not 'this'.
767 // Since the object may occur in someone else's prototype chain we
768 // can't rely on 'this' being the same as 'obj'.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000769 var hasBeenSet = false;
770 var value;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000771 var getter = function() {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000772 if (hasBeenSet) {
773 return value;
774 }
775 hasBeenSet = true;
776 value = fun(obj);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000777 return value;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000778 };
779 var setter = function(v) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000780 hasBeenSet = true;
781 value = v;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000782 };
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000783 %DefineOrRedefineAccessorProperty(obj, name, getter, setter, DONT_ENUM);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000784}
785
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000786function CallSite(receiver, fun, pos) {
787 this.receiver = receiver;
788 this.fun = fun;
789 this.pos = pos;
790}
791
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000792function CallSiteGetThis() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000793 return this.receiver;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000794}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000795
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000796function CallSiteGetTypeName() {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000797 return GetTypeName(this, false);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000798}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000799
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000800function CallSiteIsToplevel() {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000801 if (this.receiver == null) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000802 return true;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000803 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000804 return IS_GLOBAL(this.receiver);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000805}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000806
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000807function CallSiteIsEval() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000808 var script = %FunctionGetScript(this.fun);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000809 return script && script.compilation_type == COMPILATION_TYPE_EVAL;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000810}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000811
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000812function CallSiteGetEvalOrigin() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000813 var script = %FunctionGetScript(this.fun);
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000814 return FormatEvalOrigin(script);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000815}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000816
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000817function CallSiteGetScriptNameOrSourceURL() {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000818 var script = %FunctionGetScript(this.fun);
819 return script ? script.nameOrSourceURL() : null;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000820}
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000821
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000822function CallSiteGetFunction() {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000823 return this.fun;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000824}
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000825
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000826function CallSiteGetFunctionName() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000827 // See if the function knows its own name
828 var name = this.fun.name;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000829 if (name) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000830 return name;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000831 }
832 name = %FunctionGetInferredName(this.fun);
833 if (name) {
834 return name;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000835 }
836 // Maybe this is an evaluation?
837 var script = %FunctionGetScript(this.fun);
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000838 if (script && script.compilation_type == COMPILATION_TYPE_EVAL) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000839 return "eval";
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000840 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000841 return null;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000842}
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000843
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000844function CallSiteGetMethodName() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000845 // See if we can find a unique property on the receiver that holds
846 // this function.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000847 var ownName = this.fun.name;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000848 if (ownName && this.receiver &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000849 (%_CallFunction(this.receiver,
850 ownName,
851 ObjectLookupGetter) === this.fun ||
852 %_CallFunction(this.receiver,
853 ownName,
854 ObjectLookupSetter) === this.fun ||
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000855 this.receiver[ownName] === this.fun)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000856 // To handle DontEnum properties we guess that the method has
857 // the same name as the function.
858 return ownName;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000859 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000860 var name = null;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000861 for (var prop in this.receiver) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000862 if (%_CallFunction(this.receiver, prop, ObjectLookupGetter) === this.fun ||
863 %_CallFunction(this.receiver, prop, ObjectLookupSetter) === this.fun ||
864 (!%_CallFunction(this.receiver, prop, ObjectLookupGetter) &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000865 this.receiver[prop] === this.fun)) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000866 // If we find more than one match bail out to avoid confusion.
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000867 if (name) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000868 return null;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000869 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000870 name = prop;
871 }
872 }
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000873 if (name) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000874 return name;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000875 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000876 return null;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000877}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000878
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000879function CallSiteGetFileName() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000880 var script = %FunctionGetScript(this.fun);
881 return script ? script.name : null;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000882}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000883
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000884function CallSiteGetLineNumber() {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000885 if (this.pos == -1) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000886 return null;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000887 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000888 var script = %FunctionGetScript(this.fun);
889 var location = null;
890 if (script) {
891 location = script.locationFromPosition(this.pos, true);
892 }
893 return location ? location.line + 1 : null;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000894}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000895
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000896function CallSiteGetColumnNumber() {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000897 if (this.pos == -1) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000898 return null;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000899 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000900 var script = %FunctionGetScript(this.fun);
901 var location = null;
902 if (script) {
903 location = script.locationFromPosition(this.pos, true);
904 }
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000905 return location ? location.column + 1: null;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000906}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000907
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000908function CallSiteIsNative() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000909 var script = %FunctionGetScript(this.fun);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000910 return script ? (script.type == TYPE_NATIVE) : false;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000911}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000912
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000913function CallSiteGetPosition() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000914 return this.pos;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000915}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000916
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000917function CallSiteIsConstructor() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000918 var constructor = this.receiver ? this.receiver.constructor : null;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000919 if (!constructor) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000920 return false;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000921 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000922 return this.fun === constructor;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000923}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000924
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +0000925function CallSiteToString() {
926 var fileName;
927 var fileLocation = "";
928 if (this.isNative()) {
929 fileLocation = "native";
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +0000930 } else {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000931 if (this.isEval()) {
932 fileName = this.getScriptNameOrSourceURL();
933 if (!fileName) {
934 fileLocation = this.getEvalOrigin();
935 fileLocation += ", "; // Expecting source position to follow.
936 }
937 } else {
938 fileName = this.getFileName();
939 }
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +0000940
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000941 if (fileName) {
942 fileLocation += fileName;
943 } else {
944 // Source code does not originate from a file and is not native, but we
945 // can still get the source position inside the source string, e.g. in
946 // an eval string.
947 fileLocation += "<anonymous>";
948 }
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +0000949 var lineNumber = this.getLineNumber();
950 if (lineNumber != null) {
951 fileLocation += ":" + lineNumber;
952 var columnNumber = this.getColumnNumber();
953 if (columnNumber) {
954 fileLocation += ":" + columnNumber;
955 }
956 }
957 }
958
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +0000959 var line = "";
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000960 var functionName = this.getFunctionName();
961 var addSuffix = true;
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +0000962 var isConstructor = this.isConstructor();
963 var isMethodCall = !(this.isToplevel() || isConstructor);
964 if (isMethodCall) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000965 var typeName = GetTypeName(this, true);
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +0000966 var methodName = this.getMethodName();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +0000967 if (functionName) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000968 if (typeName && functionName.indexOf(typeName) != 0) {
969 line += typeName + ".";
970 }
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +0000971 line += functionName;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000972 if (methodName && functionName.lastIndexOf("." + methodName) !=
973 functionName.length - methodName.length - 1) {
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +0000974 line += " [as " + methodName + "]";
975 }
976 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000977 line += typeName + "." + (methodName || "<anonymous>");
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +0000978 }
979 } else if (isConstructor) {
980 line += "new " + (functionName || "<anonymous>");
981 } else if (functionName) {
982 line += functionName;
983 } else {
984 line += fileLocation;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000985 addSuffix = false;
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +0000986 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000987 if (addSuffix) {
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +0000988 line += " (" + fileLocation + ")";
989 }
990 return line;
991}
992
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000993SetUpLockedPrototype(CallSite, $Array("receiver", "fun", "pos"), $Array(
994 "getThis", CallSiteGetThis,
995 "getTypeName", CallSiteGetTypeName,
996 "isToplevel", CallSiteIsToplevel,
997 "isEval", CallSiteIsEval,
998 "getEvalOrigin", CallSiteGetEvalOrigin,
999 "getScriptNameOrSourceURL", CallSiteGetScriptNameOrSourceURL,
1000 "getFunction", CallSiteGetFunction,
1001 "getFunctionName", CallSiteGetFunctionName,
1002 "getMethodName", CallSiteGetMethodName,
1003 "getFileName", CallSiteGetFileName,
1004 "getLineNumber", CallSiteGetLineNumber,
1005 "getColumnNumber", CallSiteGetColumnNumber,
1006 "isNative", CallSiteIsNative,
1007 "getPosition", CallSiteGetPosition,
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001008 "isConstructor", CallSiteIsConstructor,
1009 "toString", CallSiteToString
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001010));
1011
1012
sgjesse@chromium.org98180592009-12-02 08:17:28 +00001013function FormatEvalOrigin(script) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001014 var sourceURL = script.nameOrSourceURL();
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001015 if (sourceURL) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001016 return sourceURL;
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001017 }
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001018
1019 var eval_origin = "eval at ";
sgjesse@chromium.org98180592009-12-02 08:17:28 +00001020 if (script.eval_from_function_name) {
1021 eval_origin += script.eval_from_function_name;
1022 } else {
1023 eval_origin += "<anonymous>";
1024 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00001025
sgjesse@chromium.org98180592009-12-02 08:17:28 +00001026 var eval_from_script = script.eval_from_script;
1027 if (eval_from_script) {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001028 if (eval_from_script.compilation_type == COMPILATION_TYPE_EVAL) {
sgjesse@chromium.org98180592009-12-02 08:17:28 +00001029 // eval script originated from another eval.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001030 eval_origin += " (" + FormatEvalOrigin(eval_from_script) + ")";
sgjesse@chromium.org98180592009-12-02 08:17:28 +00001031 } else {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001032 // eval script originated from "real" source.
sgjesse@chromium.org98180592009-12-02 08:17:28 +00001033 if (eval_from_script.name) {
1034 eval_origin += " (" + eval_from_script.name;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001035 var location = eval_from_script.locationFromPosition(
1036 script.eval_from_script_position, true);
sgjesse@chromium.org98180592009-12-02 08:17:28 +00001037 if (location) {
1038 eval_origin += ":" + (location.line + 1);
1039 eval_origin += ":" + (location.column + 1);
1040 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001041 eval_origin += ")";
sgjesse@chromium.org98180592009-12-02 08:17:28 +00001042 } else {
1043 eval_origin += " (unknown source)";
1044 }
1045 }
1046 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00001047
sgjesse@chromium.org98180592009-12-02 08:17:28 +00001048 return eval_origin;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001049}
sgjesse@chromium.org98180592009-12-02 08:17:28 +00001050
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001051function FormatStackTrace(error, frames) {
1052 var lines = [];
1053 try {
1054 lines.push(error.toString());
1055 } catch (e) {
1056 try {
1057 lines.push("<error: " + e + ">");
1058 } catch (ee) {
1059 lines.push("<error>");
1060 }
1061 }
1062 for (var i = 0; i < frames.length; i++) {
1063 var frame = frames[i];
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001064 var line;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001065 try {
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001066 line = frame.toString();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001067 } catch (e) {
1068 try {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001069 line = "<error: " + e + ">";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001070 } catch (ee) {
1071 // Any code that reaches this point is seriously nasty!
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001072 line = "<error>";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001073 }
1074 }
1075 lines.push(" at " + line);
1076 }
1077 return lines.join("\n");
1078}
1079
1080function FormatRawStackTrace(error, raw_stack) {
1081 var frames = [ ];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001082 for (var i = 0; i < raw_stack.length; i += 4) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001083 var recv = raw_stack[i];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001084 var fun = raw_stack[i + 1];
1085 var code = raw_stack[i + 2];
1086 var pc = raw_stack[i + 3];
1087 var pos = %FunctionGetPositionForOffset(code, pc);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001088 frames.push(new CallSite(recv, fun, pos));
1089 }
1090 if (IS_FUNCTION($Error.prepareStackTrace)) {
1091 return $Error.prepareStackTrace(error, frames);
1092 } else {
1093 return FormatStackTrace(error, frames);
1094 }
1095}
1096
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001097function GetTypeName(obj, requireConstructor) {
1098 var constructor = obj.receiver.constructor;
1099 if (!constructor) {
1100 return requireConstructor ? null :
1101 %_CallFunction(obj.receiver, ObjectToString);
1102 }
1103 var constructorName = constructor.name;
1104 if (!constructorName) {
1105 return requireConstructor ? null :
1106 %_CallFunction(obj.receiver, ObjectToString);
1107 }
1108 return constructorName;
1109}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001110
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001111function captureStackTrace(obj, cons_opt) {
1112 var stackTraceLimit = $Error.stackTraceLimit;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001113 if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return;
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001114 if (stackTraceLimit < 0 || stackTraceLimit > 10000) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001115 stackTraceLimit = 10000;
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001116 }
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00001117 var raw_stack = %CollectStackTrace(obj,
1118 cons_opt ? cons_opt : captureStackTrace,
1119 stackTraceLimit);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001120 DefineOneShotAccessor(obj, 'stack', function (obj) {
1121 return FormatRawStackTrace(obj, raw_stack);
1122 });
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001123}
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001124
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001125
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001126function SetUpError() {
1127 // Define special error type constructors.
1128
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001129 var DefineError = function(f) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001130 // Store the error function in both the global object
1131 // and the runtime object. The function is fetched
1132 // from the runtime object when throwing errors from
1133 // within the runtime system to avoid strange side
1134 // effects when overwriting the error functions from
1135 // user code.
1136 var name = f.name;
1137 %SetProperty(global, name, f, DONT_ENUM);
1138 %SetProperty(builtins, '$' + name, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
1139 // Configure the error function.
1140 if (name == 'Error') {
1141 // The prototype of the Error object must itself be an error.
1142 // However, it can't be an instance of the Error object because
1143 // it hasn't been properly configured yet. Instead we create a
1144 // special not-a-true-error-but-close-enough object.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001145 var ErrorPrototype = function() {};
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001146 %FunctionSetPrototype(ErrorPrototype, $Object.prototype);
1147 %FunctionSetInstanceClassName(ErrorPrototype, 'Error');
1148 %FunctionSetPrototype(f, new ErrorPrototype());
1149 } else {
1150 %FunctionSetPrototype(f, new $Error());
1151 }
1152 %FunctionSetInstanceClassName(f, 'Error');
1153 %SetProperty(f.prototype, 'constructor', f, DONT_ENUM);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001154 %SetProperty(f.prototype, "name", name, DONT_ENUM);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001155 %SetCode(f, function(m) {
1156 if (%_IsConstructCall()) {
1157 // Define all the expected properties directly on the error
1158 // object. This avoids going through getters and setters defined
1159 // on prototype objects.
1160 %IgnoreAttributesAndSetProperty(this, 'stack', void 0, DONT_ENUM);
1161 %IgnoreAttributesAndSetProperty(this, 'arguments', void 0, DONT_ENUM);
1162 %IgnoreAttributesAndSetProperty(this, 'type', void 0, DONT_ENUM);
1163 if (m === kAddMessageAccessorsMarker) {
1164 // DefineOneShotAccessor always inserts a message property and
1165 // ignores setters.
1166 DefineOneShotAccessor(this, 'message', function (obj) {
1167 return FormatMessage(%NewMessageObject(obj.type, obj.arguments));
1168 });
1169 } else if (!IS_UNDEFINED(m)) {
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001170 %IgnoreAttributesAndSetProperty(
1171 this, 'message', ToString(m), DONT_ENUM);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001172 }
1173 captureStackTrace(this, f);
1174 } else {
1175 return new f(m);
1176 }
1177 });
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001178 %SetNativeFlag(f);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001179 };
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001180
1181 DefineError(function Error() { });
1182 DefineError(function TypeError() { });
1183 DefineError(function RangeError() { });
1184 DefineError(function SyntaxError() { });
1185 DefineError(function ReferenceError() { });
1186 DefineError(function EvalError() { });
1187 DefineError(function URIError() { });
1188}
1189
1190SetUpError();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001191
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001192$Error.captureStackTrace = captureStackTrace;
1193
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001194%SetProperty($Error.prototype, 'message', '', DONT_ENUM);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001195
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001196// Global list of error objects visited during ErrorToString. This is
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001197// used to detect cycles in error toString formatting.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001198var visited_errors = new InternalArray();
1199var cyclic_error_marker = new $Object();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001200
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001201function GetPropertyWithoutInvokingMonkeyGetters(error, name) {
1202 // Climb the prototype chain until we find the holder.
1203 while (error && !%HasLocalProperty(error, name)) {
1204 error = error.__proto__;
1205 }
1206 if (error === null) return void 0;
1207 if (!IS_OBJECT(error)) return error[name];
1208 // If the property is an accessor on one of the predefined errors that can be
1209 // generated statically by the compiler, don't touch it. This is to address
1210 // http://code.google.com/p/chromium/issues/detail?id=69187
1211 var desc = %GetOwnProperty(error, name);
1212 if (desc && desc[IS_ACCESSOR_INDEX]) {
1213 var isName = name === "name";
1214 if (error === $ReferenceError.prototype)
1215 return isName ? "ReferenceError" : void 0;
1216 if (error === $SyntaxError.prototype)
1217 return isName ? "SyntaxError" : void 0;
1218 if (error === $TypeError.prototype)
1219 return isName ? "TypeError" : void 0;
1220 }
1221 // Otherwise, read normally.
1222 return error[name];
1223}
1224
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001225function ErrorToStringDetectCycle(error) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001226 if (!%PushIfAbsent(visited_errors, error)) throw cyclic_error_marker;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001227 try {
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001228 var type = GetPropertyWithoutInvokingMonkeyGetters(error, "type");
1229 var name = GetPropertyWithoutInvokingMonkeyGetters(error, "name");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001230 name = IS_UNDEFINED(name) ? "Error" : TO_STRING_INLINE(name);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001231 var message = GetPropertyWithoutInvokingMonkeyGetters(error, "message");
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001232 var hasMessage = %_CallFunction(error, "message", ObjectHasOwnProperty);
1233 if (type && !hasMessage) {
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001234 var args = GetPropertyWithoutInvokingMonkeyGetters(error, "arguments");
1235 message = FormatMessage(%NewMessageObject(type, args));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001236 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001237 message = IS_UNDEFINED(message) ? "" : TO_STRING_INLINE(message);
1238 if (name === "") return message;
1239 if (message === "") return name;
1240 return name + ": " + message;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001241 } finally {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001242 visited_errors.length = visited_errors.length - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001243 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001244}
1245
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001246function ErrorToString() {
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001247 if (!IS_SPEC_OBJECT(this)) {
1248 throw MakeTypeError("called_on_non_object", ["Error.prototype.toString"]);
lrn@chromium.org1c092762011-05-09 09:42:16 +00001249 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001250
1251 try {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001252 return ErrorToStringDetectCycle(this);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001253 } catch(e) {
1254 // If this error message was encountered already return the empty
1255 // string for it instead of recursively formatting it.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001256 if (e === cyclic_error_marker) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001257 return '';
1258 }
1259 throw e;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001260 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001261}
1262
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001263
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001264InstallFunctions($Error.prototype, DONT_ENUM, ['toString', ErrorToString]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001265
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001266// Boilerplate for exceptions for stack overflows. Used from
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001267// Isolate::StackOverflow().
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001268var kStackOverflowBoilerplate = MakeRangeError('stack_overflow', []);