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 // -------------------------------------------------------------------
32 cyclic_proto: ["Cyclic __proto__ value"],
33 code_gen_from_strings: ["%0"],
34 generator_running: ["Generator is already running"],
35 generator_finished: ["Generator has already finished"],
37 unexpected_token: ["Unexpected token ", "%0"],
38 unexpected_token_number: ["Unexpected number"],
39 unexpected_token_string: ["Unexpected string"],
40 unexpected_token_identifier: ["Unexpected identifier"],
41 unexpected_reserved: ["Unexpected reserved word"],
42 unexpected_strict_reserved: ["Unexpected strict mode reserved word"],
43 unexpected_eos: ["Unexpected end of input"],
44 malformed_regexp: ["Invalid regular expression: /", "%0", "/: ", "%1"],
45 unterminated_regexp: ["Invalid regular expression: missing /"],
46 regexp_flags: ["Cannot supply flags when constructing one RegExp from another"],
47 incompatible_method_receiver: ["Method ", "%0", " called on incompatible receiver ", "%1"],
48 invalid_lhs_in_assignment: ["Invalid left-hand side in assignment"],
49 invalid_lhs_in_for_in: ["Invalid left-hand side in for-in"],
50 invalid_lhs_in_postfix_op: ["Invalid left-hand side expression in postfix operation"],
51 invalid_lhs_in_prefix_op: ["Invalid left-hand side expression in prefix operation"],
52 multiple_defaults_in_switch: ["More than one default clause in switch statement"],
53 newline_after_throw: ["Illegal newline after throw"],
54 redeclaration: ["%0", " '", "%1", "' has already been declared"],
55 no_catch_or_finally: ["Missing catch or finally after try"],
56 unknown_label: ["Undefined label '", "%0", "'"],
57 uncaught_exception: ["Uncaught ", "%0"],
58 stack_trace: ["Stack Trace:\n", "%0"],
59 called_non_callable: ["%0", " is not a function"],
60 undefined_method: ["Object ", "%1", " has no method '", "%0", "'"],
61 property_not_function: ["Property '", "%0", "' of object ", "%1", " is not a function"],
62 cannot_convert_to_primitive: ["Cannot convert object to primitive value"],
63 not_constructor: ["%0", " is not a constructor"],
64 not_defined: ["%0", " is not defined"],
65 non_object_property_load: ["Cannot read property '", "%0", "' of ", "%1"],
66 non_object_property_store: ["Cannot set property '", "%0", "' of ", "%1"],
67 non_object_property_call: ["Cannot call method '", "%0", "' of ", "%1"],
68 with_expression: ["%0", " has no properties"],
69 illegal_invocation: ["Illegal invocation"],
70 no_setter_in_callback: ["Cannot set property ", "%0", " of ", "%1", " which has only a getter"],
71 apply_non_function: ["Function.prototype.apply was called on ", "%0", ", which is a ", "%1", " and not a function"],
72 apply_wrong_args: ["Function.prototype.apply: Arguments list has wrong type"],
73 invalid_in_operator_use: ["Cannot use 'in' operator to search for '", "%0", "' in ", "%1"],
74 instanceof_function_expected: ["Expecting a function in instanceof check, but got ", "%0"],
75 instanceof_nonobject_proto: ["Function has non-object prototype '", "%0", "' in instanceof check"],
76 undefined_or_null_to_object: ["Cannot convert undefined or null to object"],
77 reduce_no_initial: ["Reduce of empty array with no initial value"],
78 getter_must_be_callable: ["Getter must be a function: ", "%0"],
79 setter_must_be_callable: ["Setter must be a function: ", "%0"],
80 value_and_accessor: ["Invalid property. A property cannot both have accessors and be writable or have a value, ", "%0"],
81 proto_object_or_null: ["Object prototype may only be an Object or null: ", "%0"],
82 property_desc_object: ["Property description must be an object: ", "%0"],
83 redefine_disallowed: ["Cannot redefine property: ", "%0"],
84 define_disallowed: ["Cannot define property:", "%0", ", object is not extensible."],
85 non_extensible_proto: ["%0", " is not extensible"],
86 handler_non_object: ["Proxy.", "%0", " called with non-object as handler"],
87 proto_non_object: ["Proxy.", "%0", " called with non-object as prototype"],
88 trap_function_expected: ["Proxy.", "%0", " called with non-function for '", "%1", "' trap"],
89 handler_trap_missing: ["Proxy handler ", "%0", " has no '", "%1", "' trap"],
90 handler_trap_must_be_callable: ["Proxy handler ", "%0", " has non-callable '", "%1", "' trap"],
91 handler_returned_false: ["Proxy handler ", "%0", " returned false from '", "%1", "' trap"],
92 handler_returned_undefined: ["Proxy handler ", "%0", " returned undefined from '", "%1", "' trap"],
93 proxy_prop_not_configurable: ["Proxy handler ", "%0", " returned non-configurable descriptor for property '", "%2", "' from '", "%1", "' trap"],
94 proxy_non_object_prop_names: ["Trap '", "%1", "' returned non-object ", "%0"],
95 proxy_repeated_prop_name: ["Trap '", "%1", "' returned repeated property name '", "%2", "'"],
96 invalid_weakmap_key: ["Invalid value used as weak map key"],
97 invalid_weakset_value: ["Invalid value used in weak set"],
98 not_date_object: ["this is not a Date object."],
99 observe_non_object: ["Object.", "%0", " cannot ", "%0", " non-object"],
100 observe_non_function: ["Object.", "%0", " cannot deliver to non-function"],
101 observe_callback_frozen: ["Object.observe cannot deliver to a frozen function object"],
102 observe_invalid_accept: ["Object.observe accept must be an array of strings."],
103 observe_type_non_string: ["Invalid changeRecord with non-string 'type' property"],
104 observe_perform_non_string: ["Invalid non-string changeType"],
105 observe_perform_non_function: ["Cannot perform non-function"],
106 observe_notify_non_notifier: ["notify called on non-notifier object"],
107 not_typed_array: ["this is not a typed array."],
108 invalid_argument: ["invalid_argument"],
109 data_view_not_array_buffer: ["First argument to DataView constructor must be an ArrayBuffer"],
110 constructor_not_function: ["Constructor ", "%0", " requires 'new'"],
111 not_a_promise: ["%0", " is not a promise"],
112 resolver_not_a_function: ["Promise resolver ", "%0", " is not a function"],
113 promise_cyclic: ["Chaining cycle detected for promise ", "%0"],
114 array_functions_on_frozen: ["Cannot modify frozen array elements"],
115 array_functions_change_sealed: ["Cannot add/remove sealed array elements"],
116 first_argument_not_regexp: ["First argument to ", "%0", " must not be a regular expression"],
118 invalid_array_length: ["Invalid array length"],
119 invalid_array_buffer_length: ["Invalid array buffer length"],
120 invalid_string_length: ["Invalid string length"],
121 invalid_typed_array_offset: ["Start offset is too large:"],
122 invalid_typed_array_length: ["Invalid typed array length"],
123 invalid_typed_array_alignment: ["%0", "of", "%1", "should be a multiple of", "%3"],
124 typed_array_set_source_too_large:
125 ["Source is too large"],
126 typed_array_set_negative_offset:
127 ["Start offset is negative"],
128 invalid_data_view_offset: ["Start offset is outside the bounds of the buffer"],
129 invalid_data_view_length: ["Invalid data view length"],
130 invalid_data_view_accessor_offset:
131 ["Offset is outside the bounds of the DataView"],
133 stack_overflow: ["Maximum call stack size exceeded"],
134 invalid_time_value: ["Invalid time value"],
135 invalid_count_value: ["Invalid count value"],
137 paren_in_arg_string: ["Function arg string contains parenthesis"],
138 not_isvar: ["builtin %IS_VAR: not a variable"],
139 single_function_literal: ["Single function literal required"],
140 invalid_regexp_flags: ["Invalid flags supplied to RegExp constructor '", "%0", "'"],
141 invalid_regexp: ["Invalid RegExp pattern /", "%0", "/"],
142 illegal_break: ["Illegal break statement"],
143 illegal_continue: ["Illegal continue statement"],
144 illegal_return: ["Illegal return statement"],
145 illegal_let: ["Illegal let declaration outside extended mode"],
146 error_loading_debugger: ["Error loading debugger"],
147 no_input_to_regexp: ["No input to ", "%0"],
148 invalid_json: ["String '", "%0", "' is not valid JSON"],
149 circular_structure: ["Converting circular structure to JSON"],
150 called_on_non_object: ["%0", " called on non-object"],
151 called_on_null_or_undefined: ["%0", " called on null or undefined"],
152 array_indexof_not_defined: ["Array.getIndexOf: Argument undefined"],
153 object_not_extensible: ["Can't add property ", "%0", ", object is not extensible"],
154 illegal_access: ["Illegal access"],
155 invalid_preparser_data: ["Invalid preparser data for function ", "%0"],
156 strict_mode_with: ["Strict mode code may not include a with statement"],
157 strict_eval_arguments: ["Unexpected eval or arguments in strict mode"],
158 too_many_arguments: ["Too many arguments in function call (only 32766 allowed)"],
159 too_many_parameters: ["Too many parameters in function definition (only 32766 allowed)"],
160 too_many_variables: ["Too many variables declared (only 131071 allowed)"],
161 strict_param_dupe: ["Strict mode function may not have duplicate parameter names"],
162 strict_octal_literal: ["Octal literals are not allowed in strict mode."],
163 strict_duplicate_property: ["Duplicate data property in object literal not allowed in strict mode"],
164 accessor_data_property: ["Object literal may not have data and accessor property with the same name"],
165 accessor_get_set: ["Object literal may not have multiple get/set accessors with the same name"],
166 strict_delete: ["Delete of an unqualified identifier in strict mode."],
167 strict_delete_property: ["Cannot delete property '", "%0", "' of ", "%1"],
168 strict_const: ["Use of const in strict mode."],
169 strict_function: ["In strict mode code, functions can only be declared at top level or immediately within another function." ],
170 strict_read_only_property: ["Cannot assign to read only property '", "%0", "' of ", "%1"],
171 strict_cannot_assign: ["Cannot assign to read only '", "%0", "' in strict mode"],
172 strict_poison_pill: ["'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them"],
173 strict_caller: ["Illegal access to a strict mode caller function."],
174 unprotected_let: ["Illegal let declaration in unprotected statement context."],
175 unprotected_const: ["Illegal const declaration in unprotected statement context."],
176 cant_prevent_ext_external_array_elements: ["Cannot prevent extension of an object with external array elements"],
177 redef_external_array_element: ["Cannot redefine a property of an object with external array elements"],
178 harmony_const_assign: ["Assignment to constant variable."],
179 symbol_to_string: ["Conversion from symbol to string"],
180 invalid_module_path: ["Module does not export '", "%0", "', or export is not itself a module"],
181 module_type_error: ["Module '", "%0", "' used improperly"],
182 module_export_undefined: ["Export '", "%0", "' is not defined in module"]
186 function FormatString(format, args) {
189 for (var i = 0; i < format.length; i++) {
191 if (str.length == 2 && %_StringCharCodeAt(str, 0) == 0x25) {
192 // Two-char string starts with "%".
193 var arg_num = (%_StringCharCodeAt(str, 1) - 0x30) >>> 0;
195 // str is one of %0, %1, %2 or %3.
197 str = NoSideEffectToString(args[arg_num]);
198 if (str.length > 256) {
199 str = %SubString(str, 0, 239) + "...<omitted>..." +
200 %SubString(str, str.length - 2, str.length);
203 if (%IsJSModule(args[arg_num]))
205 else if (IS_SPEC_OBJECT(args[arg_num]))
218 function NoSideEffectToString(obj) {
219 if (IS_STRING(obj)) return obj;
220 if (IS_NUMBER(obj)) return %_NumberToString(obj);
221 if (IS_BOOLEAN(obj)) return x ? 'true' : 'false';
222 if (IS_UNDEFINED(obj)) return 'undefined';
223 if (IS_NULL(obj)) return 'null';
224 if (IS_FUNCTION(obj)) return %_CallFunction(obj, FunctionToString);
225 if (IS_OBJECT(obj) && %GetDataProperty(obj, "toString") === ObjectToString) {
226 var constructor = %GetDataProperty(obj, "constructor");
227 if (typeof constructor == "function") {
228 var constructorName = constructor.name;
229 if (IS_STRING(constructorName) && constructorName !== "") {
230 return "#<" + constructorName + ">";
234 if (CanBeSafelyTreatedAsAnErrorObject(obj)) {
235 return %_CallFunction(obj, ErrorToString);
237 return %_CallFunction(obj, ObjectToString);
240 // To determine whether we can safely stringify an object using ErrorToString
241 // without the risk of side-effects, we need to check whether the object is
242 // either an instance of a native error type (via '%_ClassOf'), or has $Error
243 // in its prototype chain and hasn't overwritten 'toString' with something
244 // strange and unusual.
245 function CanBeSafelyTreatedAsAnErrorObject(obj) {
246 switch (%_ClassOf(obj)) {
250 case 'ReferenceError':
257 var objToString = %GetDataProperty(obj, "toString");
258 return obj instanceof $Error && objToString === ErrorToString;
262 // When formatting internally created error messages, do not
263 // invoke overwritten error toString methods but explicitly use
264 // the error to string method. This is to avoid leaking error
265 // objects between script tags in a browser setting.
266 function ToStringCheckErrorObject(obj) {
267 if (CanBeSafelyTreatedAsAnErrorObject(obj)) {
268 return %_CallFunction(obj, ErrorToString);
270 return ToString(obj);
275 function ToDetailString(obj) {
276 if (obj != null && IS_OBJECT(obj) && obj.toString === ObjectToString) {
277 var constructor = obj.constructor;
278 if (typeof constructor == "function") {
279 var constructorName = constructor.name;
280 if (IS_STRING(constructorName) && constructorName !== "") {
281 return "#<" + constructorName + ">";
285 return ToStringCheckErrorObject(obj);
289 function MakeGenericError(constructor, type, args) {
290 if (IS_UNDEFINED(args)) args = [];
291 return new constructor(FormatMessage(type, args));
296 * Set up the Script function and constructor.
298 %FunctionSetInstanceClassName(Script, 'Script');
299 %SetProperty(Script.prototype, 'constructor', Script,
300 DONT_ENUM | DONT_DELETE | READ_ONLY);
301 %SetCode(Script, function(x) {
302 // Script objects can only be created by the VM.
303 throw new $Error("Not supported");
307 // Helper functions; called from the runtime system.
308 function FormatMessage(type, args) {
309 var format = kMessages[type];
310 if (!format) return "<unknown message " + type + ">";
311 return FormatString(format, args);
315 function GetLineNumber(message) {
316 var start_position = %MessageGetStartPosition(message);
317 if (start_position == -1) return kNoLineNumberInfo;
318 var script = %MessageGetScript(message);
319 var location = script.locationFromPosition(start_position, true);
320 if (location == null) return kNoLineNumberInfo;
321 return location.line + 1;
325 // Returns the source code line containing the given source
326 // position, or the empty string if the position is invalid.
327 function GetSourceLine(message) {
328 var script = %MessageGetScript(message);
329 var start_position = %MessageGetStartPosition(message);
330 var location = script.locationFromPosition(start_position, true);
331 if (location == null) return "";
333 return location.sourceText();
337 function MakeTypeError(type, args) {
338 return MakeGenericError($TypeError, type, args);
342 function MakeRangeError(type, args) {
343 return MakeGenericError($RangeError, type, args);
347 function MakeSyntaxError(type, args) {
348 return MakeGenericError($SyntaxError, type, args);
352 function MakeReferenceError(type, args) {
353 return MakeGenericError($ReferenceError, type, args);
357 function MakeEvalError(type, args) {
358 return MakeGenericError($EvalError, type, args);
362 function MakeError(type, args) {
363 return MakeGenericError($Error, type, args);
367 * Find a line number given a specific source position.
368 * @param {number} position The source position.
369 * @return {number} 0 if input too small, -1 if input too large,
370 else the line number.
372 function ScriptLineFromPosition(position) {
374 var upper = this.lineCount() - 1;
375 var line_ends = this.line_ends;
377 // We'll never find invalid positions so bail right away.
378 if (position > line_ends[upper]) {
382 // This means we don't have to safe-guard indexing line_ends[i - 1].
383 if (position <= line_ends[0]) {
387 // Binary search to find line # from position range.
389 var i = (lower + upper) >> 1;
391 if (position > line_ends[i]) {
393 } else if (position <= line_ends[i - 1]) {
404 * Get information on a specific source position.
405 * @param {number} position The source position
406 * @param {boolean} include_resource_offset Set to true to have the resource
407 * offset added to the location
408 * @return {SourceLocation}
409 * If line is negative or not in the source null is returned.
411 function ScriptLocationFromPosition(position,
412 include_resource_offset) {
413 var line = this.lineFromPosition(position);
414 if (line == -1) return null;
416 // Determine start, end and column.
417 var line_ends = this.line_ends;
418 var start = line == 0 ? 0 : line_ends[line - 1] + 1;
419 var end = line_ends[line];
420 if (end > 0 && %_CallFunction(this.source, end - 1, StringCharAt) == '\r') {
423 var column = position - start;
425 // Adjust according to the offset within the resource.
426 if (include_resource_offset) {
427 line += this.line_offset;
428 if (line == this.line_offset) {
429 column += this.column_offset;
433 return new SourceLocation(this, position, line, column, start, end);
438 * Get information on a specific source line and column possibly offset by a
439 * fixed source position. This function is used to find a source position from
440 * a line and column position. The fixed source position offset is typically
441 * used to find a source position in a function based on a line and column in
442 * the source for the function alone. The offset passed will then be the
443 * start position of the source for the function within the full script source.
444 * @param {number} opt_line The line within the source. Default value is 0
445 * @param {number} opt_column The column in within the line. Default value is 0
446 * @param {number} opt_offset_position The offset from the begining of the
447 * source from where the line and column calculation starts.
449 * @return {SourceLocation}
450 * If line is negative or not in the source null is returned.
452 function ScriptLocationFromLine(opt_line, opt_column, opt_offset_position) {
453 // Default is the first line in the script. Lines in the script is relative
454 // to the offset within the resource.
456 if (!IS_UNDEFINED(opt_line)) {
457 line = opt_line - this.line_offset;
460 // Default is first column. If on the first line add the offset within the
462 var column = opt_column || 0;
464 column -= this.column_offset;
467 var offset_position = opt_offset_position || 0;
468 if (line < 0 || column < 0 || offset_position < 0) return null;
470 return this.locationFromPosition(offset_position + column, false);
472 // Find the line where the offset position is located.
473 var offset_line = this.lineFromPosition(offset_position);
475 if (offset_line == -1 || offset_line + line >= this.lineCount()) {
479 return this.locationFromPosition(
480 this.line_ends[offset_line + line - 1] + 1 + column); // line > 0 here.
486 * Get a slice of source code from the script. The boundaries for the slice is
487 * specified in lines.
488 * @param {number} opt_from_line The first line (zero bound) in the slice.
490 * @param {number} opt_to_column The last line (zero bound) in the slice (non
491 * inclusive). Default is the number of lines in the script
492 * @return {SourceSlice} The source slice or null of the parameters where
495 function ScriptSourceSlice(opt_from_line, opt_to_line) {
496 var from_line = IS_UNDEFINED(opt_from_line) ? this.line_offset
498 var to_line = IS_UNDEFINED(opt_to_line) ? this.line_offset + this.lineCount()
501 // Adjust according to the offset within the resource.
502 from_line -= this.line_offset;
503 to_line -= this.line_offset;
504 if (from_line < 0) from_line = 0;
505 if (to_line > this.lineCount()) to_line = this.lineCount();
508 if (from_line >= this.lineCount() ||
510 from_line > to_line) {
514 var line_ends = this.line_ends;
515 var from_position = from_line == 0 ? 0 : line_ends[from_line - 1] + 1;
516 var to_position = to_line == 0 ? 0 : line_ends[to_line - 1] + 1;
518 // Return a source slice with line numbers re-adjusted to the resource.
519 return new SourceSlice(this,
520 from_line + this.line_offset,
521 to_line + this.line_offset,
522 from_position, to_position);
526 function ScriptSourceLine(opt_line) {
527 // Default is the first line in the script. Lines in the script are relative
528 // to the offset within the resource.
530 if (!IS_UNDEFINED(opt_line)) {
531 line = opt_line - this.line_offset;
535 if (line < 0 || this.lineCount() <= line) {
539 // Return the source line.
540 var line_ends = this.line_ends;
541 var start = line == 0 ? 0 : line_ends[line - 1] + 1;
542 var end = line_ends[line];
543 return %_CallFunction(this.source, start, end, StringSubstring);
548 * Returns the number of source lines.
550 * Number of source lines.
552 function ScriptLineCount() {
553 // Return number of source lines.
554 return this.line_ends.length;
559 * If sourceURL comment is available and script starts at zero returns sourceURL
560 * comment contents. Otherwise, script name is returned. See
561 * http://fbug.googlecode.com/svn/branches/firebug1.1/docs/ReleaseNotes_1.1.txt
562 * and Source Map Revision 3 proposal for details on using //# sourceURL and
563 * deprecated //@ sourceURL comment to identify scripts that don't have name.
565 * @return {?string} script name if present, value for //# sourceURL or
566 * deprecated //@ sourceURL comment otherwise.
568 function ScriptNameOrSourceURL() {
569 if (this.line_offset > 0 || this.column_offset > 0) {
573 // The result is cached as on long scripts it takes noticable time to search
574 // for the sourceURL.
575 if (this.hasCachedNameOrSourceURL) {
576 return this.cachedNameOrSourceURL;
578 this.hasCachedNameOrSourceURL = true;
580 // TODO(608): the spaces in a regexp below had to be escaped as \040
581 // because this file is being processed by js2c whose handling of spaces
582 // in regexps is broken. Also, ['"] are excluded from allowed URLs to
583 // avoid matches against sources that invoke evals with sourceURL.
584 // A better solution would be to detect these special comments in
585 // the scanner/parser.
586 var source = ToString(this.source);
587 var sourceUrlPos = %StringIndexOf(source, "sourceURL=", 0);
588 this.cachedNameOrSourceURL = this.name;
589 if (sourceUrlPos > 4) {
590 var sourceUrlPattern =
591 /\/\/[#@][\040\t]sourceURL=[\040\t]*([^\s\'\"]*)[\040\t]*$/gm;
592 // Don't reuse lastMatchInfo here, so we create a new array with room
593 // for four captures (array with length one longer than the index
594 // of the fourth capture, where the numbering is zero-based).
595 var matchInfo = new InternalArray(CAPTURE(3) + 1);
597 %_RegExpExec(sourceUrlPattern, source, sourceUrlPos - 4, matchInfo);
599 this.cachedNameOrSourceURL =
600 %_SubString(source, matchInfo[CAPTURE(2)], matchInfo[CAPTURE(3)]);
603 return this.cachedNameOrSourceURL;
607 SetUpLockedPrototype(Script,
608 $Array("source", "name", "line_ends", "line_offset", "column_offset",
609 "cachedNameOrSourceURL", "hasCachedNameOrSourceURL" ),
611 "lineFromPosition", ScriptLineFromPosition,
612 "locationFromPosition", ScriptLocationFromPosition,
613 "locationFromLine", ScriptLocationFromLine,
614 "sourceSlice", ScriptSourceSlice,
615 "sourceLine", ScriptSourceLine,
616 "lineCount", ScriptLineCount,
617 "nameOrSourceURL", ScriptNameOrSourceURL
623 * Class for source location. A source location is a position within some
624 * source with the following properties:
625 * script : script object for the source
626 * line : source line number
627 * column : source column within the line
628 * position : position within the source
629 * start : position of start of source context (inclusive)
630 * end : position of end of source context (not inclusive)
631 * Source text for the source context is the character interval
632 * [start, end[. In most cases end will point to a newline character.
633 * It might point just past the final position of the source if the last
634 * source line does not end with a newline character.
635 * @param {Script} script The Script object for which this is a location
636 * @param {number} position Source position for the location
637 * @param {number} line The line number for the location
638 * @param {number} column The column within the line for the location
639 * @param {number} start Source position for start of source context
640 * @param {number} end Source position for end of source context
643 function SourceLocation(script, position, line, column, start, end) {
644 this.script = script;
645 this.position = position;
647 this.column = column;
652 var kLineLengthLimit = 78;
655 * Restrict source location start and end positions to make the source slice
656 * no more that a certain number of characters wide.
657 * @param {number} opt_limit The with limit of the source text with a default
659 * @param {number} opt_before The number of characters to prefer before the
660 * position with a default value of 10 less that the limit
662 function SourceLocationRestrict(opt_limit, opt_before) {
663 // Find the actual limit to use.
666 if (!IS_UNDEFINED(opt_limit)) {
669 limit = kLineLengthLimit;
671 if (!IS_UNDEFINED(opt_before)) {
674 // If no before is specified center for small limits and perfer more source
675 // before the the position that after for longer limits.
677 before = $floor(limit / 2);
682 if (before >= limit) {
686 // If the [start, end[ interval is too big we restrict
687 // it in one or both ends. We make sure to always produce
688 // restricted intervals of maximum allowed size.
689 if (this.end - this.start > limit) {
690 var start_limit = this.position - before;
691 var end_limit = this.position + limit - before;
692 if (this.start < start_limit && end_limit < this.end) {
693 this.start = start_limit;
694 this.end = end_limit;
695 } else if (this.start < start_limit) {
696 this.start = this.end - limit;
698 this.end = this.start + limit;
705 * Get the source text for a SourceLocation
707 * Source text for this location.
709 function SourceLocationSourceText() {
710 return %_CallFunction(this.script.source,
717 SetUpLockedPrototype(SourceLocation,
718 $Array("script", "position", "line", "column", "start", "end"),
720 "restrict", SourceLocationRestrict,
721 "sourceText", SourceLocationSourceText
727 * Class for a source slice. A source slice is a part of a script source with
728 * the following properties:
729 * script : script object for the source
730 * from_line : line number for the first line in the slice
731 * to_line : source line number for the last line in the slice
732 * from_position : position of the first character in the slice
733 * to_position : position of the last character in the slice
734 * The to_line and to_position are not included in the slice, that is the lines
735 * in the slice are [from_line, to_line[. Likewise the characters in the slice
736 * are [from_position, to_position[.
737 * @param {Script} script The Script object for the source slice
738 * @param {number} from_line
739 * @param {number} to_line
740 * @param {number} from_position
741 * @param {number} to_position
744 function SourceSlice(script, from_line, to_line, from_position, to_position) {
745 this.script = script;
746 this.from_line = from_line;
747 this.to_line = to_line;
748 this.from_position = from_position;
749 this.to_position = to_position;
753 * Get the source text for a SourceSlice
754 * @return {String} Source text for this slice. The last line will include
755 * the line terminating characters (if any)
757 function SourceSliceSourceText() {
758 return %_CallFunction(this.script.source,
764 SetUpLockedPrototype(SourceSlice,
765 $Array("script", "from_line", "to_line", "from_position", "to_position"),
766 $Array("sourceText", SourceSliceSourceText)
770 // Returns the offset of the given position within the containing
772 function GetPositionInLine(message) {
773 var script = %MessageGetScript(message);
774 var start_position = %MessageGetStartPosition(message);
775 var location = script.locationFromPosition(start_position, false);
776 if (location == null) return -1;
778 return start_position - location.start;
782 function GetStackTraceLine(recv, fun, pos, isGlobal) {
783 return new CallSite(recv, fun, pos, false).toString();
786 // ----------------------------------------------------------------------------
787 // Error implementation
790 var CallSiteReceiverKey = NEW_PRIVATE("receiver");
791 var CallSiteFunctionKey = NEW_PRIVATE("function");
792 var CallSitePositionKey = NEW_PRIVATE("position");
793 var CallSiteStrictModeKey = NEW_PRIVATE("strict mode");
795 function CallSite(receiver, fun, pos, strict_mode) {
796 SET_PRIVATE(this, CallSiteReceiverKey, receiver);
797 SET_PRIVATE(this, CallSiteFunctionKey, fun);
798 SET_PRIVATE(this, CallSitePositionKey, pos);
799 SET_PRIVATE(this, CallSiteStrictModeKey, strict_mode);
802 function CallSiteGetThis() {
803 return GET_PRIVATE(this, CallSiteStrictModeKey)
804 ? UNDEFINED : GET_PRIVATE(this, CallSiteReceiverKey);
807 function CallSiteGetTypeName() {
808 return GetTypeName(GET_PRIVATE(this, CallSiteReceiverKey), false);
811 function CallSiteIsToplevel() {
812 if (GET_PRIVATE(this, CallSiteReceiverKey) == null) {
815 return IS_GLOBAL(GET_PRIVATE(this, CallSiteReceiverKey));
818 function CallSiteIsEval() {
819 var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey));
820 return script && script.compilation_type == COMPILATION_TYPE_EVAL;
823 function CallSiteGetEvalOrigin() {
824 var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey));
825 return FormatEvalOrigin(script);
828 function CallSiteGetScriptNameOrSourceURL() {
829 var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey));
830 return script ? script.nameOrSourceURL() : null;
833 function CallSiteGetFunction() {
834 return GET_PRIVATE(this, CallSiteStrictModeKey)
835 ? UNDEFINED : GET_PRIVATE(this, CallSiteFunctionKey);
838 function CallSiteGetFunctionName() {
839 // See if the function knows its own name
840 var name = GET_PRIVATE(this, CallSiteFunctionKey).name;
844 name = %FunctionGetInferredName(GET_PRIVATE(this, CallSiteFunctionKey));
848 // Maybe this is an evaluation?
849 var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey));
850 if (script && script.compilation_type == COMPILATION_TYPE_EVAL) {
856 function CallSiteGetMethodName() {
857 // See if we can find a unique property on the receiver that holds
859 var receiver = GET_PRIVATE(this, CallSiteReceiverKey);
860 var fun = GET_PRIVATE(this, CallSiteFunctionKey);
861 var ownName = fun.name;
862 if (ownName && receiver &&
863 (%_CallFunction(receiver, ownName, ObjectLookupGetter) === fun ||
864 %_CallFunction(receiver, ownName, ObjectLookupSetter) === fun ||
865 (IS_OBJECT(receiver) && %GetDataProperty(receiver, ownName) === fun))) {
866 // To handle DontEnum properties we guess that the method has
867 // the same name as the function.
871 for (var prop in receiver) {
872 if (%_CallFunction(receiver, prop, ObjectLookupGetter) === fun ||
873 %_CallFunction(receiver, prop, ObjectLookupSetter) === fun ||
874 (IS_OBJECT(receiver) && %GetDataProperty(receiver, prop) === fun)) {
875 // If we find more than one match bail out to avoid confusion.
888 function CallSiteGetFileName() {
889 var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey));
890 return script ? script.name : null;
893 function CallSiteGetLineNumber() {
894 if (GET_PRIVATE(this, CallSitePositionKey) == -1) {
897 var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey));
900 location = script.locationFromPosition(
901 GET_PRIVATE(this, CallSitePositionKey), true);
903 return location ? location.line + 1 : null;
906 function CallSiteGetColumnNumber() {
907 if (GET_PRIVATE(this, CallSitePositionKey) == -1) {
910 var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey));
913 location = script.locationFromPosition(
914 GET_PRIVATE(this, CallSitePositionKey), true);
916 return location ? location.column + 1: null;
919 function CallSiteIsNative() {
920 var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey));
921 return script ? (script.type == TYPE_NATIVE) : false;
924 function CallSiteGetPosition() {
925 return GET_PRIVATE(this, CallSitePositionKey);
928 function CallSiteIsConstructor() {
929 var receiver = GET_PRIVATE(this, CallSiteReceiverKey);
930 var constructor = (receiver != null && IS_OBJECT(receiver))
931 ? %GetDataProperty(receiver, "constructor") : null;
932 if (!constructor) return false;
933 return GET_PRIVATE(this, CallSiteFunctionKey) === constructor;
936 function CallSiteToString() {
938 var fileLocation = "";
939 if (this.isNative()) {
940 fileLocation = "native";
943 fileName = this.getScriptNameOrSourceURL();
945 fileLocation = this.getEvalOrigin();
946 fileLocation += ", "; // Expecting source position to follow.
949 fileName = this.getFileName();
953 fileLocation += fileName;
955 // Source code does not originate from a file and is not native, but we
956 // can still get the source position inside the source string, e.g. in
958 fileLocation += "<anonymous>";
960 var lineNumber = this.getLineNumber();
961 if (lineNumber != null) {
962 fileLocation += ":" + lineNumber;
963 var columnNumber = this.getColumnNumber();
965 fileLocation += ":" + columnNumber;
971 var functionName = this.getFunctionName();
972 var addSuffix = true;
973 var isConstructor = this.isConstructor();
974 var isMethodCall = !(this.isToplevel() || isConstructor);
976 var typeName = GetTypeName(GET_PRIVATE(this, CallSiteReceiverKey), true);
977 var methodName = this.getMethodName();
980 %_CallFunction(functionName, typeName, StringIndexOf) != 0) {
981 line += typeName + ".";
983 line += functionName;
985 (%_CallFunction(functionName, "." + methodName, StringIndexOf) !=
986 functionName.length - methodName.length - 1)) {
987 line += " [as " + methodName + "]";
990 line += typeName + "." + (methodName || "<anonymous>");
992 } else if (isConstructor) {
993 line += "new " + (functionName || "<anonymous>");
994 } else if (functionName) {
995 line += functionName;
997 line += fileLocation;
1001 line += " (" + fileLocation + ")";
1006 SetUpLockedPrototype(CallSite, $Array("receiver", "fun", "pos"), $Array(
1007 "getThis", CallSiteGetThis,
1008 "getTypeName", CallSiteGetTypeName,
1009 "isToplevel", CallSiteIsToplevel,
1010 "isEval", CallSiteIsEval,
1011 "getEvalOrigin", CallSiteGetEvalOrigin,
1012 "getScriptNameOrSourceURL", CallSiteGetScriptNameOrSourceURL,
1013 "getFunction", CallSiteGetFunction,
1014 "getFunctionName", CallSiteGetFunctionName,
1015 "getMethodName", CallSiteGetMethodName,
1016 "getFileName", CallSiteGetFileName,
1017 "getLineNumber", CallSiteGetLineNumber,
1018 "getColumnNumber", CallSiteGetColumnNumber,
1019 "isNative", CallSiteIsNative,
1020 "getPosition", CallSiteGetPosition,
1021 "isConstructor", CallSiteIsConstructor,
1022 "toString", CallSiteToString
1026 function FormatEvalOrigin(script) {
1027 var sourceURL = script.nameOrSourceURL();
1032 var eval_origin = "eval at ";
1033 if (script.eval_from_function_name) {
1034 eval_origin += script.eval_from_function_name;
1036 eval_origin += "<anonymous>";
1039 var eval_from_script = script.eval_from_script;
1040 if (eval_from_script) {
1041 if (eval_from_script.compilation_type == COMPILATION_TYPE_EVAL) {
1042 // eval script originated from another eval.
1043 eval_origin += " (" + FormatEvalOrigin(eval_from_script) + ")";
1045 // eval script originated from "real" source.
1046 if (eval_from_script.name) {
1047 eval_origin += " (" + eval_from_script.name;
1048 var location = eval_from_script.locationFromPosition(
1049 script.eval_from_script_position, true);
1051 eval_origin += ":" + (location.line + 1);
1052 eval_origin += ":" + (location.column + 1);
1056 eval_origin += " (unknown source)";
1065 function FormatErrorString(error) {
1067 return %_CallFunction(error, ErrorToString);
1070 return "<error: " + e + ">";
1078 function GetStackFrames(raw_stack) {
1079 var frames = new InternalArray();
1080 var non_strict_frames = raw_stack[0];
1081 for (var i = 1; i < raw_stack.length; i += 4) {
1082 var recv = raw_stack[i];
1083 var fun = raw_stack[i + 1];
1084 var code = raw_stack[i + 2];
1085 var pc = raw_stack[i + 3];
1086 var pos = %FunctionGetPositionForOffset(code, pc);
1087 non_strict_frames--;
1088 frames.push(new CallSite(recv, fun, pos, (non_strict_frames < 0)));
1094 // Flag to prevent recursive call of Error.prepareStackTrace.
1095 var formatting_custom_stack_trace = false;
1098 function FormatStackTrace(obj, error_string, frames) {
1099 if (IS_FUNCTION($Error.prepareStackTrace) && !formatting_custom_stack_trace) {
1101 %MoveArrayContents(frames, array);
1102 formatting_custom_stack_trace = true;
1103 var stack_trace = UNDEFINED;
1105 stack_trace = $Error.prepareStackTrace(obj, array);
1107 throw e; // The custom formatting function threw. Rethrow.
1109 formatting_custom_stack_trace = false;
1114 var lines = new InternalArray();
1115 lines.push(error_string);
1116 for (var i = 0; i < frames.length; i++) {
1117 var frame = frames[i];
1120 line = frame.toString();
1123 line = "<error: " + e + ">";
1125 // Any code that reaches this point is seriously nasty!
1129 lines.push(" at " + line);
1131 return %_CallFunction(lines, "\n", ArrayJoin);
1135 function GetTypeName(receiver, requireConstructor) {
1136 var constructor = receiver.constructor;
1138 return requireConstructor ? null :
1139 %_CallFunction(receiver, ObjectToString);
1141 var constructorName = constructor.name;
1142 if (!constructorName) {
1143 return requireConstructor ? null :
1144 %_CallFunction(receiver, ObjectToString);
1146 return constructorName;
1150 function captureStackTrace(obj, cons_opt) {
1151 var stackTraceLimit = $Error.stackTraceLimit;
1152 if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return;
1153 if (stackTraceLimit < 0 || stackTraceLimit > 10000) {
1154 stackTraceLimit = 10000;
1156 var stack = %CollectStackTrace(obj,
1157 cons_opt ? cons_opt : captureStackTrace,
1160 var error_string = FormatErrorString(obj);
1161 // The holder of this getter ('obj') may not be the receiver ('this').
1162 // When this getter is called the first time, we use the context values to
1163 // format a stack trace string and turn this accessor pair into a data
1164 // property (on the holder).
1165 var getter = function() {
1166 // Stack is still a raw array awaiting to be formatted.
1167 var result = FormatStackTrace(obj, error_string, GetStackFrames(stack));
1168 // Turn this accessor into a data property.
1169 %DefineOrRedefineDataProperty(obj, 'stack', result, NONE);
1170 // Release context values.
1171 stack = error_string = UNDEFINED;
1175 // Set the 'stack' property on the receiver. If the receiver is the same as
1176 // holder of this setter, the accessor pair is turned into a data property.
1177 var setter = function(v) {
1178 // Set data property on the receiver (not necessarily holder).
1179 %DefineOrRedefineDataProperty(this, 'stack', v, NONE);
1181 // Release context values if holder is the same as the receiver.
1182 stack = error_string = UNDEFINED;
1186 %DefineOrRedefineAccessorProperty(obj, 'stack', getter, setter, DONT_ENUM);
1190 function SetUpError() {
1191 // Define special error type constructors.
1193 var DefineError = function(f) {
1194 // Store the error function in both the global object
1195 // and the runtime object. The function is fetched
1196 // from the runtime object when throwing errors from
1197 // within the runtime system to avoid strange side
1198 // effects when overwriting the error functions from
1201 %SetProperty(global, name, f, DONT_ENUM);
1202 %SetProperty(builtins, '$' + name, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
1203 // Configure the error function.
1204 if (name == 'Error') {
1205 // The prototype of the Error object must itself be an error.
1206 // However, it can't be an instance of the Error object because
1207 // it hasn't been properly configured yet. Instead we create a
1208 // special not-a-true-error-but-close-enough object.
1209 var ErrorPrototype = function() {};
1210 %FunctionSetPrototype(ErrorPrototype, $Object.prototype);
1211 %FunctionSetInstanceClassName(ErrorPrototype, 'Error');
1212 %FunctionSetPrototype(f, new ErrorPrototype());
1214 %FunctionSetPrototype(f, new $Error());
1216 %FunctionSetInstanceClassName(f, 'Error');
1217 %SetProperty(f.prototype, 'constructor', f, DONT_ENUM);
1218 %SetProperty(f.prototype, "name", name, DONT_ENUM);
1219 %SetCode(f, function(m) {
1220 if (%_IsConstructCall()) {
1221 // Define all the expected properties directly on the error
1222 // object. This avoids going through getters and setters defined
1223 // on prototype objects.
1224 %IgnoreAttributesAndSetProperty(this, 'stack', UNDEFINED, DONT_ENUM);
1225 if (!IS_UNDEFINED(m)) {
1226 %IgnoreAttributesAndSetProperty(
1227 this, 'message', ToString(m), DONT_ENUM);
1229 captureStackTrace(this, f);
1237 DefineError(function Error() { });
1238 DefineError(function TypeError() { });
1239 DefineError(function RangeError() { });
1240 DefineError(function SyntaxError() { });
1241 DefineError(function ReferenceError() { });
1242 DefineError(function EvalError() { });
1243 DefineError(function URIError() { });
1248 $Error.captureStackTrace = captureStackTrace;
1250 %SetProperty($Error.prototype, 'message', '', DONT_ENUM);
1252 // Global list of error objects visited during ErrorToString. This is
1253 // used to detect cycles in error toString formatting.
1254 var visited_errors = new InternalArray();
1255 var cyclic_error_marker = new $Object();
1257 function GetPropertyWithoutInvokingMonkeyGetters(error, name) {
1258 var current = error;
1259 // Climb the prototype chain until we find the holder.
1260 while (current && !%HasLocalProperty(current, name)) {
1261 current = %GetPrototype(current);
1263 if (IS_NULL(current)) return UNDEFINED;
1264 if (!IS_OBJECT(current)) return error[name];
1265 // If the property is an accessor on one of the predefined errors that can be
1266 // generated statically by the compiler, don't touch it. This is to address
1267 // http://code.google.com/p/chromium/issues/detail?id=69187
1268 var desc = %GetOwnProperty(current, name);
1269 if (desc && desc[IS_ACCESSOR_INDEX]) {
1270 var isName = name === "name";
1271 if (current === $ReferenceError.prototype)
1272 return isName ? "ReferenceError" : UNDEFINED;
1273 if (current === $SyntaxError.prototype)
1274 return isName ? "SyntaxError" : UNDEFINED;
1275 if (current === $TypeError.prototype)
1276 return isName ? "TypeError" : UNDEFINED;
1278 // Otherwise, read normally.
1282 function ErrorToStringDetectCycle(error) {
1283 if (!%PushIfAbsent(visited_errors, error)) throw cyclic_error_marker;
1285 var name = GetPropertyWithoutInvokingMonkeyGetters(error, "name");
1286 name = IS_UNDEFINED(name) ? "Error" : TO_STRING_INLINE(name);
1287 var message = GetPropertyWithoutInvokingMonkeyGetters(error, "message");
1288 message = IS_UNDEFINED(message) ? "" : TO_STRING_INLINE(message);
1289 if (name === "") return message;
1290 if (message === "") return name;
1291 return name + ": " + message;
1293 visited_errors.length = visited_errors.length - 1;
1297 function ErrorToString() {
1298 if (!IS_SPEC_OBJECT(this)) {
1299 throw MakeTypeError("called_on_non_object", ["Error.prototype.toString"]);
1303 return ErrorToStringDetectCycle(this);
1305 // If this error message was encountered already return the empty
1306 // string for it instead of recursively formatting it.
1307 if (e === cyclic_error_marker) {
1315 InstallFunctions($Error.prototype, DONT_ENUM, ['toString', ErrorToString]);
1317 // Boilerplate for exceptions for stack overflows. Used from
1318 // Isolate::StackOverflow().
1319 function SetUpStackOverflowBoilerplate() {
1320 var boilerplate = MakeRangeError('stack_overflow', []);
1322 var error_string = boilerplate.name + ": " + boilerplate.message;
1324 // The raw stack trace is stored as a hidden property on the holder of this
1325 // getter, which may not be the same as the receiver. Find the holder to
1326 // retrieve the raw stack trace and then turn this accessor pair into a
1328 var getter = function() {
1330 while (!IS_ERROR(holder)) {
1331 holder = %GetPrototype(holder);
1332 if (IS_NULL(holder)) return MakeSyntaxError('illegal_access', []);
1334 var stack = %GetAndClearOverflowedStackTrace(holder);
1335 // We may not have captured any stack trace.
1336 if (IS_UNDEFINED(stack)) return stack;
1338 var result = FormatStackTrace(holder, error_string, GetStackFrames(stack));
1339 // Replace this accessor with a data property.
1340 %DefineOrRedefineDataProperty(holder, 'stack', result, NONE);
1344 // Set the 'stack' property on the receiver. If the receiver is the same as
1345 // holder of this setter, the accessor pair is turned into a data property.
1346 var setter = function(v) {
1347 %DefineOrRedefineDataProperty(this, 'stack', v, NONE);
1348 // Tentatively clear the hidden property. If the receiver is the same as
1349 // holder, we release the raw stack trace this way.
1350 %GetAndClearOverflowedStackTrace(this);
1353 %DefineOrRedefineAccessorProperty(
1354 boilerplate, 'stack', getter, setter, DONT_ENUM);
1359 var kStackOverflowBoilerplate = SetUpStackOverflowBoilerplate();