blob: 3c85d9416af035f37c302e4e7df5c29fee9c234b [file] [log] [blame]
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001// Copyright 2011 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//
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000031// If this object gets passed to an error constructor the error will
32// get an accessor for .message that constructs a descriptive error
33// message on access.
fschneider@chromium.org1805e212011-09-05 10:49:12 +000034const kAddMessageAccessorsMarker = { };
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000035
fschneider@chromium.org1805e212011-09-05 10:49:12 +000036// This will be lazily initialized when first needed (and forcibly
37// overwritten even though it's const).
38const kMessages = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000040function FormatString(format, message) {
41 var args = %MessageGetArguments(message);
42 var result = "";
43 var arg_num = 0;
44 for (var i = 0; i < format.length; i++) {
45 var str = format[i];
fschneider@chromium.org1805e212011-09-05 10:49:12 +000046 if (str.length == 2 && %_StringCharCodeAt(str, 0) == 0x25) {
47 // Two-char string starts with "%".
48 var arg_num = (%_StringCharCodeAt(str, 1) - 0x30) >>> 0;
49 if (arg_num < 4) {
50 // str is one of %0, %1, %2 or %3.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000051 try {
52 str = ToDetailString(args[arg_num]);
53 } catch (e) {
54 str = "#<error>";
55 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000056 }
ager@chromium.org378b34e2011-01-28 08:04:38 +000057 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000058 result += str;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000059 }
60 return result;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000061}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000062
63
ager@chromium.org0ee099b2011-01-25 14:06:47 +000064// To check if something is a native error we need to check the
65// concrete native error types. It is not enough to check "obj
66// instanceof $Error" because user code can replace
67// NativeError.prototype.__proto__. User code cannot replace
68// NativeError.prototype though and therefore this is a safe test.
69function IsNativeErrorObject(obj) {
70 return (obj instanceof $Error) ||
71 (obj instanceof $EvalError) ||
72 (obj instanceof $RangeError) ||
73 (obj instanceof $ReferenceError) ||
74 (obj instanceof $SyntaxError) ||
75 (obj instanceof $TypeError) ||
76 (obj instanceof $URIError);
77}
78
79
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000080// When formatting internally created error messages, do not
81// invoke overwritten error toString methods but explicitly use
82// the error to string method. This is to avoid leaking error
83// objects between script tags in a browser setting.
84function ToStringCheckErrorObject(obj) {
ager@chromium.org0ee099b2011-01-25 14:06:47 +000085 if (IsNativeErrorObject(obj)) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000086 return %_CallFunction(obj, errorToString);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000087 } else {
88 return ToString(obj);
89 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000090}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000091
92
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000093function ToDetailString(obj) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +000094 if (obj != null && IS_OBJECT(obj) && obj.toString === ObjectToString) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +000095 var constructor = obj.constructor;
fschneider@chromium.org1805e212011-09-05 10:49:12 +000096 if (typeof constructor == "function") {
97 var constructorName = constructor.name;
98 if (IS_STRING(constructorName) && constructorName !== "") {
99 return "#<" + constructorName + ">";
100 }
ager@chromium.org378b34e2011-01-28 08:04:38 +0000101 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000102 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000103 return ToStringCheckErrorObject(obj);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +0000104}
105
106
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000107function MakeGenericError(constructor, type, args) {
ager@chromium.org3e875802009-06-29 08:26:34 +0000108 if (IS_UNDEFINED(args)) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000109 args = [];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000110 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000111 var e = new constructor(kAddMessageAccessorsMarker);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000112 e.type = type;
113 e.arguments = args;
114 return e;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000115}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000116
117
118/**
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000119 * Set up the Script function and constructor.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000120 */
121%FunctionSetInstanceClassName(Script, 'Script');
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000122%SetProperty(Script.prototype, 'constructor', Script,
123 DONT_ENUM | DONT_DELETE | READ_ONLY);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000124%SetCode(Script, function(x) {
125 // Script objects can only be created by the VM.
126 throw new $Error("Not supported");
127});
128
129
130// Helper functions; called from the runtime system.
131function FormatMessage(message) {
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000132 if (kMessages === 0) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000133 var messagesDictionary = [
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000134 // Error
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000135 "cyclic_proto", ["Cyclic __proto__ value"],
136 "code_gen_from_strings", ["Code generation from strings disallowed for this context"],
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000137 // TypeError
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000138 "unexpected_token", ["Unexpected token ", "%0"],
139 "unexpected_token_number", ["Unexpected number"],
140 "unexpected_token_string", ["Unexpected string"],
141 "unexpected_token_identifier", ["Unexpected identifier"],
142 "unexpected_reserved", ["Unexpected reserved word"],
143 "unexpected_strict_reserved", ["Unexpected strict mode reserved word"],
144 "unexpected_eos", ["Unexpected end of input"],
145 "malformed_regexp", ["Invalid regular expression: /", "%0", "/: ", "%1"],
146 "unterminated_regexp", ["Invalid regular expression: missing /"],
147 "regexp_flags", ["Cannot supply flags when constructing one RegExp from another"],
148 "incompatible_method_receiver", ["Method ", "%0", " called on incompatible receiver ", "%1"],
149 "invalid_lhs_in_assignment", ["Invalid left-hand side in assignment"],
150 "invalid_lhs_in_for_in", ["Invalid left-hand side in for-in"],
151 "invalid_lhs_in_postfix_op", ["Invalid left-hand side expression in postfix operation"],
152 "invalid_lhs_in_prefix_op", ["Invalid left-hand side expression in prefix operation"],
153 "multiple_defaults_in_switch", ["More than one default clause in switch statement"],
154 "newline_after_throw", ["Illegal newline after throw"],
155 "redeclaration", ["%0", " '", "%1", "' has already been declared"],
156 "no_catch_or_finally", ["Missing catch or finally after try"],
157 "unknown_label", ["Undefined label '", "%0", "'"],
158 "uncaught_exception", ["Uncaught ", "%0"],
159 "stack_trace", ["Stack Trace:\n", "%0"],
160 "called_non_callable", ["%0", " is not a function"],
161 "undefined_method", ["Object ", "%1", " has no method '", "%0", "'"],
162 "property_not_function", ["Property '", "%0", "' of object ", "%1", " is not a function"],
163 "cannot_convert_to_primitive", ["Cannot convert object to primitive value"],
164 "not_constructor", ["%0", " is not a constructor"],
165 "not_defined", ["%0", " is not defined"],
166 "non_object_property_load", ["Cannot read property '", "%0", "' of ", "%1"],
167 "non_object_property_store", ["Cannot set property '", "%0", "' of ", "%1"],
168 "non_object_property_call", ["Cannot call method '", "%0", "' of ", "%1"],
169 "with_expression", ["%0", " has no properties"],
170 "illegal_invocation", ["Illegal invocation"],
171 "no_setter_in_callback", ["Cannot set property ", "%0", " of ", "%1", " which has only a getter"],
172 "apply_non_function", ["Function.prototype.apply was called on ", "%0", ", which is a ", "%1", " and not a function"],
173 "apply_wrong_args", ["Function.prototype.apply: Arguments list has wrong type"],
174 "invalid_in_operator_use", ["Cannot use 'in' operator to search for '", "%0", "' in ", "%1"],
175 "instanceof_function_expected", ["Expecting a function in instanceof check, but got ", "%0"],
176 "instanceof_nonobject_proto", ["Function has non-object prototype '", "%0", "' in instanceof check"],
177 "null_to_object", ["Cannot convert null to object"],
178 "reduce_no_initial", ["Reduce of empty array with no initial value"],
179 "getter_must_be_callable", ["Getter must be a function: ", "%0"],
180 "setter_must_be_callable", ["Setter must be a function: ", "%0"],
181 "value_and_accessor", ["Invalid property. A property cannot both have accessors and be writable or have a value, ", "%0"],
182 "proto_object_or_null", ["Object prototype may only be an Object or null"],
183 "property_desc_object", ["Property description must be an object: ", "%0"],
184 "redefine_disallowed", ["Cannot redefine property: ", "%0"],
185 "define_disallowed", ["Cannot define property:", "%0", ", object is not extensible."],
186 "non_extensible_proto", ["%0", " is not extensible"],
187 "handler_non_object", ["Proxy.", "%0", " called with non-object as handler"],
188 "handler_trap_missing", ["Proxy handler ", "%0", " has no '", "%1", "' trap"],
189 "handler_trap_must_be_callable", ["Proxy handler ", "%0", " has non-callable '", "%1", "' trap"],
190 "handler_returned_false", ["Proxy handler ", "%0", " returned false for '", "%1", "' trap"],
191 "handler_returned_undefined", ["Proxy handler ", "%0", " returned undefined for '", "%1", "' trap"],
192 "proxy_prop_not_configurable", ["Trap ", "%1", " of proxy handler ", "%0", " returned non-configurable descriptor for property ", "%2"],
193 "proxy_non_object_prop_names", ["Trap ", "%1", " returned non-object ", "%0"],
194 "proxy_repeated_prop_name", ["Trap ", "%1", " returned repeated property name ", "%2"],
195 "invalid_weakmap_key", ["Invalid value used as weak map key"],
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000196 // RangeError
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000197 "invalid_array_length", ["Invalid array length"],
198 "stack_overflow", ["Maximum call stack size exceeded"],
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000199 // SyntaxError
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000200 "unable_to_parse", ["Parse error"],
201 "invalid_regexp_flags", ["Invalid flags supplied to RegExp constructor '", "%0", "'"],
202 "invalid_regexp", ["Invalid RegExp pattern /", "%0", "/"],
203 "illegal_break", ["Illegal break statement"],
204 "illegal_continue", ["Illegal continue statement"],
205 "illegal_return", ["Illegal return statement"],
206 "error_loading_debugger", ["Error loading debugger"],
207 "no_input_to_regexp", ["No input to ", "%0"],
208 "invalid_json", ["String '", "%0", "' is not valid JSON"],
209 "circular_structure", ["Converting circular structure to JSON"],
210 "obj_ctor_property_non_object", ["Object.", "%0", " called on non-object"],
211 "called_on_null_or_undefined", ["%0", " called on null or undefined"],
212 "array_indexof_not_defined", ["Array.getIndexOf: Argument undefined"],
213 "object_not_extensible", ["Can't add property ", "%0", ", object is not extensible"],
214 "illegal_access", ["Illegal access"],
215 "invalid_preparser_data", ["Invalid preparser data for function ", "%0"],
216 "strict_mode_with", ["Strict mode code may not include a with statement"],
217 "strict_catch_variable", ["Catch variable may not be eval or arguments in strict mode"],
218 "too_many_arguments", ["Too many arguments in function call (only 32766 allowed)"],
219 "too_many_parameters", ["Too many parameters in function definition (only 32766 allowed)"],
220 "too_many_variables", ["Too many variables declared (only 32767 allowed)"],
221 "strict_param_name", ["Parameter name eval or arguments is not allowed in strict mode"],
222 "strict_param_dupe", ["Strict mode function may not have duplicate parameter names"],
223 "strict_var_name", ["Variable name may not be eval or arguments in strict mode"],
224 "strict_function_name", ["Function name may not be eval or arguments in strict mode"],
225 "strict_octal_literal", ["Octal literals are not allowed in strict mode."],
226 "strict_duplicate_property", ["Duplicate data property in object literal not allowed in strict mode"],
227 "accessor_data_property", ["Object literal may not have data and accessor property with the same name"],
228 "accessor_get_set", ["Object literal may not have multiple get/set accessors with the same name"],
229 "strict_lhs_assignment", ["Assignment to eval or arguments is not allowed in strict mode"],
230 "strict_lhs_postfix", ["Postfix increment/decrement may not have eval or arguments operand in strict mode"],
231 "strict_lhs_prefix", ["Prefix increment/decrement may not have eval or arguments operand in strict mode"],
232 "strict_reserved_word", ["Use of future reserved word in strict mode"],
233 "strict_delete", ["Delete of an unqualified identifier in strict mode."],
234 "strict_delete_property", ["Cannot delete property '", "%0", "' of ", "%1"],
235 "strict_const", ["Use of const in strict mode."],
236 "strict_function", ["In strict mode code, functions can only be declared at top level or immediately within another function." ],
237 "strict_read_only_property", ["Cannot assign to read only property '", "%0", "' of ", "%1"],
238 "strict_cannot_assign", ["Cannot assign to read only '", "%0", "' in strict mode"],
239 "strict_poison_pill", ["'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them"],
240 "strict_caller", ["Illegal access to a strict mode caller function."],
241 "unprotected_let", ["Illegal let declaration in unprotected statement context."],
242 ];
243 var messages = { __proto__ : null };
244 var desc = new PropertyDescriptor();
245 desc.setConfigurable(false);
246 desc.setEnumerable(false);
247 desc.setWritable(false);
248 for (var i = 0; i < messagesDictionary.length; i += 2) {
249 var key = messagesDictionary[i];
250 var format = messagesDictionary[i + 1];
251 ObjectFreeze(format);
252 desc.setValue(format);
253 DefineOwnProperty(messages, key, desc);
254 }
255 %PreventExtensions(messages);
256 %IgnoreAttributesAndSetProperty(builtins, "kMessages",
257 messages,
258 DONT_DELETE | DONT_ENUM | READ_ONLY);
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000259 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000260 var message_type = %MessageGetType(message);
261 var format = kMessages[message_type];
262 if (!format) return "<unknown message " + message_type + ">";
263 return FormatString(format, message);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000264}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000265
266
267function GetLineNumber(message) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000268 var start_position = %MessageGetStartPosition(message);
269 if (start_position == -1) return kNoLineNumberInfo;
270 var script = %MessageGetScript(message);
271 var location = script.locationFromPosition(start_position, true);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000272 if (location == null) return kNoLineNumberInfo;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000273 return location.line + 1;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000274}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000275
276
277// Returns the source code line containing the given source
278// position, or the empty string if the position is invalid.
279function GetSourceLine(message) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000280 var script = %MessageGetScript(message);
281 var start_position = %MessageGetStartPosition(message);
282 var location = script.locationFromPosition(start_position, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000283 if (location == null) return "";
284 location.restrict();
285 return location.sourceText();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000286}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000287
288
289function MakeTypeError(type, args) {
290 return MakeGenericError($TypeError, type, args);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000291}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000292
293
294function MakeRangeError(type, args) {
295 return MakeGenericError($RangeError, type, args);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000296}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000297
298
299function MakeSyntaxError(type, args) {
300 return MakeGenericError($SyntaxError, type, args);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000301}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000302
303
304function MakeReferenceError(type, args) {
305 return MakeGenericError($ReferenceError, type, args);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000306}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000307
308
309function MakeEvalError(type, args) {
310 return MakeGenericError($EvalError, type, args);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000311}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000312
313
314function MakeError(type, args) {
315 return MakeGenericError($Error, type, args);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000316}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000317
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000318/**
319 * Find a line number given a specific source position.
320 * @param {number} position The source position.
321 * @return {number} 0 if input too small, -1 if input too large,
322 else the line number.
323 */
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000324function ScriptLineFromPosition(position) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000325 var lower = 0;
326 var upper = this.lineCount() - 1;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000327 var line_ends = this.line_ends;
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000328
329 // We'll never find invalid positions so bail right away.
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000330 if (position > line_ends[upper]) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000331 return -1;
332 }
333
334 // This means we don't have to safe-guard indexing line_ends[i - 1].
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000335 if (position <= line_ends[0]) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000336 return 0;
337 }
338
339 // Binary search to find line # from position range.
340 while (upper >= 1) {
341 var i = (lower + upper) >> 1;
342
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000343 if (position > line_ends[i]) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000344 lower = i + 1;
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000345 } else if (position <= line_ends[i - 1]) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000346 upper = i - 1;
347 } else {
348 return i;
349 }
350 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000351
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000352 return -1;
353}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000354
355/**
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000356 * Get information on a specific source position.
357 * @param {number} position The source position
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000358 * @param {boolean} include_resource_offset Set to true to have the resource
359 * offset added to the location
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000360 * @return {SourceLocation}
361 * If line is negative or not in the source null is returned.
362 */
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000363function ScriptLocationFromPosition(position,
364 include_resource_offset) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000365 var line = this.lineFromPosition(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000366 if (line == -1) return null;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000367
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000368 // Determine start, end and column.
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000369 var line_ends = this.line_ends;
370 var start = line == 0 ? 0 : line_ends[line - 1] + 1;
371 var end = line_ends[line];
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000372 if (end > 0 && %_CallFunction(this.source, end - 1, StringCharAt) == '\r') {
373 end--;
374 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000375 var column = position - start;
376
377 // Adjust according to the offset within the resource.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000378 if (include_resource_offset) {
379 line += this.line_offset;
380 if (line == this.line_offset) {
381 column += this.column_offset;
382 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000383 }
384
385 return new SourceLocation(this, position, line, column, start, end);
386};
387
388
389/**
390 * Get information on a specific source line and column possibly offset by a
391 * fixed source position. This function is used to find a source position from
392 * a line and column position. The fixed source position offset is typically
393 * used to find a source position in a function based on a line and column in
394 * the source for the function alone. The offset passed will then be the
395 * start position of the source for the function within the full script source.
396 * @param {number} opt_line The line within the source. Default value is 0
397 * @param {number} opt_column The column in within the line. Default value is 0
398 * @param {number} opt_offset_position The offset from the begining of the
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000399 * source from where the line and column calculation starts.
400 * Default value is 0
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000401 * @return {SourceLocation}
402 * If line is negative or not in the source null is returned.
403 */
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000404function ScriptLocationFromLine(opt_line, opt_column, opt_offset_position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000405 // Default is the first line in the script. Lines in the script is relative
406 // to the offset within the resource.
407 var line = 0;
408 if (!IS_UNDEFINED(opt_line)) {
409 line = opt_line - this.line_offset;
410 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000411
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000412 // Default is first column. If on the first line add the offset within the
413 // resource.
414 var column = opt_column || 0;
415 if (line == 0) {
416 column -= this.column_offset
417 }
418
419 var offset_position = opt_offset_position || 0;
420 if (line < 0 || column < 0 || offset_position < 0) return null;
421 if (line == 0) {
ager@chromium.org3a6061e2009-03-12 14:24:36 +0000422 return this.locationFromPosition(offset_position + column, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000423 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000424 // Find the line where the offset position is located.
425 var offset_line = this.lineFromPosition(offset_position);
426
427 if (offset_line == -1 || offset_line + line >= this.lineCount()) {
428 return null;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000429 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000430
iposva@chromium.org245aa852009-02-10 00:49:54 +0000431 return this.locationFromPosition(this.line_ends[offset_line + line - 1] + 1 + column); // line > 0 here.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000432 }
433}
434
435
436/**
437 * Get a slice of source code from the script. The boundaries for the slice is
438 * specified in lines.
439 * @param {number} opt_from_line The first line (zero bound) in the slice.
440 * Default is 0
441 * @param {number} opt_to_column The last line (zero bound) in the slice (non
442 * inclusive). Default is the number of lines in the script
443 * @return {SourceSlice} The source slice or null of the parameters where
444 * invalid
445 */
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000446function ScriptSourceSlice(opt_from_line, opt_to_line) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000447 var from_line = IS_UNDEFINED(opt_from_line) ? this.line_offset : opt_from_line;
448 var to_line = IS_UNDEFINED(opt_to_line) ? this.line_offset + this.lineCount() : opt_to_line
449
450 // Adjust according to the offset within the resource.
451 from_line -= this.line_offset;
452 to_line -= this.line_offset;
453 if (from_line < 0) from_line = 0;
454 if (to_line > this.lineCount()) to_line = this.lineCount();
455
iposva@chromium.org245aa852009-02-10 00:49:54 +0000456 // Check parameters.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000457 if (from_line >= this.lineCount() ||
458 to_line < 0 ||
459 from_line > to_line) {
460 return null;
461 }
462
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000463 var line_ends = this.line_ends;
464 var from_position = from_line == 0 ? 0 : line_ends[from_line - 1] + 1;
465 var to_position = to_line == 0 ? 0 : line_ends[to_line - 1] + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000466
467 // Return a source slice with line numbers re-adjusted to the resource.
468 return new SourceSlice(this, from_line + this.line_offset, to_line + this.line_offset,
469 from_position, to_position);
470}
471
472
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000473function ScriptSourceLine(opt_line) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000474 // Default is the first line in the script. Lines in the script are relative
475 // to the offset within the resource.
476 var line = 0;
477 if (!IS_UNDEFINED(opt_line)) {
478 line = opt_line - this.line_offset;
479 }
iposva@chromium.org245aa852009-02-10 00:49:54 +0000480
481 // Check parameter.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000482 if (line < 0 || this.lineCount() <= line) {
483 return null;
484 }
485
iposva@chromium.org245aa852009-02-10 00:49:54 +0000486 // Return the source line.
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +0000487 var line_ends = this.line_ends;
488 var start = line == 0 ? 0 : line_ends[line - 1] + 1;
489 var end = line_ends[line];
whesse@chromium.org7a392b32011-01-31 11:30:36 +0000490 return %_CallFunction(this.source, start, end, StringSubstring);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000491}
492
493
494/**
495 * Returns the number of source lines.
496 * @return {number}
497 * Number of source lines.
498 */
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000499function ScriptLineCount() {
iposva@chromium.org245aa852009-02-10 00:49:54 +0000500 // Return number of source lines.
501 return this.line_ends.length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000502};
503
504
505/**
lrn@chromium.org25156de2010-04-06 13:10:27 +0000506 * Returns the name of script if available, contents of sourceURL comment
vegorov@chromium.org42841962010-10-18 11:18:59 +0000507 * otherwise. See
lrn@chromium.org25156de2010-04-06 13:10:27 +0000508 * http://fbug.googlecode.com/svn/branches/firebug1.1/docs/ReleaseNotes_1.1.txt
509 * for details on using //@ sourceURL comment to identify scritps that don't
510 * have name.
vegorov@chromium.org42841962010-10-18 11:18:59 +0000511 *
lrn@chromium.org25156de2010-04-06 13:10:27 +0000512 * @return {?string} script name if present, value for //@ sourceURL comment
513 * otherwise.
514 */
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000515function ScriptNameOrSourceURL() {
516 if (this.name) {
lrn@chromium.org25156de2010-04-06 13:10:27 +0000517 return this.name;
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000518 }
vegorov@chromium.org42841962010-10-18 11:18:59 +0000519 // TODO(608): the spaces in a regexp below had to be escaped as \040
lrn@chromium.org25156de2010-04-06 13:10:27 +0000520 // because this file is being processed by js2c whose handling of spaces
521 // in regexps is broken. Also, ['"] are excluded from allowed URLs to
522 // avoid matches against sources that invoke evals with sourceURL.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000523 // A better solution would be to detect these special comments in
524 // the scanner/parser.
525 var source = ToString(this.source);
526 var sourceUrlPos = %StringIndexOf(source, "sourceURL=", 0);
527 if (sourceUrlPos > 4) {
528 var sourceUrlPattern =
529 /\/\/@[\040\t]sourceURL=[\040\t]*([^\s\'\"]*)[\040\t]*$/gm;
530 // Don't reuse lastMatchInfo here, so we create a new array with room
531 // for four captures (array with length one longer than the index
532 // of the fourth capture, where the numbering is zero-based).
533 var matchInfo = new InternalArray(CAPTURE(3) + 1);
534 var match =
535 %_RegExpExec(sourceUrlPattern, source, sourceUrlPos - 4, matchInfo);
536 if (match) {
537 return SubString(source, matchInfo[CAPTURE(2)], matchInfo[CAPTURE(3)]);
538 }
539 }
540 return this.name;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000541}
542
543
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000544SetUpLockedPrototype(Script,
545 $Array("source", "name", "line_ends", "line_offset", "column_offset"),
546 $Array(
547 "lineFromPosition", ScriptLineFromPosition,
548 "locationFromPosition", ScriptLocationFromPosition,
549 "locationFromLine", ScriptLocationFromLine,
550 "sourceSlice", ScriptSourceSlice,
551 "sourceLine", ScriptSourceLine,
552 "lineCount", ScriptLineCount,
553 "nameOrSourceURL", ScriptNameOrSourceURL
554 )
555);
556
557
lrn@chromium.org25156de2010-04-06 13:10:27 +0000558/**
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000559 * Class for source location. A source location is a position within some
560 * source with the following properties:
561 * script : script object for the source
562 * line : source line number
563 * column : source column within the line
564 * position : position within the source
565 * start : position of start of source context (inclusive)
566 * end : position of end of source context (not inclusive)
567 * Source text for the source context is the character interval [start, end[. In
568 * most cases end will point to a newline character. It might point just past
569 * the final position of the source if the last source line does not end with a
iposva@chromium.org245aa852009-02-10 00:49:54 +0000570 * newline character.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000571 * @param {Script} script The Script object for which this is a location
572 * @param {number} position Source position for the location
573 * @param {number} line The line number for the location
574 * @param {number} column The column within the line for the location
575 * @param {number} start Source position for start of source context
576 * @param {number} end Source position for end of source context
577 * @constructor
578 */
579function SourceLocation(script, position, line, column, start, end) {
580 this.script = script;
581 this.position = position;
582 this.line = line;
583 this.column = column;
584 this.start = start;
585 this.end = end;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000586}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000587
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000588const kLineLengthLimit = 78;
589
590/**
591 * Restrict source location start and end positions to make the source slice
592 * no more that a certain number of characters wide.
593 * @param {number} opt_limit The with limit of the source text with a default
594 * of 78
595 * @param {number} opt_before The number of characters to prefer before the
596 * position with a default value of 10 less that the limit
597 */
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000598function SourceLocationRestrict(opt_limit, opt_before) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000599 // Find the actual limit to use.
600 var limit;
601 var before;
602 if (!IS_UNDEFINED(opt_limit)) {
603 limit = opt_limit;
604 } else {
605 limit = kLineLengthLimit;
606 }
607 if (!IS_UNDEFINED(opt_before)) {
608 before = opt_before;
609 } else {
610 // If no before is specified center for small limits and perfer more source
611 // before the the position that after for longer limits.
612 if (limit <= 20) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000613 before = $floor(limit / 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000614 } else {
615 before = limit - 10;
616 }
617 }
618 if (before >= limit) {
619 before = limit - 1;
620 }
621
622 // If the [start, end[ interval is too big we restrict
623 // it in one or both ends. We make sure to always produce
624 // restricted intervals of maximum allowed size.
625 if (this.end - this.start > limit) {
626 var start_limit = this.position - before;
627 var end_limit = this.position + limit - before;
628 if (this.start < start_limit && end_limit < this.end) {
629 this.start = start_limit;
630 this.end = end_limit;
631 } else if (this.start < start_limit) {
632 this.start = this.end - limit;
633 } else {
634 this.end = this.start + limit;
635 }
636 }
637};
638
639
640/**
641 * Get the source text for a SourceLocation
642 * @return {String}
643 * Source text for this location.
644 */
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000645function SourceLocationSourceText() {
whesse@chromium.org7a392b32011-01-31 11:30:36 +0000646 return %_CallFunction(this.script.source, this.start, this.end, StringSubstring);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000647};
648
649
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000650SetUpLockedPrototype(SourceLocation,
651 $Array("script", "position", "line", "column", "start", "end"),
652 $Array(
653 "restrict", SourceLocationRestrict,
654 "sourceText", SourceLocationSourceText
655 )
656);
657
658
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000659/**
660 * Class for a source slice. A source slice is a part of a script source with
661 * the following properties:
662 * script : script object for the source
663 * from_line : line number for the first line in the slice
664 * to_line : source line number for the last line in the slice
665 * from_position : position of the first character in the slice
666 * to_position : position of the last character in the slice
667 * The to_line and to_position are not included in the slice, that is the lines
668 * in the slice are [from_line, to_line[. Likewise the characters in the slice
669 * are [from_position, to_position[.
670 * @param {Script} script The Script object for the source slice
671 * @param {number} from_line
672 * @param {number} to_line
673 * @param {number} from_position
674 * @param {number} to_position
675 * @constructor
676 */
677function SourceSlice(script, from_line, to_line, from_position, to_position) {
678 this.script = script;
679 this.from_line = from_line;
680 this.to_line = to_line;
681 this.from_position = from_position;
682 this.to_position = to_position;
683}
684
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000685/**
686 * Get the source text for a SourceSlice
687 * @return {String} Source text for this slice. The last line will include
688 * the line terminating characters (if any)
689 */
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000690function SourceSliceSourceText() {
whesse@chromium.org7a392b32011-01-31 11:30:36 +0000691 return %_CallFunction(this.script.source,
692 this.from_position,
693 this.to_position,
694 StringSubstring);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000695};
696
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000697SetUpLockedPrototype(SourceSlice,
698 $Array("script", "from_line", "to_line", "from_position", "to_position"),
699 $Array("sourceText", SourceSliceSourceText)
700);
701
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000702
703// Returns the offset of the given position within the containing
704// line.
705function GetPositionInLine(message) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000706 var script = %MessageGetScript(message);
707 var start_position = %MessageGetStartPosition(message);
708 var location = script.locationFromPosition(start_position, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000709 if (location == null) return -1;
710 location.restrict();
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000711 return start_position - location.start;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000712}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000713
714
715function GetStackTraceLine(recv, fun, pos, isGlobal) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000716 return FormatSourcePosition(new CallSite(recv, fun, pos));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000717}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000718
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000719// ----------------------------------------------------------------------------
720// Error implementation
721
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000722// Defines accessors for a property that is calculated the first time
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000723// the property is read.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000724function DefineOneShotAccessor(obj, name, fun) {
725 // Note that the accessors consistently operate on 'obj', not 'this'.
726 // Since the object may occur in someone else's prototype chain we
727 // can't rely on 'this' being the same as 'obj'.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000728 var hasBeenSet = false;
729 var value;
whesse@chromium.org7b260152011-06-20 15:33:18 +0000730 function getter() {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000731 if (hasBeenSet) {
732 return value;
733 }
734 hasBeenSet = true;
735 value = fun(obj);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000736 return value;
whesse@chromium.org7b260152011-06-20 15:33:18 +0000737 }
738 function setter(v) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000739 hasBeenSet = true;
740 value = v;
whesse@chromium.org7b260152011-06-20 15:33:18 +0000741 }
742 var desc = { get: getter,
743 set: setter,
744 enumerable: false,
745 configurable: true };
746 desc = ToPropertyDescriptor(desc);
747 DefineOwnProperty(obj, name, desc, true);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000748}
749
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000750function CallSite(receiver, fun, pos) {
751 this.receiver = receiver;
752 this.fun = fun;
753 this.pos = pos;
754}
755
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000756function CallSiteGetThis() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000757 return this.receiver;
758};
759
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000760function CallSiteGetTypeName() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000761 var constructor = this.receiver.constructor;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000762 if (!constructor) {
whesse@chromium.org7a392b32011-01-31 11:30:36 +0000763 return %_CallFunction(this.receiver, ObjectToString);
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000764 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000765 var constructorName = constructor.name;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000766 if (!constructorName) {
whesse@chromium.org7a392b32011-01-31 11:30:36 +0000767 return %_CallFunction(this.receiver, ObjectToString);
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000768 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000769 return constructorName;
770};
771
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000772function CallSiteIsToplevel() {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000773 if (this.receiver == null) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000774 return true;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000775 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000776 return IS_GLOBAL(this.receiver);
777};
778
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000779function CallSiteIsEval() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000780 var script = %FunctionGetScript(this.fun);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000781 return script && script.compilation_type == COMPILATION_TYPE_EVAL;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000782};
783
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000784function CallSiteGetEvalOrigin() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000785 var script = %FunctionGetScript(this.fun);
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000786 return FormatEvalOrigin(script);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000787};
788
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000789function CallSiteGetScriptNameOrSourceURL() {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000790 var script = %FunctionGetScript(this.fun);
791 return script ? script.nameOrSourceURL() : null;
792};
793
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000794function CallSiteGetFunction() {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000795 return this.fun;
796};
797
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000798function CallSiteGetFunctionName() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000799 // See if the function knows its own name
800 var name = this.fun.name;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000801 if (name) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000802 return name;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000803 } else {
804 return %FunctionGetInferredName(this.fun);
805 }
806 // Maybe this is an evaluation?
807 var script = %FunctionGetScript(this.fun);
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000808 if (script && script.compilation_type == COMPILATION_TYPE_EVAL) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000809 return "eval";
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000810 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000811 return null;
812};
813
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000814function CallSiteGetMethodName() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000815 // See if we can find a unique property on the receiver that holds
816 // this function.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000817 var ownName = this.fun.name;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000818 if (ownName && this.receiver &&
whesse@chromium.org7a392b32011-01-31 11:30:36 +0000819 (%_CallFunction(this.receiver, ownName, ObjectLookupGetter) === this.fun ||
820 %_CallFunction(this.receiver, ownName, ObjectLookupSetter) === this.fun ||
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000821 this.receiver[ownName] === this.fun)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000822 // To handle DontEnum properties we guess that the method has
823 // the same name as the function.
824 return ownName;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000825 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000826 var name = null;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000827 for (var prop in this.receiver) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000828 if (this.receiver.__lookupGetter__(prop) === this.fun ||
829 this.receiver.__lookupSetter__(prop) === this.fun ||
830 (!this.receiver.__lookupGetter__(prop) && this.receiver[prop] === this.fun)) {
831 // If we find more than one match bail out to avoid confusion.
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000832 if (name) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000833 return null;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000834 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000835 name = prop;
836 }
837 }
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000838 if (name) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000839 return name;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000840 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000841 return null;
842};
843
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000844function CallSiteGetFileName() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000845 var script = %FunctionGetScript(this.fun);
846 return script ? script.name : null;
847};
848
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000849function CallSiteGetLineNumber() {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000850 if (this.pos == -1) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000851 return null;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000852 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000853 var script = %FunctionGetScript(this.fun);
854 var location = null;
855 if (script) {
856 location = script.locationFromPosition(this.pos, true);
857 }
858 return location ? location.line + 1 : null;
859};
860
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000861function CallSiteGetColumnNumber() {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000862 if (this.pos == -1) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000863 return null;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000864 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000865 var script = %FunctionGetScript(this.fun);
866 var location = null;
867 if (script) {
868 location = script.locationFromPosition(this.pos, true);
869 }
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000870 return location ? location.column + 1: null;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000871};
872
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000873function CallSiteIsNative() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000874 var script = %FunctionGetScript(this.fun);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000875 return script ? (script.type == TYPE_NATIVE) : false;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000876};
877
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000878function CallSiteGetPosition() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000879 return this.pos;
880};
881
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000882function CallSiteIsConstructor() {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000883 var constructor = this.receiver ? this.receiver.constructor : null;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000884 if (!constructor) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000885 return false;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000886 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000887 return this.fun === constructor;
888};
889
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000890SetUpLockedPrototype(CallSite, $Array("receiver", "fun", "pos"), $Array(
891 "getThis", CallSiteGetThis,
892 "getTypeName", CallSiteGetTypeName,
893 "isToplevel", CallSiteIsToplevel,
894 "isEval", CallSiteIsEval,
895 "getEvalOrigin", CallSiteGetEvalOrigin,
896 "getScriptNameOrSourceURL", CallSiteGetScriptNameOrSourceURL,
897 "getFunction", CallSiteGetFunction,
898 "getFunctionName", CallSiteGetFunctionName,
899 "getMethodName", CallSiteGetMethodName,
900 "getFileName", CallSiteGetFileName,
901 "getLineNumber", CallSiteGetLineNumber,
902 "getColumnNumber", CallSiteGetColumnNumber,
903 "isNative", CallSiteIsNative,
904 "getPosition", CallSiteGetPosition,
905 "isConstructor", CallSiteIsConstructor
906));
907
908
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000909function FormatEvalOrigin(script) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000910 var sourceURL = script.nameOrSourceURL();
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000911 if (sourceURL) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000912 return sourceURL;
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000913 }
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000914
915 var eval_origin = "eval at ";
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000916 if (script.eval_from_function_name) {
917 eval_origin += script.eval_from_function_name;
918 } else {
919 eval_origin += "<anonymous>";
920 }
lrn@chromium.org25156de2010-04-06 13:10:27 +0000921
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000922 var eval_from_script = script.eval_from_script;
923 if (eval_from_script) {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000924 if (eval_from_script.compilation_type == COMPILATION_TYPE_EVAL) {
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000925 // eval script originated from another eval.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000926 eval_origin += " (" + FormatEvalOrigin(eval_from_script) + ")";
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000927 } else {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000928 // eval script originated from "real" source.
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000929 if (eval_from_script.name) {
930 eval_origin += " (" + eval_from_script.name;
931 var location = eval_from_script.locationFromPosition(script.eval_from_script_position, true);
932 if (location) {
933 eval_origin += ":" + (location.line + 1);
934 eval_origin += ":" + (location.column + 1);
935 }
936 eval_origin += ")"
937 } else {
938 eval_origin += " (unknown source)";
939 }
940 }
941 }
lrn@chromium.org25156de2010-04-06 13:10:27 +0000942
sgjesse@chromium.org98180592009-12-02 08:17:28 +0000943 return eval_origin;
944};
945
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000946function FormatSourcePosition(frame) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000947 var fileName;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000948 var fileLocation = "";
949 if (frame.isNative()) {
950 fileLocation = "native";
951 } else if (frame.isEval()) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000952 fileName = frame.getScriptNameOrSourceURL();
953 if (!fileName)
954 fileLocation = frame.getEvalOrigin();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000955 } else {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000956 fileName = frame.getFileName();
957 }
958
959 if (fileName) {
960 fileLocation += fileName;
961 var lineNumber = frame.getLineNumber();
962 if (lineNumber != null) {
963 fileLocation += ":" + lineNumber;
964 var columnNumber = frame.getColumnNumber();
965 if (columnNumber) {
966 fileLocation += ":" + columnNumber;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000967 }
968 }
969 }
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000970
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000971 if (!fileLocation) {
972 fileLocation = "unknown source";
973 }
974 var line = "";
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000975 var functionName = frame.getFunction().name;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000976 var addPrefix = true;
977 var isConstructor = frame.isConstructor();
978 var isMethodCall = !(frame.isToplevel() || isConstructor);
979 if (isMethodCall) {
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000980 var methodName = frame.getMethodName();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000981 line += frame.getTypeName() + ".";
982 if (functionName) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000983 line += functionName;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000984 if (methodName && (methodName != functionName)) {
985 line += " [as " + methodName + "]";
986 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000987 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000988 line += methodName || "<anonymous>";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000989 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000990 } else if (isConstructor) {
991 line += "new " + (functionName || "<anonymous>");
992 } else if (functionName) {
993 line += functionName;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000994 } else {
995 line += fileLocation;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000996 addPrefix = false;
997 }
998 if (addPrefix) {
999 line += " (" + fileLocation + ")";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001000 }
1001 return line;
1002}
1003
1004function FormatStackTrace(error, frames) {
1005 var lines = [];
1006 try {
1007 lines.push(error.toString());
1008 } catch (e) {
1009 try {
1010 lines.push("<error: " + e + ">");
1011 } catch (ee) {
1012 lines.push("<error>");
1013 }
1014 }
1015 for (var i = 0; i < frames.length; i++) {
1016 var frame = frames[i];
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001017 var line;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001018 try {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001019 line = FormatSourcePosition(frame);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001020 } catch (e) {
1021 try {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001022 line = "<error: " + e + ">";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001023 } catch (ee) {
1024 // Any code that reaches this point is seriously nasty!
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001025 line = "<error>";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001026 }
1027 }
1028 lines.push(" at " + line);
1029 }
1030 return lines.join("\n");
1031}
1032
1033function FormatRawStackTrace(error, raw_stack) {
1034 var frames = [ ];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001035 for (var i = 0; i < raw_stack.length; i += 4) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001036 var recv = raw_stack[i];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001037 var fun = raw_stack[i + 1];
1038 var code = raw_stack[i + 2];
1039 var pc = raw_stack[i + 3];
1040 var pos = %FunctionGetPositionForOffset(code, pc);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001041 frames.push(new CallSite(recv, fun, pos));
1042 }
1043 if (IS_FUNCTION($Error.prepareStackTrace)) {
1044 return $Error.prepareStackTrace(error, frames);
1045 } else {
1046 return FormatStackTrace(error, frames);
1047 }
1048}
1049
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001050
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001051function captureStackTrace(obj, cons_opt) {
1052 var stackTraceLimit = $Error.stackTraceLimit;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001053 if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return;
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001054 if (stackTraceLimit < 0 || stackTraceLimit > 10000) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001055 stackTraceLimit = 10000;
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001056 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001057 var raw_stack = %CollectStackTrace(cons_opt
1058 ? cons_opt
1059 : captureStackTrace, stackTraceLimit);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001060 DefineOneShotAccessor(obj, 'stack', function (obj) {
1061 return FormatRawStackTrace(obj, raw_stack);
1062 });
1063};
1064
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001065
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001066function SetUpError() {
1067 // Define special error type constructors.
1068
1069 function DefineError(f) {
1070 // Store the error function in both the global object
1071 // and the runtime object. The function is fetched
1072 // from the runtime object when throwing errors from
1073 // within the runtime system to avoid strange side
1074 // effects when overwriting the error functions from
1075 // user code.
1076 var name = f.name;
1077 %SetProperty(global, name, f, DONT_ENUM);
1078 %SetProperty(builtins, '$' + name, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
1079 // Configure the error function.
1080 if (name == 'Error') {
1081 // The prototype of the Error object must itself be an error.
1082 // However, it can't be an instance of the Error object because
1083 // it hasn't been properly configured yet. Instead we create a
1084 // special not-a-true-error-but-close-enough object.
1085 function ErrorPrototype() {}
1086 %FunctionSetPrototype(ErrorPrototype, $Object.prototype);
1087 %FunctionSetInstanceClassName(ErrorPrototype, 'Error');
1088 %FunctionSetPrototype(f, new ErrorPrototype());
1089 } else {
1090 %FunctionSetPrototype(f, new $Error());
1091 }
1092 %FunctionSetInstanceClassName(f, 'Error');
1093 %SetProperty(f.prototype, 'constructor', f, DONT_ENUM);
1094 // The name property on the prototype of error objects is not
1095 // specified as being read-one and dont-delete. However, allowing
1096 // overwriting allows leaks of error objects between script blocks
1097 // in the same context in a browser setting. Therefore we fix the
1098 // name.
1099 %SetProperty(f.prototype, "name", name,
1100 DONT_ENUM | DONT_DELETE | READ_ONLY) ;
1101 %SetCode(f, function(m) {
1102 if (%_IsConstructCall()) {
1103 // Define all the expected properties directly on the error
1104 // object. This avoids going through getters and setters defined
1105 // on prototype objects.
1106 %IgnoreAttributesAndSetProperty(this, 'stack', void 0, DONT_ENUM);
1107 %IgnoreAttributesAndSetProperty(this, 'arguments', void 0, DONT_ENUM);
1108 %IgnoreAttributesAndSetProperty(this, 'type', void 0, DONT_ENUM);
1109 if (m === kAddMessageAccessorsMarker) {
1110 // DefineOneShotAccessor always inserts a message property and
1111 // ignores setters.
1112 DefineOneShotAccessor(this, 'message', function (obj) {
1113 return FormatMessage(%NewMessageObject(obj.type, obj.arguments));
1114 });
1115 } else if (!IS_UNDEFINED(m)) {
1116 %IgnoreAttributesAndSetProperty(this,
1117 'message',
1118 ToString(m),
1119 DONT_ENUM);
1120 }
1121 captureStackTrace(this, f);
1122 } else {
1123 return new f(m);
1124 }
1125 });
1126 }
1127
1128 DefineError(function Error() { });
1129 DefineError(function TypeError() { });
1130 DefineError(function RangeError() { });
1131 DefineError(function SyntaxError() { });
1132 DefineError(function ReferenceError() { });
1133 DefineError(function EvalError() { });
1134 DefineError(function URIError() { });
1135}
1136
1137SetUpError();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001138
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001139$Error.captureStackTrace = captureStackTrace;
1140
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001141%SetProperty($Error.prototype, 'message', '', DONT_ENUM);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001142
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001143// Global list of error objects visited during errorToString. This is
1144// used to detect cycles in error toString formatting.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001145const visited_errors = new InternalArray();
1146const cyclic_error_marker = new $Object();
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001147
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001148function errorToStringDetectCycle(error) {
1149 if (!%PushIfAbsent(visited_errors, error)) throw cyclic_error_marker;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001150 try {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001151 var type = error.type;
1152 var hasMessage = %_CallFunction(error, "message", ObjectHasOwnProperty);
1153 if (type && !hasMessage) {
1154 var formatted = FormatMessage(%NewMessageObject(type, error.arguments));
1155 return error.name + ": " + formatted;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001156 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001157 var message = hasMessage ? (": " + error.message) : "";
1158 return error.name + message;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001159 } finally {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001160 visited_errors.length = visited_errors.length - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001161 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001162}
1163
1164function errorToString() {
lrn@chromium.org1c092762011-05-09 09:42:16 +00001165 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
1166 throw MakeTypeError("called_on_null_or_undefined",
1167 ["Error.prototype.toString"]);
1168 }
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001169 // This helper function is needed because access to properties on
1170 // the builtins object do not work inside of a catch clause.
1171 function isCyclicErrorMarker(o) { return o === cyclic_error_marker; }
1172
1173 try {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001174 return errorToStringDetectCycle(this);
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001175 } catch(e) {
1176 // If this error message was encountered already return the empty
1177 // string for it instead of recursively formatting it.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001178 if (isCyclicErrorMarker(e)) {
1179 return '';
1180 }
1181 throw e;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001182 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001183}
1184
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001185
1186InstallFunctions($Error.prototype, DONT_ENUM, ['toString', errorToString]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001187
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001188// Boilerplate for exceptions for stack overflows. Used from
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001189// Isolate::StackOverflow().
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001190const kStackOverflowBoilerplate = MakeRangeError('stack_overflow', []);