1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // -------------------------------------------------------------------
9 cyclic_proto: ["Cyclic __proto__ value"],
10 code_gen_from_strings: ["%0"],
11 generator_running: ["Generator is already running"],
12 generator_finished: ["Generator has already finished"],
14 unexpected_token: ["Unexpected token ", "%0"],
15 unexpected_token_number: ["Unexpected number"],
16 unexpected_token_string: ["Unexpected string"],
17 unexpected_token_identifier: ["Unexpected identifier"],
18 unexpected_reserved: ["Unexpected reserved word"],
19 unexpected_strict_reserved: ["Unexpected strict mode reserved word"],
20 unexpected_eos: ["Unexpected end of input"],
21 malformed_regexp: ["Invalid regular expression: /", "%0", "/: ", "%1"],
22 unterminated_regexp: ["Invalid regular expression: missing /"],
23 regexp_flags: ["Cannot supply flags when constructing one RegExp from another"],
24 incompatible_method_receiver: ["Method ", "%0", " called on incompatible receiver ", "%1"],
25 multiple_defaults_in_switch: ["More than one default clause in switch statement"],
26 newline_after_throw: ["Illegal newline after throw"],
27 label_redeclaration: ["Label '", "%0", "' has already been declared"],
28 var_redeclaration: ["Identifier '", "%0", "' has already been declared"],
29 no_catch_or_finally: ["Missing catch or finally after try"],
30 unknown_label: ["Undefined label '", "%0", "'"],
31 uncaught_exception: ["Uncaught ", "%0"],
32 stack_trace: ["Stack Trace:\n", "%0"],
33 called_non_callable: ["%0", " is not a function"],
34 undefined_method: ["Object ", "%1", " has no method '", "%0", "'"],
35 property_not_function: ["Property '", "%0", "' of object ", "%1", " is not a function"],
36 cannot_convert_to_primitive: ["Cannot convert object to primitive value"],
37 not_constructor: ["%0", " is not a constructor"],
38 not_defined: ["%0", " is not defined"],
39 non_object_property_load: ["Cannot read property '", "%0", "' of ", "%1"],
40 non_object_property_store: ["Cannot set property '", "%0", "' of ", "%1"],
41 with_expression: ["%0", " has no properties"],
42 illegal_invocation: ["Illegal invocation"],
43 no_setter_in_callback: ["Cannot set property ", "%0", " of ", "%1", " which has only a getter"],
44 apply_non_function: ["Function.prototype.apply was called on ", "%0", ", which is a ", "%1", " and not a function"],
45 apply_wrong_args: ["Function.prototype.apply: Arguments list has wrong type"],
46 invalid_in_operator_use: ["Cannot use 'in' operator to search for '", "%0", "' in ", "%1"],
47 instanceof_function_expected: ["Expecting a function in instanceof check, but got ", "%0"],
48 instanceof_nonobject_proto: ["Function has non-object prototype '", "%0", "' in instanceof check"],
49 undefined_or_null_to_object: ["Cannot convert undefined or null to object"],
50 reduce_no_initial: ["Reduce of empty array with no initial value"],
51 getter_must_be_callable: ["Getter must be a function: ", "%0"],
52 setter_must_be_callable: ["Setter must be a function: ", "%0"],
53 value_and_accessor: ["Invalid property. A property cannot both have accessors and be writable or have a value, ", "%0"],
54 proto_object_or_null: ["Object prototype may only be an Object or null: ", "%0"],
55 property_desc_object: ["Property description must be an object: ", "%0"],
56 redefine_disallowed: ["Cannot redefine property: ", "%0"],
57 define_disallowed: ["Cannot define property:", "%0", ", object is not extensible."],
58 non_extensible_proto: ["%0", " is not extensible"],
59 handler_non_object: ["Proxy.", "%0", " called with non-object as handler"],
60 proto_non_object: ["Proxy.", "%0", " called with non-object as prototype"],
61 trap_function_expected: ["Proxy.", "%0", " called with non-function for '", "%1", "' trap"],
62 handler_trap_missing: ["Proxy handler ", "%0", " has no '", "%1", "' trap"],
63 handler_trap_must_be_callable: ["Proxy handler ", "%0", " has non-callable '", "%1", "' trap"],
64 handler_returned_false: ["Proxy handler ", "%0", " returned false from '", "%1", "' trap"],
65 handler_returned_undefined: ["Proxy handler ", "%0", " returned undefined from '", "%1", "' trap"],
66 proxy_prop_not_configurable: ["Proxy handler ", "%0", " returned non-configurable descriptor for property '", "%2", "' from '", "%1", "' trap"],
67 proxy_non_object_prop_names: ["Trap '", "%1", "' returned non-object ", "%0"],
68 proxy_repeated_prop_name: ["Trap '", "%1", "' returned repeated property name '", "%2", "'"],
69 invalid_weakmap_key: ["Invalid value used as weak map key"],
70 invalid_weakset_value: ["Invalid value used in weak set"],
71 not_date_object: ["this is not a Date object."],
72 observe_non_object: ["Object.", "%0", " cannot ", "%0", " non-object"],
73 observe_non_function: ["Object.", "%0", " cannot deliver to non-function"],
74 observe_callback_frozen: ["Object.observe cannot deliver to a frozen function object"],
75 observe_invalid_accept: ["Object.observe accept must be an array of strings."],
76 observe_type_non_string: ["Invalid changeRecord with non-string 'type' property"],
77 observe_perform_non_string: ["Invalid non-string changeType"],
78 observe_perform_non_function: ["Cannot perform non-function"],
79 observe_notify_non_notifier: ["notify called on non-notifier object"],
80 observe_global_proxy: ["%0", " cannot be called on the global proxy object"],
81 not_typed_array: ["this is not a typed array."],
82 invalid_argument: ["invalid_argument"],
83 data_view_not_array_buffer: ["First argument to DataView constructor must be an ArrayBuffer"],
84 constructor_not_function: ["Constructor ", "%0", " requires 'new'"],
85 not_a_symbol: ["%0", " is not a symbol"],
86 not_a_promise: ["%0", " is not a promise"],
87 resolver_not_a_function: ["Promise resolver ", "%0", " is not a function"],
88 promise_cyclic: ["Chaining cycle detected for promise ", "%0"],
89 array_functions_on_frozen: ["Cannot modify frozen array elements"],
90 array_functions_change_sealed: ["Cannot add/remove sealed array elements"],
91 first_argument_not_regexp: ["First argument to ", "%0", " must not be a regular expression"],
93 invalid_array_length: ["Invalid array length"],
94 invalid_array_buffer_length: ["Invalid array buffer length"],
95 invalid_string_length: ["Invalid string length"],
96 invalid_typed_array_offset: ["Start offset is too large:"],
97 invalid_typed_array_length: ["Invalid typed array length"],
98 invalid_typed_array_alignment: ["%0", " of ", "%1", " should be a multiple of ", "%2"],
99 typed_array_set_source_too_large:
100 ["Source is too large"],
101 typed_array_set_negative_offset:
102 ["Start offset is negative"],
103 invalid_data_view_offset: ["Start offset is outside the bounds of the buffer"],
104 invalid_data_view_length: ["Invalid data view length"],
105 invalid_data_view_accessor_offset:
106 ["Offset is outside the bounds of the DataView"],
108 stack_overflow: ["Maximum call stack size exceeded"],
109 invalid_time_value: ["Invalid time value"],
110 invalid_count_value: ["Invalid count value"],
112 invalid_lhs_in_assignment: ["Invalid left-hand side in assignment"],
113 invalid_lhs_in_for: ["Invalid left-hand side in for-loop"],
114 invalid_lhs_in_postfix_op: ["Invalid left-hand side expression in postfix operation"],
115 invalid_lhs_in_prefix_op: ["Invalid left-hand side expression in prefix operation"],
117 paren_in_arg_string: ["Function arg string contains parenthesis"],
118 not_isvar: ["builtin %IS_VAR: not a variable"],
119 single_function_literal: ["Single function literal required"],
120 invalid_regexp_flags: ["Invalid flags supplied to RegExp constructor '", "%0", "'"],
121 invalid_regexp: ["Invalid RegExp pattern /", "%0", "/"],
122 illegal_break: ["Illegal break statement"],
123 illegal_continue: ["Illegal continue statement"],
124 illegal_return: ["Illegal return statement"],
125 illegal_let: ["Illegal let declaration outside extended mode"],
126 error_loading_debugger: ["Error loading debugger"],
127 no_input_to_regexp: ["No input to ", "%0"],
128 invalid_json: ["String '", "%0", "' is not valid JSON"],
129 circular_structure: ["Converting circular structure to JSON"],
130 called_on_non_object: ["%0", " called on non-object"],
131 called_on_null_or_undefined: ["%0", " called on null or undefined"],
132 array_indexof_not_defined: ["Array.getIndexOf: Argument undefined"],
133 object_not_extensible: ["Can't add property ", "%0", ", object is not extensible"],
134 illegal_access: ["Illegal access"],
135 invalid_cached_data_function: ["Invalid cached data for function ", "%0"],
136 invalid_cached_data: ["Invalid cached data"],
137 strict_mode_with: ["Strict mode code may not include a with statement"],
138 strict_eval_arguments: ["Unexpected eval or arguments in strict mode"],
139 too_many_arguments: ["Too many arguments in function call (only 65535 allowed)"],
140 too_many_parameters: ["Too many parameters in function definition (only 65535 allowed)"],
141 too_many_variables: ["Too many variables declared (only 4194303 allowed)"],
142 strict_param_dupe: ["Strict mode function may not have duplicate parameter names"],
143 strict_octal_literal: ["Octal literals are not allowed in strict mode."],
144 strict_duplicate_property: ["Duplicate data property in object literal not allowed in strict mode"],
145 accessor_data_property: ["Object literal may not have data and accessor property with the same name"],
146 accessor_get_set: ["Object literal may not have multiple get/set accessors with the same name"],
147 strict_delete: ["Delete of an unqualified identifier in strict mode."],
148 strict_delete_property: ["Cannot delete property '", "%0", "' of ", "%1"],
149 strict_const: ["Use of const in strict mode."],
150 strict_function: ["In strict mode code, functions can only be declared at top level or immediately within another function." ],
151 strict_read_only_property: ["Cannot assign to read only property '", "%0", "' of ", "%1"],
152 strict_cannot_assign: ["Cannot assign to read only '", "%0", "' in strict mode"],
153 strict_poison_pill: ["'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them"],
154 strict_caller: ["Illegal access to a strict mode caller function."],
155 unprotected_let: ["Illegal let declaration in unprotected statement context."],
156 unprotected_const: ["Illegal const declaration in unprotected statement context."],
157 cant_prevent_ext_external_array_elements: ["Cannot prevent extension of an object with external array elements"],
158 redef_external_array_element: ["Cannot redefine a property of an object with external array elements"],
159 harmony_const_assign: ["Assignment to constant variable."],
160 symbol_to_string: ["Cannot convert a Symbol value to a string"],
161 symbol_to_primitive: ["Cannot convert a Symbol wrapper object to a primitive value"],
162 invalid_module_path: ["Module does not export '", "%0", "', or export is not itself a module"],
163 module_type_error: ["Module '", "%0", "' used improperly"],
164 module_export_undefined: ["Export '", "%0", "' is not defined in module"]
168 function FormatString(format, args) {
171 for (var i = 0; i < format.length; i++) {
173 if (str.length == 2 && %_StringCharCodeAt(str, 0) == 0x25) {
174 // Two-char string starts with "%".
175 var arg_num = (%_StringCharCodeAt(str, 1) - 0x30) >>> 0;
177 // str is one of %0, %1, %2 or %3.
179 str = NoSideEffectToString(args[arg_num]);
180 if (str.length > 256) {
181 str = %_SubString(str, 0, 239) + "...<omitted>..." +
182 %_SubString(str, str.length - 2, str.length);
185 if (%IsJSModule(args[arg_num]))
187 else if (IS_SPEC_OBJECT(args[arg_num]))
200 function NoSideEffectToString(obj) {
201 if (IS_STRING(obj)) return obj;
202 if (IS_NUMBER(obj)) return %_NumberToString(obj);
203 if (IS_BOOLEAN(obj)) return x ? 'true' : 'false';
204 if (IS_UNDEFINED(obj)) return 'undefined';
205 if (IS_NULL(obj)) return 'null';
206 if (IS_FUNCTION(obj)) return %_CallFunction(obj, FunctionToString);
207 if (IS_OBJECT(obj) && %GetDataProperty(obj, "toString") === ObjectToString) {
208 var constructor = %GetDataProperty(obj, "constructor");
209 if (typeof constructor == "function") {
210 var constructorName = constructor.name;
211 if (IS_STRING(constructorName) && constructorName !== "") {
212 return "#<" + constructorName + ">";
216 if (CanBeSafelyTreatedAsAnErrorObject(obj)) {
217 return %_CallFunction(obj, ErrorToString);
219 return %_CallFunction(obj, ObjectToString);
222 // To determine whether we can safely stringify an object using ErrorToString
223 // without the risk of side-effects, we need to check whether the object is
224 // either an instance of a native error type (via '%_ClassOf'), or has $Error
225 // in its prototype chain and hasn't overwritten 'toString' with something
226 // strange and unusual.
227 function CanBeSafelyTreatedAsAnErrorObject(obj) {
228 switch (%_ClassOf(obj)) {
232 case 'ReferenceError':
239 var objToString = %GetDataProperty(obj, "toString");
240 return obj instanceof $Error && objToString === ErrorToString;
244 // When formatting internally created error messages, do not
245 // invoke overwritten error toString methods but explicitly use
246 // the error to string method. This is to avoid leaking error
247 // objects between script tags in a browser setting.
248 function ToStringCheckErrorObject(obj) {
249 if (CanBeSafelyTreatedAsAnErrorObject(obj)) {
250 return %_CallFunction(obj, ErrorToString);
252 return ToString(obj);
257 function ToDetailString(obj) {
258 if (obj != null && IS_OBJECT(obj) && obj.toString === ObjectToString) {
259 var constructor = obj.constructor;
260 if (typeof constructor == "function") {
261 var constructorName = constructor.name;
262 if (IS_STRING(constructorName) && constructorName !== "") {
263 return "#<" + constructorName + ">";
267 return ToStringCheckErrorObject(obj);
271 function MakeGenericError(constructor, type, args) {
272 if (IS_UNDEFINED(args)) args = [];
273 return new constructor(FormatMessage(type, args));
278 * Set up the Script function and constructor.
280 %FunctionSetInstanceClassName(Script, 'Script');
281 %SetProperty(Script.prototype, 'constructor', Script,
282 DONT_ENUM | DONT_DELETE | READ_ONLY);
283 %SetCode(Script, function(x) {
284 // Script objects can only be created by the VM.
285 throw new $Error("Not supported");
289 // Helper functions; called from the runtime system.
290 function FormatMessage(type, args) {
291 var format = kMessages[type];
292 if (!format) return "<unknown message " + type + ">";
293 return FormatString(format, args);
297 function GetLineNumber(message) {
298 var start_position = %MessageGetStartPosition(message);
299 if (start_position == -1) return kNoLineNumberInfo;
300 var script = %MessageGetScript(message);
301 var location = script.locationFromPosition(start_position, true);
302 if (location == null) return kNoLineNumberInfo;
303 return location.line + 1;
307 // Returns the source code line containing the given source
308 // position, or the empty string if the position is invalid.
309 function GetSourceLine(message) {
310 var script = %MessageGetScript(message);
311 var start_position = %MessageGetStartPosition(message);
312 var location = script.locationFromPosition(start_position, true);
313 if (location == null) return "";
315 return location.sourceText();
319 function MakeTypeError(type, args) {
320 return MakeGenericError($TypeError, type, args);
324 function MakeRangeError(type, args) {
325 return MakeGenericError($RangeError, type, args);
329 function MakeSyntaxError(type, args) {
330 return MakeGenericError($SyntaxError, type, args);
334 function MakeReferenceError(type, args) {
335 return MakeGenericError($ReferenceError, type, args);
339 function MakeEvalError(type, args) {
340 return MakeGenericError($EvalError, type, args);
344 function MakeError(type, args) {
345 return MakeGenericError($Error, type, args);
349 * Find a line number given a specific source position.
350 * @param {number} position The source position.
351 * @return {number} 0 if input too small, -1 if input too large,
352 else the line number.
354 function ScriptLineFromPosition(position) {
356 var upper = this.lineCount() - 1;
357 var line_ends = this.line_ends;
359 // We'll never find invalid positions so bail right away.
360 if (position > line_ends[upper]) {
364 // This means we don't have to safe-guard indexing line_ends[i - 1].
365 if (position <= line_ends[0]) {
369 // Binary search to find line # from position range.
371 var i = (lower + upper) >> 1;
373 if (position > line_ends[i]) {
375 } else if (position <= line_ends[i - 1]) {
386 * Get information on a specific source position.
387 * @param {number} position The source position
388 * @param {boolean} include_resource_offset Set to true to have the resource
389 * offset added to the location
390 * @return {SourceLocation}
391 * If line is negative or not in the source null is returned.
393 function ScriptLocationFromPosition(position,
394 include_resource_offset) {
395 var line = this.lineFromPosition(position);
396 if (line == -1) return null;
398 // Determine start, end and column.
399 var line_ends = this.line_ends;
400 var start = line == 0 ? 0 : line_ends[line - 1] + 1;
401 var end = line_ends[line];
402 if (end > 0 && %_CallFunction(this.source, end - 1, StringCharAt) == '\r') {
405 var column = position - start;
407 // Adjust according to the offset within the resource.
408 if (include_resource_offset) {
409 line += this.line_offset;
410 if (line == this.line_offset) {
411 column += this.column_offset;
415 return new SourceLocation(this, position, line, column, start, end);
420 * Get information on a specific source line and column possibly offset by a
421 * fixed source position. This function is used to find a source position from
422 * a line and column position. The fixed source position offset is typically
423 * used to find a source position in a function based on a line and column in
424 * the source for the function alone. The offset passed will then be the
425 * start position of the source for the function within the full script source.
426 * @param {number} opt_line The line within the source. Default value is 0
427 * @param {number} opt_column The column in within the line. Default value is 0
428 * @param {number} opt_offset_position The offset from the begining of the
429 * source from where the line and column calculation starts.
431 * @return {SourceLocation}
432 * If line is negative or not in the source null is returned.
434 function ScriptLocationFromLine(opt_line, opt_column, opt_offset_position) {
435 // Default is the first line in the script. Lines in the script is relative
436 // to the offset within the resource.
438 if (!IS_UNDEFINED(opt_line)) {
439 line = opt_line - this.line_offset;
442 // Default is first column. If on the first line add the offset within the
444 var column = opt_column || 0;
446 column -= this.column_offset;
449 var offset_position = opt_offset_position || 0;
450 if (line < 0 || column < 0 || offset_position < 0) return null;
452 return this.locationFromPosition(offset_position + column, false);
454 // Find the line where the offset position is located.
455 var offset_line = this.lineFromPosition(offset_position);
457 if (offset_line == -1 || offset_line + line >= this.lineCount()) {
461 return this.locationFromPosition(
462 this.line_ends[offset_line + line - 1] + 1 + column); // line > 0 here.
468 * Get a slice of source code from the script. The boundaries for the slice is
469 * specified in lines.
470 * @param {number} opt_from_line The first line (zero bound) in the slice.
472 * @param {number} opt_to_column The last line (zero bound) in the slice (non
473 * inclusive). Default is the number of lines in the script
474 * @return {SourceSlice} The source slice or null of the parameters where
477 function ScriptSourceSlice(opt_from_line, opt_to_line) {
478 var from_line = IS_UNDEFINED(opt_from_line) ? this.line_offset
480 var to_line = IS_UNDEFINED(opt_to_line) ? this.line_offset + this.lineCount()
483 // Adjust according to the offset within the resource.
484 from_line -= this.line_offset;
485 to_line -= this.line_offset;
486 if (from_line < 0) from_line = 0;
487 if (to_line > this.lineCount()) to_line = this.lineCount();
490 if (from_line >= this.lineCount() ||
492 from_line > to_line) {
496 var line_ends = this.line_ends;
497 var from_position = from_line == 0 ? 0 : line_ends[from_line - 1] + 1;
498 var to_position = to_line == 0 ? 0 : line_ends[to_line - 1] + 1;
500 // Return a source slice with line numbers re-adjusted to the resource.
501 return new SourceSlice(this,
502 from_line + this.line_offset,
503 to_line + this.line_offset,
504 from_position, to_position);
508 function ScriptSourceLine(opt_line) {
509 // Default is the first line in the script. Lines in the script are relative
510 // to the offset within the resource.
512 if (!IS_UNDEFINED(opt_line)) {
513 line = opt_line - this.line_offset;
517 if (line < 0 || this.lineCount() <= line) {
521 // Return the source line.
522 var line_ends = this.line_ends;
523 var start = line == 0 ? 0 : line_ends[line - 1] + 1;
524 var end = line_ends[line];
525 return %_CallFunction(this.source, start, end, StringSubstring);
530 * Returns the number of source lines.
532 * Number of source lines.
534 function ScriptLineCount() {
535 // Return number of source lines.
536 return this.line_ends.length;
541 * If sourceURL comment is available and script starts at zero returns sourceURL
542 * comment contents. Otherwise, script name is returned. See
543 * http://fbug.googlecode.com/svn/branches/firebug1.1/docs/ReleaseNotes_1.1.txt
544 * and Source Map Revision 3 proposal for details on using //# sourceURL and
545 * deprecated //@ sourceURL comment to identify scripts that don't have name.
547 * @return {?string} script name if present, value for //# sourceURL or
548 * deprecated //@ sourceURL comment otherwise.
550 function ScriptNameOrSourceURL() {
551 if (this.line_offset > 0 || this.column_offset > 0) {
555 // The result is cached as on long scripts it takes noticable time to search
556 // for the sourceURL.
557 if (this.hasCachedNameOrSourceURL) {
558 return this.cachedNameOrSourceURL;
560 this.hasCachedNameOrSourceURL = true;
562 // TODO(608): the spaces in a regexp below had to be escaped as \040
563 // because this file is being processed by js2c whose handling of spaces
564 // in regexps is broken. Also, ['"] are excluded from allowed URLs to
565 // avoid matches against sources that invoke evals with sourceURL.
566 // A better solution would be to detect these special comments in
567 // the scanner/parser.
568 var source = ToString(this.source);
569 var sourceUrlPos = %StringIndexOf(source, "sourceURL=", 0);
570 this.cachedNameOrSourceURL = this.name;
571 if (sourceUrlPos > 4) {
572 var sourceUrlPattern =
573 /\/\/[#@][\040\t]sourceURL=[\040\t]*([^\s\'\"]*)[\040\t]*$/gm;
574 // Don't reuse lastMatchInfo here, so we create a new array with room
575 // for four captures (array with length one longer than the index
576 // of the fourth capture, where the numbering is zero-based).
577 var matchInfo = new InternalArray(CAPTURE(3) + 1);
579 %_RegExpExec(sourceUrlPattern, source, sourceUrlPos - 4, matchInfo);
581 this.cachedNameOrSourceURL =
582 %_SubString(source, matchInfo[CAPTURE(2)], matchInfo[CAPTURE(3)]);
585 return this.cachedNameOrSourceURL;
589 SetUpLockedPrototype(Script,
590 $Array("source", "name", "line_ends", "line_offset", "column_offset",
591 "cachedNameOrSourceURL", "hasCachedNameOrSourceURL" ),
593 "lineFromPosition", ScriptLineFromPosition,
594 "locationFromPosition", ScriptLocationFromPosition,
595 "locationFromLine", ScriptLocationFromLine,
596 "sourceSlice", ScriptSourceSlice,
597 "sourceLine", ScriptSourceLine,
598 "lineCount", ScriptLineCount,
599 "nameOrSourceURL", ScriptNameOrSourceURL
605 * Class for source location. A source location is a position within some
606 * source with the following properties:
607 * script : script object for the source
608 * line : source line number
609 * column : source column within the line
610 * position : position within the source
611 * start : position of start of source context (inclusive)
612 * end : position of end of source context (not inclusive)
613 * Source text for the source context is the character interval
614 * [start, end[. In most cases end will point to a newline character.
615 * It might point just past the final position of the source if the last
616 * source line does not end with a newline character.
617 * @param {Script} script The Script object for which this is a location
618 * @param {number} position Source position for the location
619 * @param {number} line The line number for the location
620 * @param {number} column The column within the line for the location
621 * @param {number} start Source position for start of source context
622 * @param {number} end Source position for end of source context
625 function SourceLocation(script, position, line, column, start, end) {
626 this.script = script;
627 this.position = position;
629 this.column = column;
634 var kLineLengthLimit = 78;
637 * Restrict source location start and end positions to make the source slice
638 * no more that a certain number of characters wide.
639 * @param {number} opt_limit The with limit of the source text with a default
641 * @param {number} opt_before The number of characters to prefer before the
642 * position with a default value of 10 less that the limit
644 function SourceLocationRestrict(opt_limit, opt_before) {
645 // Find the actual limit to use.
648 if (!IS_UNDEFINED(opt_limit)) {
651 limit = kLineLengthLimit;
653 if (!IS_UNDEFINED(opt_before)) {
656 // If no before is specified center for small limits and perfer more source
657 // before the the position that after for longer limits.
659 before = $floor(limit / 2);
664 if (before >= limit) {
668 // If the [start, end[ interval is too big we restrict
669 // it in one or both ends. We make sure to always produce
670 // restricted intervals of maximum allowed size.
671 if (this.end - this.start > limit) {
672 var start_limit = this.position - before;
673 var end_limit = this.position + limit - before;
674 if (this.start < start_limit && end_limit < this.end) {
675 this.start = start_limit;
676 this.end = end_limit;
677 } else if (this.start < start_limit) {
678 this.start = this.end - limit;
680 this.end = this.start + limit;
687 * Get the source text for a SourceLocation
689 * Source text for this location.
691 function SourceLocationSourceText() {
692 return %_CallFunction(this.script.source,
699 SetUpLockedPrototype(SourceLocation,
700 $Array("script", "position", "line", "column", "start", "end"),
702 "restrict", SourceLocationRestrict,
703 "sourceText", SourceLocationSourceText
709 * Class for a source slice. A source slice is a part of a script source with
710 * the following properties:
711 * script : script object for the source
712 * from_line : line number for the first line in the slice
713 * to_line : source line number for the last line in the slice
714 * from_position : position of the first character in the slice
715 * to_position : position of the last character in the slice
716 * The to_line and to_position are not included in the slice, that is the lines
717 * in the slice are [from_line, to_line[. Likewise the characters in the slice
718 * are [from_position, to_position[.
719 * @param {Script} script The Script object for the source slice
720 * @param {number} from_line
721 * @param {number} to_line
722 * @param {number} from_position
723 * @param {number} to_position
726 function SourceSlice(script, from_line, to_line, from_position, to_position) {
727 this.script = script;
728 this.from_line = from_line;
729 this.to_line = to_line;
730 this.from_position = from_position;
731 this.to_position = to_position;
735 * Get the source text for a SourceSlice
736 * @return {String} Source text for this slice. The last line will include
737 * the line terminating characters (if any)
739 function SourceSliceSourceText() {
740 return %_CallFunction(this.script.source,
746 SetUpLockedPrototype(SourceSlice,
747 $Array("script", "from_line", "to_line", "from_position", "to_position"),
748 $Array("sourceText", SourceSliceSourceText)
752 // Returns the offset of the given position within the containing
754 function GetPositionInLine(message) {
755 var script = %MessageGetScript(message);
756 var start_position = %MessageGetStartPosition(message);
757 var location = script.locationFromPosition(start_position, false);
758 if (location == null) return -1;
760 return start_position - location.start;
764 function GetStackTraceLine(recv, fun, pos, isGlobal) {
765 return new CallSite(recv, fun, pos, false).toString();
768 // ----------------------------------------------------------------------------
769 // Error implementation
771 var CallSiteReceiverKey = NEW_PRIVATE("CallSite#receiver");
772 var CallSiteFunctionKey = NEW_PRIVATE("CallSite#function");
773 var CallSitePositionKey = NEW_PRIVATE("CallSite#position");
774 var CallSiteStrictModeKey = NEW_PRIVATE("CallSite#strict_mode");
776 function CallSite(receiver, fun, pos, strict_mode) {
777 SET_PRIVATE(this, CallSiteReceiverKey, receiver);
778 SET_PRIVATE(this, CallSiteFunctionKey, fun);
779 SET_PRIVATE(this, CallSitePositionKey, pos);
780 SET_PRIVATE(this, CallSiteStrictModeKey, strict_mode);
783 function CallSiteGetThis() {
784 return GET_PRIVATE(this, CallSiteStrictModeKey)
785 ? UNDEFINED : GET_PRIVATE(this, CallSiteReceiverKey);
788 function CallSiteGetTypeName() {
789 return GetTypeName(GET_PRIVATE(this, CallSiteReceiverKey), false);
792 function CallSiteIsToplevel() {
793 if (GET_PRIVATE(this, CallSiteReceiverKey) == null) {
796 return IS_GLOBAL(GET_PRIVATE(this, CallSiteReceiverKey));
799 function CallSiteIsEval() {
800 var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey));
801 return script && script.compilation_type == COMPILATION_TYPE_EVAL;
804 function CallSiteGetEvalOrigin() {
805 var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey));
806 return FormatEvalOrigin(script);
809 function CallSiteGetScriptNameOrSourceURL() {
810 var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey));
811 return script ? script.nameOrSourceURL() : null;
814 function CallSiteGetFunction() {
815 return GET_PRIVATE(this, CallSiteStrictModeKey)
816 ? UNDEFINED : GET_PRIVATE(this, CallSiteFunctionKey);
819 function CallSiteGetFunctionName() {
820 // See if the function knows its own name
821 var name = GET_PRIVATE(this, CallSiteFunctionKey).name;
825 name = %FunctionGetInferredName(GET_PRIVATE(this, CallSiteFunctionKey));
829 // Maybe this is an evaluation?
830 var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey));
831 if (script && script.compilation_type == COMPILATION_TYPE_EVAL) {
837 function CallSiteGetMethodName() {
838 // See if we can find a unique property on the receiver that holds
840 var receiver = GET_PRIVATE(this, CallSiteReceiverKey);
841 var fun = GET_PRIVATE(this, CallSiteFunctionKey);
842 var ownName = fun.name;
843 if (ownName && receiver &&
844 (%_CallFunction(receiver, ownName, ObjectLookupGetter) === fun ||
845 %_CallFunction(receiver, ownName, ObjectLookupSetter) === fun ||
846 (IS_OBJECT(receiver) && %GetDataProperty(receiver, ownName) === fun))) {
847 // To handle DontEnum properties we guess that the method has
848 // the same name as the function.
852 for (var prop in receiver) {
853 if (%_CallFunction(receiver, prop, ObjectLookupGetter) === fun ||
854 %_CallFunction(receiver, prop, ObjectLookupSetter) === fun ||
855 (IS_OBJECT(receiver) && %GetDataProperty(receiver, prop) === fun)) {
856 // If we find more than one match bail out to avoid confusion.
869 function CallSiteGetFileName() {
870 var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey));
871 return script ? script.name : null;
874 function CallSiteGetLineNumber() {
875 if (GET_PRIVATE(this, CallSitePositionKey) == -1) {
878 var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey));
881 location = script.locationFromPosition(
882 GET_PRIVATE(this, CallSitePositionKey), true);
884 return location ? location.line + 1 : null;
887 function CallSiteGetColumnNumber() {
888 if (GET_PRIVATE(this, CallSitePositionKey) == -1) {
891 var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey));
894 location = script.locationFromPosition(
895 GET_PRIVATE(this, CallSitePositionKey), true);
897 return location ? location.column + 1: null;
900 function CallSiteIsNative() {
901 var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey));
902 return script ? (script.type == TYPE_NATIVE) : false;
905 function CallSiteGetPosition() {
906 return GET_PRIVATE(this, CallSitePositionKey);
909 function CallSiteIsConstructor() {
910 var receiver = GET_PRIVATE(this, CallSiteReceiverKey);
911 var constructor = (receiver != null && IS_OBJECT(receiver))
912 ? %GetDataProperty(receiver, "constructor") : null;
913 if (!constructor) return false;
914 return GET_PRIVATE(this, CallSiteFunctionKey) === constructor;
917 function CallSiteToString() {
919 var fileLocation = "";
920 if (this.isNative()) {
921 fileLocation = "native";
923 fileName = this.getScriptNameOrSourceURL();
924 if (!fileName && this.isEval()) {
925 fileLocation = this.getEvalOrigin();
926 fileLocation += ", "; // Expecting source position to follow.
930 fileLocation += fileName;
932 // Source code does not originate from a file and is not native, but we
933 // can still get the source position inside the source string, e.g. in
935 fileLocation += "<anonymous>";
937 var lineNumber = this.getLineNumber();
938 if (lineNumber != null) {
939 fileLocation += ":" + lineNumber;
940 var columnNumber = this.getColumnNumber();
942 fileLocation += ":" + columnNumber;
948 var functionName = this.getFunctionName();
949 var addSuffix = true;
950 var isConstructor = this.isConstructor();
951 var isMethodCall = !(this.isToplevel() || isConstructor);
953 var typeName = GetTypeName(GET_PRIVATE(this, CallSiteReceiverKey), true);
954 var methodName = this.getMethodName();
957 %_CallFunction(functionName, typeName, StringIndexOf) != 0) {
958 line += typeName + ".";
960 line += functionName;
962 (%_CallFunction(functionName, "." + methodName, StringIndexOf) !=
963 functionName.length - methodName.length - 1)) {
964 line += " [as " + methodName + "]";
967 line += typeName + "." + (methodName || "<anonymous>");
969 } else if (isConstructor) {
970 line += "new " + (functionName || "<anonymous>");
971 } else if (functionName) {
972 line += functionName;
974 line += fileLocation;
978 line += " (" + fileLocation + ")";
983 SetUpLockedPrototype(CallSite, $Array("receiver", "fun", "pos"), $Array(
984 "getThis", CallSiteGetThis,
985 "getTypeName", CallSiteGetTypeName,
986 "isToplevel", CallSiteIsToplevel,
987 "isEval", CallSiteIsEval,
988 "getEvalOrigin", CallSiteGetEvalOrigin,
989 "getScriptNameOrSourceURL", CallSiteGetScriptNameOrSourceURL,
990 "getFunction", CallSiteGetFunction,
991 "getFunctionName", CallSiteGetFunctionName,
992 "getMethodName", CallSiteGetMethodName,
993 "getFileName", CallSiteGetFileName,
994 "getLineNumber", CallSiteGetLineNumber,
995 "getColumnNumber", CallSiteGetColumnNumber,
996 "isNative", CallSiteIsNative,
997 "getPosition", CallSiteGetPosition,
998 "isConstructor", CallSiteIsConstructor,
999 "toString", CallSiteToString
1003 function FormatEvalOrigin(script) {
1004 var sourceURL = script.nameOrSourceURL();
1009 var eval_origin = "eval at ";
1010 if (script.eval_from_function_name) {
1011 eval_origin += script.eval_from_function_name;
1013 eval_origin += "<anonymous>";
1016 var eval_from_script = script.eval_from_script;
1017 if (eval_from_script) {
1018 if (eval_from_script.compilation_type == COMPILATION_TYPE_EVAL) {
1019 // eval script originated from another eval.
1020 eval_origin += " (" + FormatEvalOrigin(eval_from_script) + ")";
1022 // eval script originated from "real" source.
1023 if (eval_from_script.name) {
1024 eval_origin += " (" + eval_from_script.name;
1025 var location = eval_from_script.locationFromPosition(
1026 script.eval_from_script_position, true);
1028 eval_origin += ":" + (location.line + 1);
1029 eval_origin += ":" + (location.column + 1);
1033 eval_origin += " (unknown source)";
1042 function FormatErrorString(error) {
1044 return %_CallFunction(error, ErrorToString);
1047 return "<error: " + e + ">";
1055 function GetStackFrames(raw_stack) {
1056 var frames = new InternalArray();
1057 var sloppy_frames = raw_stack[0];
1058 for (var i = 1; i < raw_stack.length; i += 4) {
1059 var recv = raw_stack[i];
1060 var fun = raw_stack[i + 1];
1061 var code = raw_stack[i + 2];
1062 var pc = raw_stack[i + 3];
1063 var pos = %FunctionGetPositionForOffset(code, pc);
1065 frames.push(new CallSite(recv, fun, pos, (sloppy_frames < 0)));
1071 // Flag to prevent recursive call of Error.prepareStackTrace.
1072 var formatting_custom_stack_trace = false;
1075 function FormatStackTrace(obj, error_string, frames) {
1076 if (IS_FUNCTION($Error.prepareStackTrace) && !formatting_custom_stack_trace) {
1078 %MoveArrayContents(frames, array);
1079 formatting_custom_stack_trace = true;
1080 var stack_trace = UNDEFINED;
1082 stack_trace = $Error.prepareStackTrace(obj, array);
1084 throw e; // The custom formatting function threw. Rethrow.
1086 formatting_custom_stack_trace = false;
1091 var lines = new InternalArray();
1092 lines.push(error_string);
1093 for (var i = 0; i < frames.length; i++) {
1094 var frame = frames[i];
1097 line = frame.toString();
1100 line = "<error: " + e + ">";
1102 // Any code that reaches this point is seriously nasty!
1106 lines.push(" at " + line);
1108 return %_CallFunction(lines, "\n", ArrayJoin);
1112 function GetTypeName(receiver, requireConstructor) {
1113 var constructor = receiver.constructor;
1115 return requireConstructor ? null :
1116 %_CallFunction(receiver, ObjectToString);
1118 var constructorName = constructor.name;
1119 if (!constructorName) {
1120 return requireConstructor ? null :
1121 %_CallFunction(receiver, ObjectToString);
1123 return constructorName;
1127 function captureStackTrace(obj, cons_opt) {
1128 var stackTraceLimit = $Error.stackTraceLimit;
1129 if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return;
1130 if (stackTraceLimit < 0 || stackTraceLimit > 10000) {
1131 stackTraceLimit = 10000;
1133 var stack = %CollectStackTrace(obj,
1134 cons_opt ? cons_opt : captureStackTrace,
1137 var error_string = FormatErrorString(obj);
1139 // Set the 'stack' property on the receiver. If the receiver is the same as
1140 // holder of this setter, the accessor pair is turned into a data property.
1141 var setter = function(v) {
1142 // Set data property on the receiver (not necessarily holder).
1143 %DefineOrRedefineDataProperty(this, 'stack', v, NONE);
1145 // Release context values if holder is the same as the receiver.
1146 stack = error_string = UNDEFINED;
1150 // The holder of this getter ('obj') may not be the receiver ('this').
1151 // When this getter is called the first time, we use the context values to
1152 // format a stack trace string and turn this accessor pair into a data
1153 // property (on the holder).
1154 var getter = function() {
1155 // Stack is still a raw array awaiting to be formatted.
1156 var result = FormatStackTrace(obj, error_string, GetStackFrames(stack));
1157 // Replace this accessor to return result directly.
1158 %DefineOrRedefineAccessorProperty(
1159 obj, 'stack', function() { return result }, setter, DONT_ENUM);
1160 // Release context values.
1161 stack = error_string = UNDEFINED;
1165 %DefineOrRedefineAccessorProperty(obj, 'stack', getter, setter, DONT_ENUM);
1169 function SetUpError() {
1170 // Define special error type constructors.
1172 var DefineError = function(f) {
1173 // Store the error function in both the global object
1174 // and the runtime object. The function is fetched
1175 // from the runtime object when throwing errors from
1176 // within the runtime system to avoid strange side
1177 // effects when overwriting the error functions from
1180 %SetProperty(global, name, f, DONT_ENUM);
1181 %SetProperty(builtins, '$' + name, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
1182 // Configure the error function.
1183 if (name == 'Error') {
1184 // The prototype of the Error object must itself be an error.
1185 // However, it can't be an instance of the Error object because
1186 // it hasn't been properly configured yet. Instead we create a
1187 // special not-a-true-error-but-close-enough object.
1188 var ErrorPrototype = function() {};
1189 %FunctionSetPrototype(ErrorPrototype, $Object.prototype);
1190 %FunctionSetInstanceClassName(ErrorPrototype, 'Error');
1191 %FunctionSetPrototype(f, new ErrorPrototype());
1193 %FunctionSetPrototype(f, new $Error());
1195 %FunctionSetInstanceClassName(f, 'Error');
1196 %SetProperty(f.prototype, 'constructor', f, DONT_ENUM);
1197 %SetProperty(f.prototype, "name", name, DONT_ENUM);
1198 %SetCode(f, function(m) {
1199 if (%_IsConstructCall()) {
1200 // Define all the expected properties directly on the error
1201 // object. This avoids going through getters and setters defined
1202 // on prototype objects.
1203 %IgnoreAttributesAndSetProperty(this, 'stack', UNDEFINED, DONT_ENUM);
1204 if (!IS_UNDEFINED(m)) {
1205 %IgnoreAttributesAndSetProperty(
1206 this, 'message', ToString(m), DONT_ENUM);
1208 captureStackTrace(this, f);
1216 DefineError(function Error() { });
1217 DefineError(function TypeError() { });
1218 DefineError(function RangeError() { });
1219 DefineError(function SyntaxError() { });
1220 DefineError(function ReferenceError() { });
1221 DefineError(function EvalError() { });
1222 DefineError(function URIError() { });
1227 $Error.captureStackTrace = captureStackTrace;
1229 %SetProperty($Error.prototype, 'message', '', DONT_ENUM);
1231 // Global list of error objects visited during ErrorToString. This is
1232 // used to detect cycles in error toString formatting.
1233 var visited_errors = new InternalArray();
1234 var cyclic_error_marker = new $Object();
1236 function GetPropertyWithoutInvokingMonkeyGetters(error, name) {
1237 var current = error;
1238 // Climb the prototype chain until we find the holder.
1239 while (current && !%HasLocalProperty(current, name)) {
1240 current = %GetPrototype(current);
1242 if (IS_NULL(current)) return UNDEFINED;
1243 if (!IS_OBJECT(current)) return error[name];
1244 // If the property is an accessor on one of the predefined errors that can be
1245 // generated statically by the compiler, don't touch it. This is to address
1246 // http://code.google.com/p/chromium/issues/detail?id=69187
1247 var desc = %GetOwnProperty(current, name);
1248 if (desc && desc[IS_ACCESSOR_INDEX]) {
1249 var isName = name === "name";
1250 if (current === $ReferenceError.prototype)
1251 return isName ? "ReferenceError" : UNDEFINED;
1252 if (current === $SyntaxError.prototype)
1253 return isName ? "SyntaxError" : UNDEFINED;
1254 if (current === $TypeError.prototype)
1255 return isName ? "TypeError" : UNDEFINED;
1257 // Otherwise, read normally.
1261 function ErrorToStringDetectCycle(error) {
1262 if (!%PushIfAbsent(visited_errors, error)) throw cyclic_error_marker;
1264 var name = GetPropertyWithoutInvokingMonkeyGetters(error, "name");
1265 name = IS_UNDEFINED(name) ? "Error" : TO_STRING_INLINE(name);
1266 var message = GetPropertyWithoutInvokingMonkeyGetters(error, "message");
1267 message = IS_UNDEFINED(message) ? "" : TO_STRING_INLINE(message);
1268 if (name === "") return message;
1269 if (message === "") return name;
1270 return name + ": " + message;
1272 visited_errors.length = visited_errors.length - 1;
1276 function ErrorToString() {
1277 if (!IS_SPEC_OBJECT(this)) {
1278 throw MakeTypeError("called_on_non_object", ["Error.prototype.toString"]);
1282 return ErrorToStringDetectCycle(this);
1284 // If this error message was encountered already return the empty
1285 // string for it instead of recursively formatting it.
1286 if (e === cyclic_error_marker) {
1294 InstallFunctions($Error.prototype, DONT_ENUM, ['toString', ErrorToString]);
1296 // Boilerplate for exceptions for stack overflows. Used from
1297 // Isolate::StackOverflow().
1298 function SetUpStackOverflowBoilerplate() {
1299 var boilerplate = MakeRangeError('stack_overflow', []);
1301 var error_string = boilerplate.name + ": " + boilerplate.message;
1303 // Set the 'stack' property on the receiver. If the receiver is the same as
1304 // holder of this setter, the accessor pair is turned into a data property.
1305 var setter = function(v) {
1306 %DefineOrRedefineDataProperty(this, 'stack', v, NONE);
1307 // Tentatively clear the hidden property. If the receiver is the same as
1308 // holder, we release the raw stack trace this way.
1309 %GetAndClearOverflowedStackTrace(this);
1312 // The raw stack trace is stored as a hidden property on the holder of this
1313 // getter, which may not be the same as the receiver. Find the holder to
1314 // retrieve the raw stack trace and then turn this accessor pair into a
1316 var getter = function() {
1318 while (!IS_ERROR(holder)) {
1319 holder = %GetPrototype(holder);
1320 if (IS_NULL(holder)) return MakeSyntaxError('illegal_access', []);
1322 var stack = %GetAndClearOverflowedStackTrace(holder);
1323 // We may not have captured any stack trace.
1324 if (IS_UNDEFINED(stack)) return stack;
1326 var result = FormatStackTrace(holder, error_string, GetStackFrames(stack));
1327 // Replace this accessor to return result directly.
1328 %DefineOrRedefineAccessorProperty(
1329 holder, 'stack', function() { return result }, setter, DONT_ENUM);
1333 %DefineOrRedefineAccessorProperty(
1334 boilerplate, 'stack', getter, setter, DONT_ENUM);
1339 var kStackOverflowBoilerplate = SetUpStackOverflowBoilerplate();