1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
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.
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.
28 // -------------------------------------------------------------------
30 // If this object gets passed to an error constructor the error will
31 // get an accessor for .message that constructs a descriptive error
33 var kAddMessageAccessorsMarker = { };
35 // This will be lazily initialized when first needed (and forcibly
36 // overwritten even though it's const).
39 function FormatString(format, message) {
40 var args = %MessageGetArguments(message);
43 for (var i = 0; i < format.length; i++) {
45 if (str.length == 2 && %_StringCharCodeAt(str, 0) == 0x25) {
46 // Two-char string starts with "%".
47 var arg_num = (%_StringCharCodeAt(str, 1) - 0x30) >>> 0;
49 // str is one of %0, %1, %2 or %3.
51 str = ToDetailString(args[arg_num]);
63 // To check if something is a native error we need to check the
64 // concrete native error types. It is not sufficient to use instanceof
65 // since it possible to create an object that has Error.prototype on
66 // its prototype chain. This is the case for DOMException for example.
67 function IsNativeErrorObject(obj) {
68 switch (%_ClassOf(obj)) {
72 case 'ReferenceError':
82 // When formatting internally created error messages, do not
83 // invoke overwritten error toString methods but explicitly use
84 // the error to string method. This is to avoid leaking error
85 // objects between script tags in a browser setting.
86 function ToStringCheckErrorObject(obj) {
87 if (IsNativeErrorObject(obj)) {
88 return %_CallFunction(obj, ErrorToString);
95 function ToDetailString(obj) {
96 if (obj != null && IS_OBJECT(obj) && obj.toString === ObjectToString) {
97 var constructor = obj.constructor;
98 if (typeof constructor == "function") {
99 var constructorName = constructor.name;
100 if (IS_STRING(constructorName) && constructorName !== "") {
101 return "#<" + constructorName + ">";
105 return ToStringCheckErrorObject(obj);
109 function MakeGenericError(constructor, type, args) {
110 if (IS_UNDEFINED(args)) {
113 var e = new constructor(kAddMessageAccessorsMarker);
121 * Set up the Script function and constructor.
123 %FunctionSetInstanceClassName(Script, 'Script');
124 %SetProperty(Script.prototype, 'constructor', Script,
125 DONT_ENUM | DONT_DELETE | READ_ONLY);
126 %SetCode(Script, function(x) {
127 // Script objects can only be created by the VM.
128 throw new $Error("Not supported");
132 // Helper functions; called from the runtime system.
133 function FormatMessage(message) {
134 if (kMessages === 0) {
135 var messagesDictionary = [
137 "cyclic_proto", ["Cyclic __proto__ value"],
138 "code_gen_from_strings", ["Code generation from strings disallowed for this context"],
140 "unexpected_token", ["Unexpected token ", "%0"],
141 "unexpected_token_number", ["Unexpected number"],
142 "unexpected_token_string", ["Unexpected string"],
143 "unexpected_token_identifier", ["Unexpected identifier"],
144 "unexpected_reserved", ["Unexpected reserved word"],
145 "unexpected_strict_reserved", ["Unexpected strict mode reserved word"],
146 "unexpected_eos", ["Unexpected end of input"],
147 "malformed_regexp", ["Invalid regular expression: /", "%0", "/: ", "%1"],
148 "unterminated_regexp", ["Invalid regular expression: missing /"],
149 "regexp_flags", ["Cannot supply flags when constructing one RegExp from another"],
150 "incompatible_method_receiver", ["Method ", "%0", " called on incompatible receiver ", "%1"],
151 "invalid_lhs_in_assignment", ["Invalid left-hand side in assignment"],
152 "invalid_lhs_in_for_in", ["Invalid left-hand side in for-in"],
153 "invalid_lhs_in_postfix_op", ["Invalid left-hand side expression in postfix operation"],
154 "invalid_lhs_in_prefix_op", ["Invalid left-hand side expression in prefix operation"],
155 "multiple_defaults_in_switch", ["More than one default clause in switch statement"],
156 "newline_after_throw", ["Illegal newline after throw"],
157 "redeclaration", ["%0", " '", "%1", "' has already been declared"],
158 "no_catch_or_finally", ["Missing catch or finally after try"],
159 "unknown_label", ["Undefined label '", "%0", "'"],
160 "uncaught_exception", ["Uncaught ", "%0"],
161 "stack_trace", ["Stack Trace:\n", "%0"],
162 "called_non_callable", ["%0", " is not a function"],
163 "undefined_method", ["Object ", "%1", " has no method '", "%0", "'"],
164 "property_not_function", ["Property '", "%0", "' of object ", "%1", " is not a function"],
165 "cannot_convert_to_primitive", ["Cannot convert object to primitive value"],
166 "not_constructor", ["%0", " is not a constructor"],
167 "not_defined", ["%0", " is not defined"],
168 "non_object_property_load", ["Cannot read property '", "%0", "' of ", "%1"],
169 "non_object_property_store", ["Cannot set property '", "%0", "' of ", "%1"],
170 "non_object_property_call", ["Cannot call method '", "%0", "' of ", "%1"],
171 "with_expression", ["%0", " has no properties"],
172 "illegal_invocation", ["Illegal invocation"],
173 "no_setter_in_callback", ["Cannot set property ", "%0", " of ", "%1", " which has only a getter"],
174 "apply_non_function", ["Function.prototype.apply was called on ", "%0", ", which is a ", "%1", " and not a function"],
175 "apply_wrong_args", ["Function.prototype.apply: Arguments list has wrong type"],
176 "invalid_in_operator_use", ["Cannot use 'in' operator to search for '", "%0", "' in ", "%1"],
177 "instanceof_function_expected", ["Expecting a function in instanceof check, but got ", "%0"],
178 "instanceof_nonobject_proto", ["Function has non-object prototype '", "%0", "' in instanceof check"],
179 "null_to_object", ["Cannot convert null to object"],
180 "reduce_no_initial", ["Reduce of empty array with no initial value"],
181 "getter_must_be_callable", ["Getter must be a function: ", "%0"],
182 "setter_must_be_callable", ["Setter must be a function: ", "%0"],
183 "value_and_accessor", ["Invalid property. A property cannot both have accessors and be writable or have a value, ", "%0"],
184 "proto_object_or_null", ["Object prototype may only be an Object or null"],
185 "property_desc_object", ["Property description must be an object: ", "%0"],
186 "redefine_disallowed", ["Cannot redefine property: ", "%0"],
187 "define_disallowed", ["Cannot define property:", "%0", ", object is not extensible."],
188 "non_extensible_proto", ["%0", " is not extensible"],
189 "handler_non_object", ["Proxy.", "%0", " called with non-object as handler"],
190 "proto_non_object", ["Proxy.", "%0", " called with non-object as prototype"],
191 "trap_function_expected", ["Proxy.", "%0", " called with non-function for '", "%1", "' trap"],
192 "handler_trap_missing", ["Proxy handler ", "%0", " has no '", "%1", "' trap"],
193 "handler_trap_must_be_callable", ["Proxy handler ", "%0", " has non-callable '", "%1", "' trap"],
194 "handler_returned_false", ["Proxy handler ", "%0", " returned false from '", "%1", "' trap"],
195 "handler_returned_undefined", ["Proxy handler ", "%0", " returned undefined from '", "%1", "' trap"],
196 "proxy_prop_not_configurable", ["Proxy handler ", "%0", " returned non-configurable descriptor for property '", "%2", "' from '", "%1", "' trap"],
197 "proxy_non_object_prop_names", ["Trap '", "%1", "' returned non-object ", "%0"],
198 "proxy_repeated_prop_name", ["Trap '", "%1", "' returned repeated property name '", "%2", "'"],
199 "invalid_weakmap_key", ["Invalid value used as weak map key"],
201 "invalid_array_length", ["Invalid array length"],
202 "stack_overflow", ["Maximum call stack size exceeded"],
203 "invalid_time_value", ["Invalid time value"],
205 "unable_to_parse", ["Parse error"],
206 "invalid_regexp_flags", ["Invalid flags supplied to RegExp constructor '", "%0", "'"],
207 "invalid_regexp", ["Invalid RegExp pattern /", "%0", "/"],
208 "illegal_break", ["Illegal break statement"],
209 "illegal_continue", ["Illegal continue statement"],
210 "illegal_return", ["Illegal return statement"],
211 "illegal_let", ["Illegal let declaration outside extended mode"],
212 "error_loading_debugger", ["Error loading debugger"],
213 "no_input_to_regexp", ["No input to ", "%0"],
214 "invalid_json", ["String '", "%0", "' is not valid JSON"],
215 "circular_structure", ["Converting circular structure to JSON"],
216 "called_on_non_object", ["%0", " called on non-object"],
217 "called_on_null_or_undefined", ["%0", " called on null or undefined"],
218 "array_indexof_not_defined", ["Array.getIndexOf: Argument undefined"],
219 "object_not_extensible", ["Can't add property ", "%0", ", object is not extensible"],
220 "illegal_access", ["Illegal access"],
221 "invalid_preparser_data", ["Invalid preparser data for function ", "%0"],
222 "strict_mode_with", ["Strict mode code may not include a with statement"],
223 "strict_catch_variable", ["Catch variable may not be eval or arguments in strict mode"],
224 "too_many_arguments", ["Too many arguments in function call (only 32766 allowed)"],
225 "too_many_parameters", ["Too many parameters in function definition (only 32766 allowed)"],
226 "too_many_variables", ["Too many variables declared (only 32767 allowed)"],
227 "strict_param_name", ["Parameter name eval or arguments is not allowed in strict mode"],
228 "strict_param_dupe", ["Strict mode function may not have duplicate parameter names"],
229 "strict_var_name", ["Variable name may not be eval or arguments in strict mode"],
230 "strict_function_name", ["Function name may not be eval or arguments in strict mode"],
231 "strict_octal_literal", ["Octal literals are not allowed in strict mode."],
232 "strict_duplicate_property", ["Duplicate data property in object literal not allowed in strict mode"],
233 "accessor_data_property", ["Object literal may not have data and accessor property with the same name"],
234 "accessor_get_set", ["Object literal may not have multiple get/set accessors with the same name"],
235 "strict_lhs_assignment", ["Assignment to eval or arguments is not allowed in strict mode"],
236 "strict_lhs_postfix", ["Postfix increment/decrement may not have eval or arguments operand in strict mode"],
237 "strict_lhs_prefix", ["Prefix increment/decrement may not have eval or arguments operand in strict mode"],
238 "strict_reserved_word", ["Use of future reserved word in strict mode"],
239 "strict_delete", ["Delete of an unqualified identifier in strict mode."],
240 "strict_delete_property", ["Cannot delete property '", "%0", "' of ", "%1"],
241 "strict_const", ["Use of const in strict mode."],
242 "strict_function", ["In strict mode code, functions can only be declared at top level or immediately within another function." ],
243 "strict_read_only_property", ["Cannot assign to read only property '", "%0", "' of ", "%1"],
244 "strict_cannot_assign", ["Cannot assign to read only '", "%0", "' in strict mode"],
245 "strict_poison_pill", ["'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them"],
246 "strict_caller", ["Illegal access to a strict mode caller function."],
247 "unprotected_let", ["Illegal let declaration in unprotected statement context."],
248 "unprotected_const", ["Illegal const declaration in unprotected statement context."],
249 "cant_prevent_ext_external_array_elements", ["Cannot prevent extension of an object with external array elements"],
250 "redef_external_array_element", ["Cannot redefine a property of an object with external array elements"],
251 "harmony_const_assign", ["Assignment to constant variable."],
252 "invalid_module_path", ["Module does not export '", "%0", "', or export is not itself a module"],
253 "module_type_error", ["Module '", "%0", "' used improperly"],
255 var messages = { __proto__ : null };
256 for (var i = 0; i < messagesDictionary.length; i += 2) {
257 var key = messagesDictionary[i];
258 var format = messagesDictionary[i + 1];
260 for (var j = 0; j < format.length; j++) {
261 %IgnoreAttributesAndSetProperty(format, %_NumberToString(j), format[j],
262 DONT_DELETE | READ_ONLY | DONT_ENUM);
264 %IgnoreAttributesAndSetProperty(format, 'length', format.length,
265 DONT_DELETE | READ_ONLY | DONT_ENUM);
266 %PreventExtensions(format);
267 %IgnoreAttributesAndSetProperty(messages,
270 DONT_DELETE | DONT_ENUM | READ_ONLY);
272 %PreventExtensions(messages);
273 %IgnoreAttributesAndSetProperty(builtins, "kMessages",
275 DONT_DELETE | DONT_ENUM | READ_ONLY);
277 var message_type = %MessageGetType(message);
278 var format = kMessages[message_type];
279 if (!format) return "<unknown message " + message_type + ">";
280 return FormatString(format, message);
284 function GetLineNumber(message) {
285 var start_position = %MessageGetStartPosition(message);
286 if (start_position == -1) return kNoLineNumberInfo;
287 var script = %MessageGetScript(message);
288 var location = script.locationFromPosition(start_position, true);
289 if (location == null) return kNoLineNumberInfo;
290 return location.line + 1;
294 // Returns the source code line containing the given source
295 // position, or the empty string if the position is invalid.
296 function GetSourceLine(message) {
297 var script = %MessageGetScript(message);
298 var start_position = %MessageGetStartPosition(message);
299 var location = script.locationFromPosition(start_position, true);
300 if (location == null) return "";
302 return location.sourceText();
306 function MakeTypeError(type, args) {
307 return MakeGenericError($TypeError, type, args);
311 function MakeRangeError(type, args) {
312 return MakeGenericError($RangeError, type, args);
316 function MakeSyntaxError(type, args) {
317 return MakeGenericError($SyntaxError, type, args);
321 function MakeReferenceError(type, args) {
322 return MakeGenericError($ReferenceError, type, args);
326 function MakeEvalError(type, args) {
327 return MakeGenericError($EvalError, type, args);
331 function MakeError(type, args) {
332 return MakeGenericError($Error, type, args);
336 * Find a line number given a specific source position.
337 * @param {number} position The source position.
338 * @return {number} 0 if input too small, -1 if input too large,
339 else the line number.
341 function ScriptLineFromPosition(position) {
343 var upper = this.lineCount() - 1;
344 var line_ends = this.line_ends;
346 // We'll never find invalid positions so bail right away.
347 if (position > line_ends[upper]) {
351 // This means we don't have to safe-guard indexing line_ends[i - 1].
352 if (position <= line_ends[0]) {
356 // Binary search to find line # from position range.
358 var i = (lower + upper) >> 1;
360 if (position > line_ends[i]) {
362 } else if (position <= line_ends[i - 1]) {
373 * Get information on a specific source position.
374 * @param {number} position The source position
375 * @param {boolean} include_resource_offset Set to true to have the resource
376 * offset added to the location
377 * @return {SourceLocation}
378 * If line is negative or not in the source null is returned.
380 function ScriptLocationFromPosition(position,
381 include_resource_offset) {
382 var line = this.lineFromPosition(position);
383 if (line == -1) return null;
385 // Determine start, end and column.
386 var line_ends = this.line_ends;
387 var start = line == 0 ? 0 : line_ends[line - 1] + 1;
388 var end = line_ends[line];
389 if (end > 0 && %_CallFunction(this.source, end - 1, StringCharAt) == '\r') {
392 var column = position - start;
394 // Adjust according to the offset within the resource.
395 if (include_resource_offset) {
396 line += this.line_offset;
397 if (line == this.line_offset) {
398 column += this.column_offset;
402 return new SourceLocation(this, position, line, column, start, end);
407 * Get information on a specific source line and column possibly offset by a
408 * fixed source position. This function is used to find a source position from
409 * a line and column position. The fixed source position offset is typically
410 * used to find a source position in a function based on a line and column in
411 * the source for the function alone. The offset passed will then be the
412 * start position of the source for the function within the full script source.
413 * @param {number} opt_line The line within the source. Default value is 0
414 * @param {number} opt_column The column in within the line. Default value is 0
415 * @param {number} opt_offset_position The offset from the begining of the
416 * source from where the line and column calculation starts.
418 * @return {SourceLocation}
419 * If line is negative or not in the source null is returned.
421 function ScriptLocationFromLine(opt_line, opt_column, opt_offset_position) {
422 // Default is the first line in the script. Lines in the script is relative
423 // to the offset within the resource.
425 if (!IS_UNDEFINED(opt_line)) {
426 line = opt_line - this.line_offset;
429 // Default is first column. If on the first line add the offset within the
431 var column = opt_column || 0;
433 column -= this.column_offset;
436 var offset_position = opt_offset_position || 0;
437 if (line < 0 || column < 0 || offset_position < 0) return null;
439 return this.locationFromPosition(offset_position + column, false);
441 // Find the line where the offset position is located.
442 var offset_line = this.lineFromPosition(offset_position);
444 if (offset_line == -1 || offset_line + line >= this.lineCount()) {
448 return this.locationFromPosition(
449 this.line_ends[offset_line + line - 1] + 1 + column); // line > 0 here.
455 * Get a slice of source code from the script. The boundaries for the slice is
456 * specified in lines.
457 * @param {number} opt_from_line The first line (zero bound) in the slice.
459 * @param {number} opt_to_column The last line (zero bound) in the slice (non
460 * inclusive). Default is the number of lines in the script
461 * @return {SourceSlice} The source slice or null of the parameters where
464 function ScriptSourceSlice(opt_from_line, opt_to_line) {
465 var from_line = IS_UNDEFINED(opt_from_line) ? this.line_offset
467 var to_line = IS_UNDEFINED(opt_to_line) ? this.line_offset + this.lineCount()
470 // Adjust according to the offset within the resource.
471 from_line -= this.line_offset;
472 to_line -= this.line_offset;
473 if (from_line < 0) from_line = 0;
474 if (to_line > this.lineCount()) to_line = this.lineCount();
477 if (from_line >= this.lineCount() ||
479 from_line > to_line) {
483 var line_ends = this.line_ends;
484 var from_position = from_line == 0 ? 0 : line_ends[from_line - 1] + 1;
485 var to_position = to_line == 0 ? 0 : line_ends[to_line - 1] + 1;
487 // Return a source slice with line numbers re-adjusted to the resource.
488 return new SourceSlice(this,
489 from_line + this.line_offset,
490 to_line + this.line_offset,
491 from_position, to_position);
495 function ScriptSourceLine(opt_line) {
496 // Default is the first line in the script. Lines in the script are relative
497 // to the offset within the resource.
499 if (!IS_UNDEFINED(opt_line)) {
500 line = opt_line - this.line_offset;
504 if (line < 0 || this.lineCount() <= line) {
508 // Return the source line.
509 var line_ends = this.line_ends;
510 var start = line == 0 ? 0 : line_ends[line - 1] + 1;
511 var end = line_ends[line];
512 return %_CallFunction(this.source, start, end, StringSubstring);
517 * Returns the number of source lines.
519 * Number of source lines.
521 function ScriptLineCount() {
522 // Return number of source lines.
523 return this.line_ends.length;
528 * Returns the name of script if available, contents of sourceURL comment
530 * http://fbug.googlecode.com/svn/branches/firebug1.1/docs/ReleaseNotes_1.1.txt
531 * for details on using //@ sourceURL comment to identify scritps that don't
534 * @return {?string} script name if present, value for //@ sourceURL comment
537 function ScriptNameOrSourceURL() {
542 // The result is cached as on long scripts it takes noticable time to search
543 // for the sourceURL.
544 if (this.hasCachedNameOrSourceURL)
545 return this.cachedNameOrSourceURL;
546 this.hasCachedNameOrSourceURL = true;
548 // TODO(608): the spaces in a regexp below had to be escaped as \040
549 // because this file is being processed by js2c whose handling of spaces
550 // in regexps is broken. Also, ['"] are excluded from allowed URLs to
551 // avoid matches against sources that invoke evals with sourceURL.
552 // A better solution would be to detect these special comments in
553 // the scanner/parser.
554 var source = ToString(this.source);
555 var sourceUrlPos = %StringIndexOf(source, "sourceURL=", 0);
556 this.cachedNameOrSourceURL = this.name;
557 if (sourceUrlPos > 4) {
558 var sourceUrlPattern =
559 /\/\/@[\040\t]sourceURL=[\040\t]*([^\s\'\"]*)[\040\t]*$/gm;
560 // Don't reuse lastMatchInfo here, so we create a new array with room
561 // for four captures (array with length one longer than the index
562 // of the fourth capture, where the numbering is zero-based).
563 var matchInfo = new InternalArray(CAPTURE(3) + 1);
565 %_RegExpExec(sourceUrlPattern, source, sourceUrlPos - 4, matchInfo);
567 this.cachedNameOrSourceURL =
568 SubString(source, matchInfo[CAPTURE(2)], matchInfo[CAPTURE(3)]);
571 return this.cachedNameOrSourceURL;
575 SetUpLockedPrototype(Script,
576 $Array("source", "name", "line_ends", "line_offset", "column_offset",
577 "cachedNameOrSourceURL", "hasCachedNameOrSourceURL" ),
579 "lineFromPosition", ScriptLineFromPosition,
580 "locationFromPosition", ScriptLocationFromPosition,
581 "locationFromLine", ScriptLocationFromLine,
582 "sourceSlice", ScriptSourceSlice,
583 "sourceLine", ScriptSourceLine,
584 "lineCount", ScriptLineCount,
585 "nameOrSourceURL", ScriptNameOrSourceURL
591 * Class for source location. A source location is a position within some
592 * source with the following properties:
593 * script : script object for the source
594 * line : source line number
595 * column : source column within the line
596 * position : position within the source
597 * start : position of start of source context (inclusive)
598 * end : position of end of source context (not inclusive)
599 * Source text for the source context is the character interval
600 * [start, end[. In most cases end will point to a newline character.
601 * It might point just past the final position of the source if the last
602 * source line does not end with a newline character.
603 * @param {Script} script The Script object for which this is a location
604 * @param {number} position Source position for the location
605 * @param {number} line The line number for the location
606 * @param {number} column The column within the line for the location
607 * @param {number} start Source position for start of source context
608 * @param {number} end Source position for end of source context
611 function SourceLocation(script, position, line, column, start, end) {
612 this.script = script;
613 this.position = position;
615 this.column = column;
620 var kLineLengthLimit = 78;
623 * Restrict source location start and end positions to make the source slice
624 * no more that a certain number of characters wide.
625 * @param {number} opt_limit The with limit of the source text with a default
627 * @param {number} opt_before The number of characters to prefer before the
628 * position with a default value of 10 less that the limit
630 function SourceLocationRestrict(opt_limit, opt_before) {
631 // Find the actual limit to use.
634 if (!IS_UNDEFINED(opt_limit)) {
637 limit = kLineLengthLimit;
639 if (!IS_UNDEFINED(opt_before)) {
642 // If no before is specified center for small limits and perfer more source
643 // before the the position that after for longer limits.
645 before = $floor(limit / 2);
650 if (before >= limit) {
654 // If the [start, end[ interval is too big we restrict
655 // it in one or both ends. We make sure to always produce
656 // restricted intervals of maximum allowed size.
657 if (this.end - this.start > limit) {
658 var start_limit = this.position - before;
659 var end_limit = this.position + limit - before;
660 if (this.start < start_limit && end_limit < this.end) {
661 this.start = start_limit;
662 this.end = end_limit;
663 } else if (this.start < start_limit) {
664 this.start = this.end - limit;
666 this.end = this.start + limit;
673 * Get the source text for a SourceLocation
675 * Source text for this location.
677 function SourceLocationSourceText() {
678 return %_CallFunction(this.script.source,
685 SetUpLockedPrototype(SourceLocation,
686 $Array("script", "position", "line", "column", "start", "end"),
688 "restrict", SourceLocationRestrict,
689 "sourceText", SourceLocationSourceText
695 * Class for a source slice. A source slice is a part of a script source with
696 * the following properties:
697 * script : script object for the source
698 * from_line : line number for the first line in the slice
699 * to_line : source line number for the last line in the slice
700 * from_position : position of the first character in the slice
701 * to_position : position of the last character in the slice
702 * The to_line and to_position are not included in the slice, that is the lines
703 * in the slice are [from_line, to_line[. Likewise the characters in the slice
704 * are [from_position, to_position[.
705 * @param {Script} script The Script object for the source slice
706 * @param {number} from_line
707 * @param {number} to_line
708 * @param {number} from_position
709 * @param {number} to_position
712 function SourceSlice(script, from_line, to_line, from_position, to_position) {
713 this.script = script;
714 this.from_line = from_line;
715 this.to_line = to_line;
716 this.from_position = from_position;
717 this.to_position = to_position;
721 * Get the source text for a SourceSlice
722 * @return {String} Source text for this slice. The last line will include
723 * the line terminating characters (if any)
725 function SourceSliceSourceText() {
726 return %_CallFunction(this.script.source,
732 SetUpLockedPrototype(SourceSlice,
733 $Array("script", "from_line", "to_line", "from_position", "to_position"),
734 $Array("sourceText", SourceSliceSourceText)
738 // Returns the offset of the given position within the containing
740 function GetPositionInLine(message) {
741 var script = %MessageGetScript(message);
742 var start_position = %MessageGetStartPosition(message);
743 var location = script.locationFromPosition(start_position, false);
744 if (location == null) return -1;
746 return start_position - location.start;
750 function GetStackTraceLine(recv, fun, pos, isGlobal) {
751 return new CallSite(recv, fun, pos).toString();
754 // ----------------------------------------------------------------------------
755 // Error implementation
757 // Defines accessors for a property that is calculated the first time
758 // the property is read.
759 function DefineOneShotAccessor(obj, name, fun) {
760 // Note that the accessors consistently operate on 'obj', not 'this'.
761 // Since the object may occur in someone else's prototype chain we
762 // can't rely on 'this' being the same as 'obj'.
763 var hasBeenSet = false;
765 var getter = function() {
773 var setter = function(v) {
777 %DefineOrRedefineAccessorProperty(obj, name, getter, setter, DONT_ENUM);
780 function CallSite(receiver, fun, pos) {
781 this.receiver = receiver;
786 function CallSiteGetThis() {
787 return this.receiver;
790 function CallSiteGetTypeName() {
791 var constructor = this.receiver.constructor;
793 return %_CallFunction(this.receiver, ObjectToString);
795 var constructorName = constructor.name;
796 if (!constructorName) {
797 return %_CallFunction(this.receiver, ObjectToString);
799 return constructorName;
802 function CallSiteIsToplevel() {
803 if (this.receiver == null) {
806 return IS_GLOBAL(this.receiver);
809 function CallSiteIsEval() {
810 var script = %FunctionGetScript(this.fun);
811 return script && script.compilation_type == COMPILATION_TYPE_EVAL;
814 function CallSiteGetEvalOrigin() {
815 var script = %FunctionGetScript(this.fun);
816 return FormatEvalOrigin(script);
819 function CallSiteGetScriptNameOrSourceURL() {
820 var script = %FunctionGetScript(this.fun);
821 return script ? script.nameOrSourceURL() : null;
824 function CallSiteGetFunction() {
828 function CallSiteGetFunctionName() {
829 // See if the function knows its own name
830 var name = this.fun.name;
834 return %FunctionGetInferredName(this.fun);
836 // Maybe this is an evaluation?
837 var script = %FunctionGetScript(this.fun);
838 if (script && script.compilation_type == COMPILATION_TYPE_EVAL) {
844 function CallSiteGetMethodName() {
845 // See if we can find a unique property on the receiver that holds
847 var ownName = this.fun.name;
848 if (ownName && this.receiver &&
849 (%_CallFunction(this.receiver,
851 ObjectLookupGetter) === this.fun ||
852 %_CallFunction(this.receiver,
854 ObjectLookupSetter) === this.fun ||
855 this.receiver[ownName] === this.fun)) {
856 // To handle DontEnum properties we guess that the method has
857 // the same name as the function.
861 for (var prop in this.receiver) {
862 if (this.receiver.__lookupGetter__(prop) === this.fun ||
863 this.receiver.__lookupSetter__(prop) === this.fun ||
864 (!this.receiver.__lookupGetter__(prop) &&
865 this.receiver[prop] === this.fun)) {
866 // If we find more than one match bail out to avoid confusion.
879 function CallSiteGetFileName() {
880 var script = %FunctionGetScript(this.fun);
881 return script ? script.name : null;
884 function CallSiteGetLineNumber() {
885 if (this.pos == -1) {
888 var script = %FunctionGetScript(this.fun);
891 location = script.locationFromPosition(this.pos, true);
893 return location ? location.line + 1 : null;
896 function CallSiteGetColumnNumber() {
897 if (this.pos == -1) {
900 var script = %FunctionGetScript(this.fun);
903 location = script.locationFromPosition(this.pos, true);
905 return location ? location.column + 1: null;
908 function CallSiteIsNative() {
909 var script = %FunctionGetScript(this.fun);
910 return script ? (script.type == TYPE_NATIVE) : false;
913 function CallSiteGetPosition() {
917 function CallSiteIsConstructor() {
918 var constructor = this.receiver ? this.receiver.constructor : null;
922 return this.fun === constructor;
925 function CallSiteToString() {
927 var fileLocation = "";
928 if (this.isNative()) {
929 fileLocation = "native";
930 } else if (this.isEval()) {
931 fileName = this.getScriptNameOrSourceURL();
933 fileLocation = this.getEvalOrigin();
936 fileName = this.getFileName();
940 fileLocation += fileName;
941 var lineNumber = this.getLineNumber();
942 if (lineNumber != null) {
943 fileLocation += ":" + lineNumber;
944 var columnNumber = this.getColumnNumber();
946 fileLocation += ":" + columnNumber;
952 fileLocation = "unknown source";
955 var functionName = this.getFunction().name;
956 var addPrefix = true;
957 var isConstructor = this.isConstructor();
958 var isMethodCall = !(this.isToplevel() || isConstructor);
960 var methodName = this.getMethodName();
961 line += this.getTypeName() + ".";
963 line += functionName;
964 if (methodName && (methodName != functionName)) {
965 line += " [as " + methodName + "]";
968 line += methodName || "<anonymous>";
970 } else if (isConstructor) {
971 line += "new " + (functionName || "<anonymous>");
972 } else if (functionName) {
973 line += functionName;
975 line += fileLocation;
979 line += " (" + fileLocation + ")";
984 SetUpLockedPrototype(CallSite, $Array("receiver", "fun", "pos"), $Array(
985 "getThis", CallSiteGetThis,
986 "getTypeName", CallSiteGetTypeName,
987 "isToplevel", CallSiteIsToplevel,
988 "isEval", CallSiteIsEval,
989 "getEvalOrigin", CallSiteGetEvalOrigin,
990 "getScriptNameOrSourceURL", CallSiteGetScriptNameOrSourceURL,
991 "getFunction", CallSiteGetFunction,
992 "getFunctionName", CallSiteGetFunctionName,
993 "getMethodName", CallSiteGetMethodName,
994 "getFileName", CallSiteGetFileName,
995 "getLineNumber", CallSiteGetLineNumber,
996 "getColumnNumber", CallSiteGetColumnNumber,
997 "isNative", CallSiteIsNative,
998 "getPosition", CallSiteGetPosition,
999 "isConstructor", CallSiteIsConstructor,
1000 "toString", CallSiteToString
1004 function FormatEvalOrigin(script) {
1005 var sourceURL = script.nameOrSourceURL();
1010 var eval_origin = "eval at ";
1011 if (script.eval_from_function_name) {
1012 eval_origin += script.eval_from_function_name;
1014 eval_origin += "<anonymous>";
1017 var eval_from_script = script.eval_from_script;
1018 if (eval_from_script) {
1019 if (eval_from_script.compilation_type == COMPILATION_TYPE_EVAL) {
1020 // eval script originated from another eval.
1021 eval_origin += " (" + FormatEvalOrigin(eval_from_script) + ")";
1023 // eval script originated from "real" source.
1024 if (eval_from_script.name) {
1025 eval_origin += " (" + eval_from_script.name;
1026 var location = eval_from_script.locationFromPosition(
1027 script.eval_from_script_position, true);
1029 eval_origin += ":" + (location.line + 1);
1030 eval_origin += ":" + (location.column + 1);
1034 eval_origin += " (unknown source)";
1042 function FormatStackTrace(error, frames) {
1045 lines.push(error.toString());
1048 lines.push("<error: " + e + ">");
1050 lines.push("<error>");
1053 for (var i = 0; i < frames.length; i++) {
1054 var frame = frames[i];
1057 line = frame.toString();
1060 line = "<error: " + e + ">";
1062 // Any code that reaches this point is seriously nasty!
1066 lines.push(" at " + line);
1068 return lines.join("\n");
1071 function FormatRawStackTrace(error, raw_stack) {
1073 for (var i = 0; i < raw_stack.length; i += 4) {
1074 var recv = raw_stack[i];
1075 var fun = raw_stack[i + 1];
1076 var code = raw_stack[i + 2];
1077 var pc = raw_stack[i + 3];
1078 var pos = %FunctionGetPositionForOffset(code, pc);
1079 frames.push(new CallSite(recv, fun, pos));
1081 if (IS_FUNCTION($Error.prepareStackTrace)) {
1082 return $Error.prepareStackTrace(error, frames);
1084 return FormatStackTrace(error, frames);
1089 function captureStackTrace(obj, cons_opt) {
1090 var stackTraceLimit = $Error.stackTraceLimit;
1091 if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return;
1092 if (stackTraceLimit < 0 || stackTraceLimit > 10000) {
1093 stackTraceLimit = 10000;
1095 var raw_stack = %CollectStackTrace(obj,
1096 cons_opt ? cons_opt : captureStackTrace,
1098 DefineOneShotAccessor(obj, 'stack', function (obj) {
1099 return FormatRawStackTrace(obj, raw_stack);
1104 function SetUpError() {
1105 // Define special error type constructors.
1107 var DefineError = function(f) {
1108 // Store the error function in both the global object
1109 // and the runtime object. The function is fetched
1110 // from the runtime object when throwing errors from
1111 // within the runtime system to avoid strange side
1112 // effects when overwriting the error functions from
1115 %SetProperty(global, name, f, DONT_ENUM);
1116 %SetProperty(builtins, '$' + name, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
1117 // Configure the error function.
1118 if (name == 'Error') {
1119 // The prototype of the Error object must itself be an error.
1120 // However, it can't be an instance of the Error object because
1121 // it hasn't been properly configured yet. Instead we create a
1122 // special not-a-true-error-but-close-enough object.
1123 var ErrorPrototype = function() {};
1124 %FunctionSetPrototype(ErrorPrototype, $Object.prototype);
1125 %FunctionSetInstanceClassName(ErrorPrototype, 'Error');
1126 %FunctionSetPrototype(f, new ErrorPrototype());
1128 %FunctionSetPrototype(f, new $Error());
1130 %FunctionSetInstanceClassName(f, 'Error');
1131 %SetProperty(f.prototype, 'constructor', f, DONT_ENUM);
1132 %SetProperty(f.prototype, "name", name, DONT_ENUM);
1133 %SetCode(f, function(m) {
1134 if (%_IsConstructCall()) {
1135 // Define all the expected properties directly on the error
1136 // object. This avoids going through getters and setters defined
1137 // on prototype objects.
1138 %IgnoreAttributesAndSetProperty(this, 'stack', void 0, DONT_ENUM);
1139 %IgnoreAttributesAndSetProperty(this, 'arguments', void 0, DONT_ENUM);
1140 %IgnoreAttributesAndSetProperty(this, 'type', void 0, DONT_ENUM);
1141 if (m === kAddMessageAccessorsMarker) {
1142 // DefineOneShotAccessor always inserts a message property and
1144 DefineOneShotAccessor(this, 'message', function (obj) {
1145 return FormatMessage(%NewMessageObject(obj.type, obj.arguments));
1147 } else if (!IS_UNDEFINED(m)) {
1148 %IgnoreAttributesAndSetProperty(
1149 this, 'message', ToString(m), DONT_ENUM);
1151 captureStackTrace(this, f);
1159 DefineError(function Error() { });
1160 DefineError(function TypeError() { });
1161 DefineError(function RangeError() { });
1162 DefineError(function SyntaxError() { });
1163 DefineError(function ReferenceError() { });
1164 DefineError(function EvalError() { });
1165 DefineError(function URIError() { });
1170 $Error.captureStackTrace = captureStackTrace;
1172 %SetProperty($Error.prototype, 'message', '', DONT_ENUM);
1174 // Global list of error objects visited during ErrorToString. This is
1175 // used to detect cycles in error toString formatting.
1176 var visited_errors = new InternalArray();
1177 var cyclic_error_marker = new $Object();
1179 function GetPropertyWithoutInvokingMonkeyGetters(error, name) {
1180 // Climb the prototype chain until we find the holder.
1181 while (error && !%HasLocalProperty(error, name)) {
1182 error = error.__proto__;
1184 if (error === null) return void 0;
1185 if (!IS_OBJECT(error)) return error[name];
1186 // If the property is an accessor on one of the predefined errors that can be
1187 // generated statically by the compiler, don't touch it. This is to address
1188 // http://code.google.com/p/chromium/issues/detail?id=69187
1189 var desc = %GetOwnProperty(error, name);
1190 if (desc && desc[IS_ACCESSOR_INDEX]) {
1191 var isName = name === "name";
1192 if (error === $ReferenceError.prototype)
1193 return isName ? "ReferenceError" : void 0;
1194 if (error === $SyntaxError.prototype)
1195 return isName ? "SyntaxError" : void 0;
1196 if (error === $TypeError.prototype)
1197 return isName ? "TypeError" : void 0;
1199 // Otherwise, read normally.
1203 function ErrorToStringDetectCycle(error) {
1204 if (!%PushIfAbsent(visited_errors, error)) throw cyclic_error_marker;
1206 var type = GetPropertyWithoutInvokingMonkeyGetters(error, "type");
1207 var name = GetPropertyWithoutInvokingMonkeyGetters(error, "name");
1208 name = IS_UNDEFINED(name) ? "Error" : TO_STRING_INLINE(name);
1209 var message = GetPropertyWithoutInvokingMonkeyGetters(error, "message");
1210 var hasMessage = %_CallFunction(error, "message", ObjectHasOwnProperty);
1211 if (type && !hasMessage) {
1212 var args = GetPropertyWithoutInvokingMonkeyGetters(error, "arguments");
1213 message = FormatMessage(%NewMessageObject(type, args));
1215 message = IS_UNDEFINED(message) ? "" : TO_STRING_INLINE(message);
1216 if (name === "") return message;
1217 if (message === "") return name;
1218 return name + ": " + message;
1220 visited_errors.length = visited_errors.length - 1;
1224 function ErrorToString() {
1225 if (!IS_SPEC_OBJECT(this)) {
1226 throw MakeTypeError("called_on_non_object", ["Error.prototype.toString"]);
1230 return ErrorToStringDetectCycle(this);
1232 // If this error message was encountered already return the empty
1233 // string for it instead of recursively formatting it.
1234 if (e === cyclic_error_marker) {
1242 InstallFunctions($Error.prototype, DONT_ENUM, ['toString', ErrorToString]);
1244 // Boilerplate for exceptions for stack overflows. Used from
1245 // Isolate::StackOverflow().
1246 var kStackOverflowBoilerplate = MakeRangeError('stack_overflow', []);