blob: 6603185a3207bf330bf4c1a34d04de782bdbc5cd [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 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
28
29// -------------------------------------------------------------------
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000030//
31// Matches Script::Type from objects.h
32var TYPE_NATIVE = 0;
33var TYPE_EXTENSION = 1;
34var TYPE_NORMAL = 2;
35
36// Matches Script::CompilationType from objects.h
37var COMPILATION_TYPE_HOST = 0;
38var COMPILATION_TYPE_EVAL = 1;
39var COMPILATION_TYPE_JSON = 2;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000041// Matches Messages::kNoLineNumberInfo from v8.h
42var kNoLineNumberInfo = 0;
43
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000044// If this object gets passed to an error constructor the error will
45// get an accessor for .message that constructs a descriptive error
46// message on access.
47var kAddMessageAccessorsMarker = { };
48
ager@chromium.orgadd848f2009-08-13 12:44:13 +000049var kMessages = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000050
ricow@chromium.org83aa5492011-02-07 12:42:56 +000051var kReplacementMarkers = [ "%0", "%1", "%2", "%3" ];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000053function FormatString(format, message) {
54 var args = %MessageGetArguments(message);
55 var result = "";
56 var arg_num = 0;
57 for (var i = 0; i < format.length; i++) {
58 var str = format[i];
59 for (arg_num = 0; arg_num < kReplacementMarkers.length; arg_num++) {
60 if (format[i] !== kReplacementMarkers[arg_num]) continue;
61 try {
62 str = ToDetailString(args[arg_num]);
63 } catch (e) {
64 str = "#<error>";
65 }
ager@chromium.org378b34e2011-01-28 08:04:38 +000066 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000067 result += str;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068 }
69 return result;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000070}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000071
72
ager@chromium.org0ee099b2011-01-25 14:06:47 +000073// To check if something is a native error we need to check the
74// concrete native error types. It is not enough to check "obj
75// instanceof $Error" because user code can replace
76// NativeError.prototype.__proto__. User code cannot replace
77// NativeError.prototype though and therefore this is a safe test.
78function IsNativeErrorObject(obj) {
79 return (obj instanceof $Error) ||
80 (obj instanceof $EvalError) ||
81 (obj instanceof $RangeError) ||
82 (obj instanceof $ReferenceError) ||
83 (obj instanceof $SyntaxError) ||
84 (obj instanceof $TypeError) ||
85 (obj instanceof $URIError);
86}
87
88
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000089// When formatting internally created error messages, do not
90// invoke overwritten error toString methods but explicitly use
91// the error to string method. This is to avoid leaking error
92// objects between script tags in a browser setting.
93function ToStringCheckErrorObject(obj) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +000094 if (IsNativeErrorObject(obj)) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000095 return %_CallFunction(obj, errorToString);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096 } else {
97 return ToString(obj);
98 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000099}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100
101
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000102function ToDetailString(obj) {
103 if (obj != null && IS_OBJECT(obj) && obj.toString === $Object.prototype.toString) {
104 var constructor = obj.constructor;
105 if (!constructor) return ToStringCheckErrorObject(obj);
106 var constructorName = constructor.name;
ager@chromium.org378b34e2011-01-28 08:04:38 +0000107 if (!constructorName || !IS_STRING(constructorName)) {
108 return ToStringCheckErrorObject(obj);
109 }
whesse@chromium.org7a392b32011-01-31 11:30:36 +0000110 return "#<" + constructorName + ">";
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000111 } else {
112 return ToStringCheckErrorObject(obj);
113 }
114}
115
116
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000117function MakeGenericError(constructor, type, args) {
ager@chromium.org3e875802009-06-29 08:26:34 +0000118 if (IS_UNDEFINED(args)) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000119 args = [];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000120 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000121 var e = new constructor(kAddMessageAccessorsMarker);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000122 e.type = type;
123 e.arguments = args;
124 return e;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000125}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000126
127
128/**
129 * Setup the Script function and constructor.
130 */
131%FunctionSetInstanceClassName(Script, 'Script');
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000132%SetProperty(Script.prototype, 'constructor', Script, DONT_ENUM);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000133%SetCode(Script, function(x) {
134 // Script objects can only be created by the VM.
135 throw new $Error("Not supported");
136});
137
138
139// Helper functions; called from the runtime system.
140function FormatMessage(message) {
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000141 if (kMessages === 0) {
142 kMessages = {
143 // Error
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000144 cyclic_proto: ["Cyclic __proto__ value"],
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +0000145 code_gen_from_strings: ["Code generation from strings disallowed for this context"],
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000146 // TypeError
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000147 unexpected_token: ["Unexpected token ", "%0"],
148 unexpected_token_number: ["Unexpected number"],
149 unexpected_token_string: ["Unexpected string"],
150 unexpected_token_identifier: ["Unexpected identifier"],
ager@chromium.org04921a82011-06-27 13:21:41 +0000151 unexpected_reserved: ["Unexpected reserved word"],
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000152 unexpected_strict_reserved: ["Unexpected strict mode reserved word"],
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000153 unexpected_eos: ["Unexpected end of input"],
154 malformed_regexp: ["Invalid regular expression: /", "%0", "/: ", "%1"],
155 unterminated_regexp: ["Invalid regular expression: missing /"],
156 regexp_flags: ["Cannot supply flags when constructing one RegExp from another"],
157 incompatible_method_receiver: ["Method ", "%0", " called on incompatible receiver ", "%1"],
158 invalid_lhs_in_assignment: ["Invalid left-hand side in assignment"],
159 invalid_lhs_in_for_in: ["Invalid left-hand side in for-in"],
160 invalid_lhs_in_postfix_op: ["Invalid left-hand side expression in postfix operation"],
161 invalid_lhs_in_prefix_op: ["Invalid left-hand side expression in prefix operation"],
162 multiple_defaults_in_switch: ["More than one default clause in switch statement"],
163 newline_after_throw: ["Illegal newline after throw"],
164 redeclaration: ["%0", " '", "%1", "' has already been declared"],
165 no_catch_or_finally: ["Missing catch or finally after try"],
166 unknown_label: ["Undefined label '", "%0", "'"],
167 uncaught_exception: ["Uncaught ", "%0"],
168 stack_trace: ["Stack Trace:\n", "%0"],
169 called_non_callable: ["%0", " is not a function"],
170 undefined_method: ["Object ", "%1", " has no method '", "%0", "'"],
171 property_not_function: ["Property '", "%0", "' of object ", "%1", " is not a function"],
172 cannot_convert_to_primitive: ["Cannot convert object to primitive value"],
173 not_constructor: ["%0", " is not a constructor"],
174 not_defined: ["%0", " is not defined"],
175 non_object_property_load: ["Cannot read property '", "%0", "' of ", "%1"],
176 non_object_property_store: ["Cannot set property '", "%0", "' of ", "%1"],
177 non_object_property_call: ["Cannot call method '", "%0", "' of ", "%1"],
178 with_expression: ["%0", " has no properties"],
179 illegal_invocation: ["Illegal invocation"],
180 no_setter_in_callback: ["Cannot set property ", "%0", " of ", "%1", " which has only a getter"],
181 apply_non_function: ["Function.prototype.apply was called on ", "%0", ", which is a ", "%1", " and not a function"],
182 apply_wrong_args: ["Function.prototype.apply: Arguments list has wrong type"],
183 invalid_in_operator_use: ["Cannot use 'in' operator to search for '", "%0", "' in ", "%1"],
184 instanceof_function_expected: ["Expecting a function in instanceof check, but got ", "%0"],
185 instanceof_nonobject_proto: ["Function has non-object prototype '", "%0", "' in instanceof check"],
186 null_to_object: ["Cannot convert null to object"],
187 reduce_no_initial: ["Reduce of empty array with no initial value"],
188 getter_must_be_callable: ["Getter must be a function: ", "%0"],
189 setter_must_be_callable: ["Setter must be a function: ", "%0"],
190 value_and_accessor: ["Invalid property. A property cannot both have accessors and be writable or have a value: ", "%0"],
191 proto_object_or_null: ["Object prototype may only be an Object or null"],
192 property_desc_object: ["Property description must be an object: ", "%0"],
193 redefine_disallowed: ["Cannot redefine property: ", "%0"],
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000194 define_disallowed: ["Cannot define property:", "%0", ", object is not extensible."],
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000195 non_extensible_proto: ["%0", " is not extensible"],
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000196 handler_non_object: ["Proxy.", "%0", " called with non-object as handler"],
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000197 handler_trap_missing: ["Proxy handler ", "%0", " has no '", "%1", "' trap"],
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000198 handler_trap_must_be_callable: ["Proxy handler ", "%0", " has non-callable '", "%1", "' trap"],
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000199 handler_returned_false: ["Proxy handler ", "%0", " returned false for '", "%1", "' trap"],
200 handler_returned_undefined: ["Proxy handler ", "%0", " returned undefined for '", "%1", "' trap"],
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000201 proxy_prop_not_configurable: ["Trap ", "%1", " of proxy handler ", "%0", " returned non-configurable descriptor for property ", "%2"],
202 proxy_non_object_prop_names: ["Trap ", "%1", " returned non-object ", "%0"],
203 proxy_repeated_prop_name: ["Trap ", "%1", " returned repeated property name ", "%2"],
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000204 invalid_weakmap_key: ["Invalid value used as weak map key"],
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000205 // RangeError
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000206 invalid_array_length: ["Invalid array length"],
207 stack_overflow: ["Maximum call stack size exceeded"],
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000208 // SyntaxError
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000209 unable_to_parse: ["Parse error"],
210 duplicate_regexp_flag: ["Duplicate RegExp flag ", "%0"],
211 invalid_regexp: ["Invalid RegExp pattern /", "%0", "/"],
212 illegal_break: ["Illegal break statement"],
213 illegal_continue: ["Illegal continue statement"],
214 illegal_return: ["Illegal return statement"],
215 error_loading_debugger: ["Error loading debugger"],
216 no_input_to_regexp: ["No input to ", "%0"],
217 invalid_json: ["String '", "%0", "' is not valid JSON"],
218 circular_structure: ["Converting circular structure to JSON"],
219 obj_ctor_property_non_object: ["Object.", "%0", " called on non-object"],
lrn@chromium.org1c092762011-05-09 09:42:16 +0000220 called_on_null_or_undefined: ["%0", " called on null or undefined"],
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000221 array_indexof_not_defined: ["Array.getIndexOf: Argument undefined"],
222 object_not_extensible: ["Can't add property ", "%0", ", object is not extensible"],
223 illegal_access: ["Illegal access"],
224 invalid_preparser_data: ["Invalid preparser data for function ", "%0"],
225 strict_mode_with: ["Strict mode code may not include a with statement"],
226 strict_catch_variable: ["Catch variable may not be eval or arguments in strict mode"],
jkummerow@chromium.orge297f592011-06-08 10:05:15 +0000227 too_many_arguments: ["Too many arguments in function call (only 32766 allowed)"],
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000228 too_many_parameters: ["Too many parameters in function definition (only 32766 allowed)"],
229 too_many_variables: ["Too many variables declared (only 32767 allowed)"],
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000230 strict_param_name: ["Parameter name eval or arguments is not allowed in strict mode"],
231 strict_param_dupe: ["Strict mode function may not have duplicate parameter names"],
232 strict_var_name: ["Variable name may not be eval or arguments in strict mode"],
233 strict_function_name: ["Function name may not be eval or arguments in strict mode"],
234 strict_octal_literal: ["Octal literals are not allowed in strict mode."],
235 strict_duplicate_property: ["Duplicate data property in object literal not allowed in strict mode"],
236 accessor_data_property: ["Object literal may not have data and accessor property with the same name"],
237 accessor_get_set: ["Object literal may not have multiple get/set accessors with the same name"],
238 strict_lhs_assignment: ["Assignment to eval or arguments is not allowed in strict mode"],
239 strict_lhs_postfix: ["Postfix increment/decrement may not have eval or arguments operand in strict mode"],
240 strict_lhs_prefix: ["Prefix increment/decrement may not have eval or arguments operand in strict mode"],
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000241 strict_reserved_word: ["Use of future reserved word in strict mode"],
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000242 strict_delete: ["Delete of an unqualified identifier in strict mode."],
243 strict_delete_property: ["Cannot delete property '", "%0", "' of ", "%1"],
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000244 strict_const: ["Use of const in strict mode."],
245 strict_function: ["In strict mode code, functions can only be declared at top level or immediately within another function." ],
246 strict_read_only_property: ["Cannot assign to read only property '", "%0", "' of ", "%1"],
247 strict_cannot_assign: ["Cannot assign to read only '", "%0", "' in strict mode"],
danno@chromium.org40cb8782011-05-25 07:58:50 +0000248 strict_poison_pill: ["'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them"],
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000249 strict_caller: ["Illegal access to a strict mode caller function."],
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000250 };
251 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000252 var message_type = %MessageGetType(message);
253 var format = kMessages[message_type];
254 if (!format) return "<unknown message " + message_type + ">";
255 return FormatString(format, message);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000256}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000257
258
259function GetLineNumber(message) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000260 var start_position = %MessageGetStartPosition(message);
261 if (start_position == -1) return kNoLineNumberInfo;
262 var script = %MessageGetScript(message);
263 var location = script.locationFromPosition(start_position, true);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000264 if (location == null) return kNoLineNumberInfo;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000265 return location.line + 1;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000266}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000267
268
269// Returns the source code line containing the given source
270// position, or the empty string if the position is invalid.
271function GetSourceLine(message) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000272 var script = %MessageGetScript(message);
273 var start_position = %MessageGetStartPosition(message);
274 var location = script.locationFromPosition(start_position, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000275 if (location == null) return "";
276 location.restrict();
277 return location.sourceText();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000278}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000279
280
281function MakeTypeError(type, args) {
282 return MakeGenericError($TypeError, type, args);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000283}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000284
285
286function MakeRangeError(type, args) {
287 return MakeGenericError($RangeError, type, args);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000288}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000289
290
291function MakeSyntaxError(type, args) {
292 return MakeGenericError($SyntaxError, type, args);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000293}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000294
295
296function MakeReferenceError(type, args) {
297 return MakeGenericError($ReferenceError, type, args);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000298}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000299
300
301function MakeEvalError(type, args) {
302 return MakeGenericError($EvalError, type, args);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000303}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000304
305
306function MakeError(type, args) {
307 return MakeGenericError($Error, type, args);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000308}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000309
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000310/**
311 * Find a line number given a specific source position.
312 * @param {number} position The source position.
313 * @return {number} 0 if input too small, -1 if input too large,
314 else the line number.
315 */
316Script.prototype.lineFromPosition = function(position) {
317 var lower = 0;
318 var upper = this.lineCount() - 1;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000319 var line_ends = this.line_ends;
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000320
321 // We'll never find invalid positions so bail right away.
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000322 if (position > line_ends[upper]) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000323 return -1;
324 }
325
326 // This means we don't have to safe-guard indexing line_ends[i - 1].
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000327 if (position <= line_ends[0]) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000328 return 0;
329 }
330
331 // Binary search to find line # from position range.
332 while (upper >= 1) {
333 var i = (lower + upper) >> 1;
334
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000335 if (position > line_ends[i]) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000336 lower = i + 1;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000337 } else if (position <= line_ends[i - 1]) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000338 upper = i - 1;
339 } else {
340 return i;
341 }
342 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000343
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000344 return -1;
345}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000346
347/**
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000348 * Get information on a specific source position.
349 * @param {number} position The source position
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000350 * @param {boolean} include_resource_offset Set to true to have the resource
351 * offset added to the location
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000352 * @return {SourceLocation}
353 * If line is negative or not in the source null is returned.
354 */
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000355Script.prototype.locationFromPosition = function (position,
356 include_resource_offset) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000357 var line = this.lineFromPosition(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000358 if (line == -1) return null;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000359
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000360 // Determine start, end and column.
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000361 var line_ends = this.line_ends;
362 var start = line == 0 ? 0 : line_ends[line - 1] + 1;
363 var end = line_ends[line];
whesse@chromium.org7a392b32011-01-31 11:30:36 +0000364 if (end > 0 && %_CallFunction(this.source, end - 1, StringCharAt) == '\r') end--;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000365 var column = position - start;
366
367 // Adjust according to the offset within the resource.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000368 if (include_resource_offset) {
369 line += this.line_offset;
370 if (line == this.line_offset) {
371 column += this.column_offset;
372 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000373 }
374
375 return new SourceLocation(this, position, line, column, start, end);
376};
377
378
379/**
380 * Get information on a specific source line and column possibly offset by a
381 * fixed source position. This function is used to find a source position from
382 * a line and column position. The fixed source position offset is typically
383 * used to find a source position in a function based on a line and column in
384 * the source for the function alone. The offset passed will then be the
385 * start position of the source for the function within the full script source.
386 * @param {number} opt_line The line within the source. Default value is 0
387 * @param {number} opt_column The column in within the line. Default value is 0
388 * @param {number} opt_offset_position The offset from the begining of the
389 * source from where the line and column calculation starts. Default value is 0
390 * @return {SourceLocation}
391 * If line is negative or not in the source null is returned.
392 */
393Script.prototype.locationFromLine = function (opt_line, opt_column, opt_offset_position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000394 // Default is the first line in the script. Lines in the script is relative
395 // to the offset within the resource.
396 var line = 0;
397 if (!IS_UNDEFINED(opt_line)) {
398 line = opt_line - this.line_offset;
399 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000400
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000401 // Default is first column. If on the first line add the offset within the
402 // resource.
403 var column = opt_column || 0;
404 if (line == 0) {
405 column -= this.column_offset
406 }
407
408 var offset_position = opt_offset_position || 0;
409 if (line < 0 || column < 0 || offset_position < 0) return null;
410 if (line == 0) {
ager@chromium.org3a6061e2009-03-12 14:24:36 +0000411 return this.locationFromPosition(offset_position + column, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000412 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000413 // Find the line where the offset position is located.
414 var offset_line = this.lineFromPosition(offset_position);
415
416 if (offset_line == -1 || offset_line + line >= this.lineCount()) {
417 return null;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000418 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000419
iposva@chromium.org245aa852009-02-10 00:49:54 +0000420 return this.locationFromPosition(this.line_ends[offset_line + line - 1] + 1 + column); // line > 0 here.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000421 }
422}
423
424
425/**
426 * Get a slice of source code from the script. The boundaries for the slice is
427 * specified in lines.
428 * @param {number} opt_from_line The first line (zero bound) in the slice.
429 * Default is 0
430 * @param {number} opt_to_column The last line (zero bound) in the slice (non
431 * inclusive). Default is the number of lines in the script
432 * @return {SourceSlice} The source slice or null of the parameters where
433 * invalid
434 */
435Script.prototype.sourceSlice = function (opt_from_line, opt_to_line) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000436 var from_line = IS_UNDEFINED(opt_from_line) ? this.line_offset : opt_from_line;
437 var to_line = IS_UNDEFINED(opt_to_line) ? this.line_offset + this.lineCount() : opt_to_line
438
439 // Adjust according to the offset within the resource.
440 from_line -= this.line_offset;
441 to_line -= this.line_offset;
442 if (from_line < 0) from_line = 0;
443 if (to_line > this.lineCount()) to_line = this.lineCount();
444
iposva@chromium.org245aa852009-02-10 00:49:54 +0000445 // Check parameters.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000446 if (from_line >= this.lineCount() ||
447 to_line < 0 ||
448 from_line > to_line) {
449 return null;
450 }
451
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000452 var line_ends = this.line_ends;
453 var from_position = from_line == 0 ? 0 : line_ends[from_line - 1] + 1;
454 var to_position = to_line == 0 ? 0 : line_ends[to_line - 1] + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000455
456 // Return a source slice with line numbers re-adjusted to the resource.
457 return new SourceSlice(this, from_line + this.line_offset, to_line + this.line_offset,
458 from_position, to_position);
459}
460
461
462Script.prototype.sourceLine = function (opt_line) {
463 // Default is the first line in the script. Lines in the script are relative
464 // to the offset within the resource.
465 var line = 0;
466 if (!IS_UNDEFINED(opt_line)) {
467 line = opt_line - this.line_offset;
468 }
iposva@chromium.org245aa852009-02-10 00:49:54 +0000469
470 // Check parameter.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000471 if (line < 0 || this.lineCount() <= line) {
472 return null;
473 }
474
iposva@chromium.org245aa852009-02-10 00:49:54 +0000475 // Return the source line.
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000476 var line_ends = this.line_ends;
477 var start = line == 0 ? 0 : line_ends[line - 1] + 1;
478 var end = line_ends[line];
whesse@chromium.org7a392b32011-01-31 11:30:36 +0000479 return %_CallFunction(this.source, start, end, StringSubstring);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000480}
481
482
483/**
484 * Returns the number of source lines.
485 * @return {number}
486 * Number of source lines.
487 */
488Script.prototype.lineCount = function() {
iposva@chromium.org245aa852009-02-10 00:49:54 +0000489 // Return number of source lines.
490 return this.line_ends.length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000491};
492
493
494/**
lrn@chromium.org25156de2010-04-06 13:10:27 +0000495 * Returns the name of script if available, contents of sourceURL comment
vegorov@chromium.org42841962010-10-18 11:18:59 +0000496 * otherwise. See
lrn@chromium.org25156de2010-04-06 13:10:27 +0000497 * http://fbug.googlecode.com/svn/branches/firebug1.1/docs/ReleaseNotes_1.1.txt
498 * for details on using //@ sourceURL comment to identify scritps that don't
499 * have name.
vegorov@chromium.org42841962010-10-18 11:18:59 +0000500 *
lrn@chromium.org25156de2010-04-06 13:10:27 +0000501 * @return {?string} script name if present, value for //@ sourceURL comment
502 * otherwise.
503 */
504Script.prototype.nameOrSourceURL = function() {
505 if (this.name)
506 return this.name;
vegorov@chromium.org42841962010-10-18 11:18:59 +0000507 // TODO(608): the spaces in a regexp below had to be escaped as \040
lrn@chromium.org25156de2010-04-06 13:10:27 +0000508 // because this file is being processed by js2c whose handling of spaces
509 // in regexps is broken. Also, ['"] are excluded from allowed URLs to
510 // avoid matches against sources that invoke evals with sourceURL.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000511 // A better solution would be to detect these special comments in
512 // the scanner/parser.
513 var source = ToString(this.source);
514 var sourceUrlPos = %StringIndexOf(source, "sourceURL=", 0);
515 if (sourceUrlPos > 4) {
516 var sourceUrlPattern =
517 /\/\/@[\040\t]sourceURL=[\040\t]*([^\s\'\"]*)[\040\t]*$/gm;
518 // Don't reuse lastMatchInfo here, so we create a new array with room
519 // for four captures (array with length one longer than the index
520 // of the fourth capture, where the numbering is zero-based).
521 var matchInfo = new InternalArray(CAPTURE(3) + 1);
522 var match =
523 %_RegExpExec(sourceUrlPattern, source, sourceUrlPos - 4, matchInfo);
524 if (match) {
525 return SubString(source, matchInfo[CAPTURE(2)], matchInfo[CAPTURE(3)]);
526 }
527 }
528 return this.name;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000529}
530
531
532/**
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000533 * Class for source location. A source location is a position within some
534 * source with the following properties:
535 * script : script object for the source
536 * line : source line number
537 * column : source column within the line
538 * position : position within the source
539 * start : position of start of source context (inclusive)
540 * end : position of end of source context (not inclusive)
541 * Source text for the source context is the character interval [start, end[. In
542 * most cases end will point to a newline character. It might point just past
543 * the final position of the source if the last source line does not end with a
iposva@chromium.org245aa852009-02-10 00:49:54 +0000544 * newline character.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000545 * @param {Script} script The Script object for which this is a location
546 * @param {number} position Source position for the location
547 * @param {number} line The line number for the location
548 * @param {number} column The column within the line for the location
549 * @param {number} start Source position for start of source context
550 * @param {number} end Source position for end of source context
551 * @constructor
552 */
553function SourceLocation(script, position, line, column, start, end) {
554 this.script = script;
555 this.position = position;
556 this.line = line;
557 this.column = column;
558 this.start = start;
559 this.end = end;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000560}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000561
562
563const kLineLengthLimit = 78;
564
565/**
566 * Restrict source location start and end positions to make the source slice
567 * no more that a certain number of characters wide.
568 * @param {number} opt_limit The with limit of the source text with a default
569 * of 78
570 * @param {number} opt_before The number of characters to prefer before the
571 * position with a default value of 10 less that the limit
572 */
573SourceLocation.prototype.restrict = function (opt_limit, opt_before) {
574 // Find the actual limit to use.
575 var limit;
576 var before;
577 if (!IS_UNDEFINED(opt_limit)) {
578 limit = opt_limit;
579 } else {
580 limit = kLineLengthLimit;
581 }
582 if (!IS_UNDEFINED(opt_before)) {
583 before = opt_before;
584 } else {
585 // If no before is specified center for small limits and perfer more source
586 // before the the position that after for longer limits.
587 if (limit <= 20) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000588 before = $floor(limit / 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000589 } else {
590 before = limit - 10;
591 }
592 }
593 if (before >= limit) {
594 before = limit - 1;
595 }
596
597 // If the [start, end[ interval is too big we restrict
598 // it in one or both ends. We make sure to always produce
599 // restricted intervals of maximum allowed size.
600 if (this.end - this.start > limit) {
601 var start_limit = this.position - before;
602 var end_limit = this.position + limit - before;
603 if (this.start < start_limit && end_limit < this.end) {
604 this.start = start_limit;
605 this.end = end_limit;
606 } else if (this.start < start_limit) {
607 this.start = this.end - limit;
608 } else {
609 this.end = this.start + limit;
610 }
611 }
612};
613
614
615/**
616 * Get the source text for a SourceLocation
617 * @return {String}
618 * Source text for this location.
619 */
620SourceLocation.prototype.sourceText = function () {
whesse@chromium.org7a392b32011-01-31 11:30:36 +0000621 return %_CallFunction(this.script.source, this.start, this.end, StringSubstring);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000622};
623
624
625/**
626 * Class for a source slice. A source slice is a part of a script source with
627 * the following properties:
628 * script : script object for the source
629 * from_line : line number for the first line in the slice
630 * to_line : source line number for the last line in the slice
631 * from_position : position of the first character in the slice
632 * to_position : position of the last character in the slice
633 * The to_line and to_position are not included in the slice, that is the lines
634 * in the slice are [from_line, to_line[. Likewise the characters in the slice
635 * are [from_position, to_position[.
636 * @param {Script} script The Script object for the source slice
637 * @param {number} from_line
638 * @param {number} to_line
639 * @param {number} from_position
640 * @param {number} to_position
641 * @constructor
642 */
643function SourceSlice(script, from_line, to_line, from_position, to_position) {
644 this.script = script;
645 this.from_line = from_line;
646 this.to_line = to_line;
647 this.from_position = from_position;
648 this.to_position = to_position;
649}
650
651
652/**
653 * Get the source text for a SourceSlice
654 * @return {String} Source text for this slice. The last line will include
655 * the line terminating characters (if any)
656 */
657SourceSlice.prototype.sourceText = function () {
whesse@chromium.org7a392b32011-01-31 11:30:36 +0000658 return %_CallFunction(this.script.source,
659 this.from_position,
660 this.to_position,
661 StringSubstring);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000662};
663
664
665// Returns the offset of the given position within the containing
666// line.
667function GetPositionInLine(message) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000668 var script = %MessageGetScript(message);
669 var start_position = %MessageGetStartPosition(message);
670 var location = script.locationFromPosition(start_position, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000671 if (location == null) return -1;
672 location.restrict();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000673 return start_position - location.start;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000674}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000675
676
677function GetStackTraceLine(recv, fun, pos, isGlobal) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000678 return FormatSourcePosition(new CallSite(recv, fun, pos));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000679}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000680
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000681// ----------------------------------------------------------------------------
682// Error implementation
683
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000684// Defines accessors for a property that is calculated the first time
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000685// the property is read.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000686function DefineOneShotAccessor(obj, name, fun) {
687 // Note that the accessors consistently operate on 'obj', not 'this'.
688 // Since the object may occur in someone else's prototype chain we
689 // can't rely on 'this' being the same as 'obj'.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000690 var hasBeenSet = false;
691 var value;
whesse@chromium.org7b260152011-06-20 15:33:18 +0000692 function getter() {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000693 if (hasBeenSet) {
694 return value;
695 }
696 hasBeenSet = true;
697 value = fun(obj);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000698 return value;
whesse@chromium.org7b260152011-06-20 15:33:18 +0000699 }
700 function setter(v) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000701 hasBeenSet = true;
702 value = v;
whesse@chromium.org7b260152011-06-20 15:33:18 +0000703 }
704 var desc = { get: getter,
705 set: setter,
706 enumerable: false,
707 configurable: true };
708 desc = ToPropertyDescriptor(desc);
709 DefineOwnProperty(obj, name, desc, true);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000710}
711
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000712function CallSite(receiver, fun, pos) {
713 this.receiver = receiver;
714 this.fun = fun;
715 this.pos = pos;
716}
717
718CallSite.prototype.getThis = function () {
719 return this.receiver;
720};
721
722CallSite.prototype.getTypeName = function () {
723 var constructor = this.receiver.constructor;
724 if (!constructor)
whesse@chromium.org7a392b32011-01-31 11:30:36 +0000725 return %_CallFunction(this.receiver, ObjectToString);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000726 var constructorName = constructor.name;
727 if (!constructorName)
whesse@chromium.org7a392b32011-01-31 11:30:36 +0000728 return %_CallFunction(this.receiver, ObjectToString);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000729 return constructorName;
730};
731
732CallSite.prototype.isToplevel = function () {
733 if (this.receiver == null)
734 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000735 return IS_GLOBAL(this.receiver);
736};
737
738CallSite.prototype.isEval = function () {
739 var script = %FunctionGetScript(this.fun);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000740 return script && script.compilation_type == COMPILATION_TYPE_EVAL;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000741};
742
743CallSite.prototype.getEvalOrigin = function () {
744 var script = %FunctionGetScript(this.fun);
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000745 return FormatEvalOrigin(script);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000746};
747
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000748CallSite.prototype.getScriptNameOrSourceURL = function () {
749 var script = %FunctionGetScript(this.fun);
750 return script ? script.nameOrSourceURL() : null;
751};
752
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000753CallSite.prototype.getFunction = function () {
754 return this.fun;
755};
756
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000757CallSite.prototype.getFunctionName = function () {
758 // See if the function knows its own name
759 var name = this.fun.name;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000760 if (name) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000761 return name;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000762 } else {
763 return %FunctionGetInferredName(this.fun);
764 }
765 // Maybe this is an evaluation?
766 var script = %FunctionGetScript(this.fun);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000767 if (script && script.compilation_type == COMPILATION_TYPE_EVAL)
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000768 return "eval";
769 return null;
770};
771
772CallSite.prototype.getMethodName = function () {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000773 // See if we can find a unique property on the receiver that holds
774 // this function.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000775 var ownName = this.fun.name;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000776 if (ownName && this.receiver &&
whesse@chromium.org7a392b32011-01-31 11:30:36 +0000777 (%_CallFunction(this.receiver, ownName, ObjectLookupGetter) === this.fun ||
778 %_CallFunction(this.receiver, ownName, ObjectLookupSetter) === this.fun ||
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000779 this.receiver[ownName] === this.fun)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000780 // To handle DontEnum properties we guess that the method has
781 // the same name as the function.
782 return ownName;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000783 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000784 var name = null;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000785 for (var prop in this.receiver) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000786 if (this.receiver.__lookupGetter__(prop) === this.fun ||
787 this.receiver.__lookupSetter__(prop) === this.fun ||
788 (!this.receiver.__lookupGetter__(prop) && this.receiver[prop] === this.fun)) {
789 // If we find more than one match bail out to avoid confusion.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000790 if (name)
791 return null;
792 name = prop;
793 }
794 }
795 if (name)
796 return name;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000797 return null;
798};
799
800CallSite.prototype.getFileName = function () {
801 var script = %FunctionGetScript(this.fun);
802 return script ? script.name : null;
803};
804
805CallSite.prototype.getLineNumber = function () {
806 if (this.pos == -1)
807 return null;
808 var script = %FunctionGetScript(this.fun);
809 var location = null;
810 if (script) {
811 location = script.locationFromPosition(this.pos, true);
812 }
813 return location ? location.line + 1 : null;
814};
815
816CallSite.prototype.getColumnNumber = function () {
817 if (this.pos == -1)
818 return null;
819 var script = %FunctionGetScript(this.fun);
820 var location = null;
821 if (script) {
822 location = script.locationFromPosition(this.pos, true);
823 }
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000824 return location ? location.column + 1: null;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000825};
826
827CallSite.prototype.isNative = function () {
828 var script = %FunctionGetScript(this.fun);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000829 return script ? (script.type == TYPE_NATIVE) : false;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000830};
831
832CallSite.prototype.getPosition = function () {
833 return this.pos;
834};
835
836CallSite.prototype.isConstructor = function () {
837 var constructor = this.receiver ? this.receiver.constructor : null;
838 if (!constructor)
839 return false;
840 return this.fun === constructor;
841};
842
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000843function FormatEvalOrigin(script) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000844 var sourceURL = script.nameOrSourceURL();
845 if (sourceURL)
846 return sourceURL;
847
848 var eval_origin = "eval at ";
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000849 if (script.eval_from_function_name) {
850 eval_origin += script.eval_from_function_name;
851 } else {
852 eval_origin += "<anonymous>";
853 }
lrn@chromium.org25156de2010-04-06 13:10:27 +0000854
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000855 var eval_from_script = script.eval_from_script;
856 if (eval_from_script) {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000857 if (eval_from_script.compilation_type == COMPILATION_TYPE_EVAL) {
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000858 // eval script originated from another eval.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000859 eval_origin += " (" + FormatEvalOrigin(eval_from_script) + ")";
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000860 } else {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000861 // eval script originated from "real" source.
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000862 if (eval_from_script.name) {
863 eval_origin += " (" + eval_from_script.name;
864 var location = eval_from_script.locationFromPosition(script.eval_from_script_position, true);
865 if (location) {
866 eval_origin += ":" + (location.line + 1);
867 eval_origin += ":" + (location.column + 1);
868 }
869 eval_origin += ")"
870 } else {
871 eval_origin += " (unknown source)";
872 }
873 }
874 }
lrn@chromium.org25156de2010-04-06 13:10:27 +0000875
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000876 return eval_origin;
877};
878
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000879function FormatSourcePosition(frame) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000880 var fileName;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000881 var fileLocation = "";
882 if (frame.isNative()) {
883 fileLocation = "native";
884 } else if (frame.isEval()) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000885 fileName = frame.getScriptNameOrSourceURL();
886 if (!fileName)
887 fileLocation = frame.getEvalOrigin();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000888 } else {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000889 fileName = frame.getFileName();
890 }
891
892 if (fileName) {
893 fileLocation += fileName;
894 var lineNumber = frame.getLineNumber();
895 if (lineNumber != null) {
896 fileLocation += ":" + lineNumber;
897 var columnNumber = frame.getColumnNumber();
898 if (columnNumber) {
899 fileLocation += ":" + columnNumber;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000900 }
901 }
902 }
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000903
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000904 if (!fileLocation) {
905 fileLocation = "unknown source";
906 }
907 var line = "";
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000908 var functionName = frame.getFunction().name;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000909 var addPrefix = true;
910 var isConstructor = frame.isConstructor();
911 var isMethodCall = !(frame.isToplevel() || isConstructor);
912 if (isMethodCall) {
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000913 var methodName = frame.getMethodName();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000914 line += frame.getTypeName() + ".";
915 if (functionName) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000916 line += functionName;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000917 if (methodName && (methodName != functionName)) {
918 line += " [as " + methodName + "]";
919 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000920 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000921 line += methodName || "<anonymous>";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000922 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000923 } else if (isConstructor) {
924 line += "new " + (functionName || "<anonymous>");
925 } else if (functionName) {
926 line += functionName;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000927 } else {
928 line += fileLocation;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000929 addPrefix = false;
930 }
931 if (addPrefix) {
932 line += " (" + fileLocation + ")";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000933 }
934 return line;
935}
936
937function FormatStackTrace(error, frames) {
938 var lines = [];
939 try {
940 lines.push(error.toString());
941 } catch (e) {
942 try {
943 lines.push("<error: " + e + ">");
944 } catch (ee) {
945 lines.push("<error>");
946 }
947 }
948 for (var i = 0; i < frames.length; i++) {
949 var frame = frames[i];
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000950 var line;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000951 try {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000952 line = FormatSourcePosition(frame);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000953 } catch (e) {
954 try {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000955 line = "<error: " + e + ">";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000956 } catch (ee) {
957 // Any code that reaches this point is seriously nasty!
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000958 line = "<error>";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000959 }
960 }
961 lines.push(" at " + line);
962 }
963 return lines.join("\n");
964}
965
966function FormatRawStackTrace(error, raw_stack) {
967 var frames = [ ];
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000968 for (var i = 0; i < raw_stack.length; i += 4) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000969 var recv = raw_stack[i];
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000970 var fun = raw_stack[i + 1];
971 var code = raw_stack[i + 2];
972 var pc = raw_stack[i + 3];
973 var pos = %FunctionGetPositionForOffset(code, pc);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000974 frames.push(new CallSite(recv, fun, pos));
975 }
976 if (IS_FUNCTION($Error.prepareStackTrace)) {
977 return $Error.prepareStackTrace(error, frames);
978 } else {
979 return FormatStackTrace(error, frames);
980 }
981}
982
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000983function DefineError(f) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000984 // Store the error function in both the global object
985 // and the runtime object. The function is fetched
986 // from the runtime object when throwing errors from
987 // within the runtime system to avoid strange side
988 // effects when overwriting the error functions from
989 // user code.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000990 var name = f.name;
991 %SetProperty(global, name, f, DONT_ENUM);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000992 this['$' + name] = f;
993 // Configure the error function.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000994 if (name == 'Error') {
995 // The prototype of the Error object must itself be an error.
996 // However, it can't be an instance of the Error object because
997 // it hasn't been properly configured yet. Instead we create a
998 // special not-a-true-error-but-close-enough object.
999 function ErrorPrototype() {}
1000 %FunctionSetPrototype(ErrorPrototype, $Object.prototype);
1001 %FunctionSetInstanceClassName(ErrorPrototype, 'Error');
1002 %FunctionSetPrototype(f, new ErrorPrototype());
1003 } else {
1004 %FunctionSetPrototype(f, new $Error());
1005 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001006 %FunctionSetInstanceClassName(f, 'Error');
ager@chromium.org7c537e22008-10-16 08:43:32 +00001007 %SetProperty(f.prototype, 'constructor', f, DONT_ENUM);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001008 // The name property on the prototype of error objects is not
1009 // specified as being read-one and dont-delete. However, allowing
1010 // overwriting allows leaks of error objects between script blocks
1011 // in the same context in a browser setting. Therefore we fix the
1012 // name.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001013 %SetProperty(f.prototype, "name", name, DONT_ENUM | DONT_DELETE | READ_ONLY);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001014 %SetCode(f, function(m) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001015 if (%_IsConstructCall()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001016 // Define all the expected properties directly on the error
1017 // object. This avoids going through getters and setters defined
1018 // on prototype objects.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001019 %IgnoreAttributesAndSetProperty(this, 'stack', void 0, DONT_ENUM);
1020 %IgnoreAttributesAndSetProperty(this, 'arguments', void 0, DONT_ENUM);
1021 %IgnoreAttributesAndSetProperty(this, 'type', void 0, DONT_ENUM);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001022 if (m === kAddMessageAccessorsMarker) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001023 // DefineOneShotAccessor always inserts a message property and
1024 // ignores setters.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001025 DefineOneShotAccessor(this, 'message', function (obj) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001026 return FormatMessage(%NewMessageObject(obj.type, obj.arguments));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001027 });
1028 } else if (!IS_UNDEFINED(m)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001029 %IgnoreAttributesAndSetProperty(this,
1030 'message',
1031 ToString(m),
1032 DONT_ENUM);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001033 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001034 captureStackTrace(this, f);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001035 } else {
1036 return new f(m);
1037 }
1038 });
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001039}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001040
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001041function captureStackTrace(obj, cons_opt) {
1042 var stackTraceLimit = $Error.stackTraceLimit;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001043 if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001044 if (stackTraceLimit < 0 || stackTraceLimit > 10000)
1045 stackTraceLimit = 10000;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001046 var raw_stack = %CollectStackTrace(cons_opt
1047 ? cons_opt
1048 : captureStackTrace, stackTraceLimit);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001049 DefineOneShotAccessor(obj, 'stack', function (obj) {
1050 return FormatRawStackTrace(obj, raw_stack);
1051 });
1052};
1053
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001054$Math.__proto__ = global.Object.prototype;
1055
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001056// DefineError is a native function. Use explicit receiver. Otherwise
1057// the receiver will be 'undefined'.
1058this.DefineError(function Error() { });
1059this.DefineError(function TypeError() { });
1060this.DefineError(function RangeError() { });
1061this.DefineError(function SyntaxError() { });
1062this.DefineError(function ReferenceError() { });
1063this.DefineError(function EvalError() { });
1064this.DefineError(function URIError() { });
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001065
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001066$Error.captureStackTrace = captureStackTrace;
1067
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001068// Setup extra properties of the Error.prototype object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001069function setErrorMessage() {
1070 var desc = {value: '',
1071 enumerable: false,
1072 configurable: true,
1073 writable: true };
1074 DefineOwnProperty($Error.prototype,
1075 'message',
1076 ToPropertyDescriptor(desc),
1077 true);
1078
1079}
1080
1081setErrorMessage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001082
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001083// Global list of error objects visited during errorToString. This is
1084// used to detect cycles in error toString formatting.
1085var visited_errors = new $Array();
1086var cyclic_error_marker = new $Object();
1087
1088function errorToStringDetectCycle() {
1089 if (!%PushIfAbsent(visited_errors, this)) throw cyclic_error_marker;
1090 try {
1091 var type = this.type;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001092 if (type && !%_CallFunction(this, "message", ObjectHasOwnProperty)) {
1093 var formatted = FormatMessage(%NewMessageObject(type, this.arguments));
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001094 return this.name + ": " + formatted;
1095 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001096 var message = %_CallFunction(this, "message", ObjectHasOwnProperty)
1097 ? (": " + this.message)
1098 : "";
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001099 return this.name + message;
1100 } finally {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001101 visited_errors.length = visited_errors.length - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001102 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001103}
1104
1105function errorToString() {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001106 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1107 throw MakeTypeError("called_on_null_or_undefined",
1108 ["Error.prototype.toString"]);
1109 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001110 // This helper function is needed because access to properties on
1111 // the builtins object do not work inside of a catch clause.
1112 function isCyclicErrorMarker(o) { return o === cyclic_error_marker; }
1113
1114 try {
1115 return %_CallFunction(this, errorToStringDetectCycle);
1116 } catch(e) {
1117 // If this error message was encountered already return the empty
1118 // string for it instead of recursively formatting it.
1119 if (isCyclicErrorMarker(e)) return '';
1120 else throw e;
1121 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001122}
1123
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001124
1125InstallFunctions($Error.prototype, DONT_ENUM, ['toString', errorToString]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001126
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001127// Boilerplate for exceptions for stack overflows. Used from
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001128// Isolate::StackOverflow().
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001129const kStackOverflowBoilerplate = MakeRangeError('stack_overflow', []);