Home | History | Annotate | Download | only in src
      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
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 // -------------------------------------------------------------------
     29 //
     30 // If this object gets passed to an error constructor the error will
     31 // get an accessor for .message that constructs a descriptive error
     32 // message on access.
     33 var kAddMessageAccessorsMarker = { };
     34 
     35 // This will be lazily initialized when first needed (and forcibly
     36 // overwritten even though it's const).
     37 var kMessages = 0;
     38 
     39 function FormatString(format, message) {
     40   var args = %MessageGetArguments(message);
     41   var result = "";
     42   var arg_num = 0;
     43   for (var i = 0; i < format.length; i++) {
     44     var str = format[i];
     45     if (str.length == 2 && %_StringCharCodeAt(str, 0) == 0x25) {
     46       // Two-char string starts with "%".
     47       var arg_num = (%_StringCharCodeAt(str, 1) - 0x30) >>> 0;
     48       if (arg_num < 4) {
     49         // str is one of %0, %1, %2 or %3.
     50         try {
     51           str = ToDetailString(args[arg_num]);
     52         } catch (e) {
     53           str = "#<error>";
     54         }
     55       }
     56     }
     57     result += str;
     58   }
     59   return result;
     60 }
     61 
     62 
     63 // To check if something is a native error we need to check the
     64 // concrete native error types. It is not enough to check "obj
     65 // instanceof $Error" because user code can replace
     66 // NativeError.prototype.__proto__. User code cannot replace
     67 // NativeError.prototype though and therefore this is a safe test.
     68 function IsNativeErrorObject(obj) {
     69   return (obj instanceof $Error) ||
     70       (obj instanceof $EvalError) ||
     71       (obj instanceof $RangeError) ||
     72       (obj instanceof $ReferenceError) ||
     73       (obj instanceof $SyntaxError) ||
     74       (obj instanceof $TypeError) ||
     75       (obj instanceof $URIError);
     76 }
     77 
     78 
     79 // When formatting internally created error messages, do not
     80 // invoke overwritten error toString methods but explicitly use
     81 // the error to string method. This is to avoid leaking error
     82 // objects between script tags in a browser setting.
     83 function ToStringCheckErrorObject(obj) {
     84   if (IsNativeErrorObject(obj)) {
     85     return %_CallFunction(obj, ErrorToString);
     86   } else {
     87     return ToString(obj);
     88   }
     89 }
     90 
     91 
     92 function ToDetailString(obj) {
     93   if (obj != null && IS_OBJECT(obj) && obj.toString === ObjectToString) {
     94     var constructor = obj.constructor;
     95     if (typeof constructor == "function") {
     96       var constructorName = constructor.name;
     97       if (IS_STRING(constructorName) && constructorName !== "") {
     98         return "#<" + constructorName + ">";
     99       }
    100     }
    101   }
    102   return ToStringCheckErrorObject(obj);
    103 }
    104 
    105 
    106 function MakeGenericError(constructor, type, args) {
    107   if (IS_UNDEFINED(args)) {
    108     args = [];
    109   }
    110   var e = new constructor(kAddMessageAccessorsMarker);
    111   e.type = type;
    112   e.arguments = args;
    113   return e;
    114 }
    115 
    116 
    117 /**
    118  * Set up the Script function and constructor.
    119  */
    120 %FunctionSetInstanceClassName(Script, 'Script');
    121 %SetProperty(Script.prototype, 'constructor', Script,
    122              DONT_ENUM | DONT_DELETE | READ_ONLY);
    123 %SetCode(Script, function(x) {
    124   // Script objects can only be created by the VM.
    125   throw new $Error("Not supported");
    126 });
    127 
    128 
    129 // Helper functions; called from the runtime system.
    130 function FormatMessage(message) {
    131   if (kMessages === 0) {
    132     var messagesDictionary = [
    133       // Error
    134       "cyclic_proto",                 ["Cyclic __proto__ value"],
    135       "code_gen_from_strings",        ["Code generation from strings disallowed for this context"],
    136       // TypeError
    137       "unexpected_token",             ["Unexpected token ", "%0"],
    138       "unexpected_token_number",      ["Unexpected number"],
    139       "unexpected_token_string",      ["Unexpected string"],
    140       "unexpected_token_identifier",  ["Unexpected identifier"],
    141       "unexpected_reserved",          ["Unexpected reserved word"],
    142       "unexpected_strict_reserved",   ["Unexpected strict mode reserved word"],
    143       "unexpected_eos",               ["Unexpected end of input"],
    144       "malformed_regexp",             ["Invalid regular expression: /", "%0", "/: ", "%1"],
    145       "unterminated_regexp",          ["Invalid regular expression: missing /"],
    146       "regexp_flags",                 ["Cannot supply flags when constructing one RegExp from another"],
    147       "incompatible_method_receiver", ["Method ", "%0", " called on incompatible receiver ", "%1"],
    148       "invalid_lhs_in_assignment",    ["Invalid left-hand side in assignment"],
    149       "invalid_lhs_in_for_in",        ["Invalid left-hand side in for-in"],
    150       "invalid_lhs_in_postfix_op",    ["Invalid left-hand side expression in postfix operation"],
    151       "invalid_lhs_in_prefix_op",     ["Invalid left-hand side expression in prefix operation"],
    152       "multiple_defaults_in_switch",  ["More than one default clause in switch statement"],
    153       "newline_after_throw",          ["Illegal newline after throw"],
    154       "redeclaration",                ["%0", " '", "%1", "' has already been declared"],
    155       "no_catch_or_finally",          ["Missing catch or finally after try"],
    156       "unknown_label",                ["Undefined label '", "%0", "'"],
    157       "uncaught_exception",           ["Uncaught ", "%0"],
    158       "stack_trace",                  ["Stack Trace:\n", "%0"],
    159       "called_non_callable",          ["%0", " is not a function"],
    160       "undefined_method",             ["Object ", "%1", " has no method '", "%0", "'"],
    161       "property_not_function",        ["Property '", "%0", "' of object ", "%1", " is not a function"],
    162       "cannot_convert_to_primitive",  ["Cannot convert object to primitive value"],
    163       "not_constructor",              ["%0", " is not a constructor"],
    164       "not_defined",                  ["%0", " is not defined"],
    165       "non_object_property_load",     ["Cannot read property '", "%0", "' of ", "%1"],
    166       "non_object_property_store",    ["Cannot set property '", "%0", "' of ", "%1"],
    167       "non_object_property_call",     ["Cannot call method '", "%0", "' of ", "%1"],
    168       "with_expression",              ["%0", " has no properties"],
    169       "illegal_invocation",           ["Illegal invocation"],
    170       "no_setter_in_callback",        ["Cannot set property ", "%0", " of ", "%1", " which has only a getter"],
    171       "apply_non_function",           ["Function.prototype.apply was called on ", "%0", ", which is a ", "%1", " and not a function"],
    172       "apply_wrong_args",             ["Function.prototype.apply: Arguments list has wrong type"],
    173       "invalid_in_operator_use",      ["Cannot use 'in' operator to search for '", "%0", "' in ", "%1"],
    174       "instanceof_function_expected", ["Expecting a function in instanceof check, but got ", "%0"],
    175       "instanceof_nonobject_proto",   ["Function has non-object prototype '", "%0", "' in instanceof check"],
    176       "null_to_object",               ["Cannot convert null to object"],
    177       "reduce_no_initial",            ["Reduce of empty array with no initial value"],
    178       "getter_must_be_callable",      ["Getter must be a function: ", "%0"],
    179       "setter_must_be_callable",      ["Setter must be a function: ", "%0"],
    180       "value_and_accessor",           ["Invalid property.  A property cannot both have accessors and be writable or have a value, ", "%0"],
    181       "proto_object_or_null",         ["Object prototype may only be an Object or null"],
    182       "property_desc_object",         ["Property description must be an object: ", "%0"],
    183       "redefine_disallowed",          ["Cannot redefine property: ", "%0"],
    184       "define_disallowed",            ["Cannot define property:", "%0", ", object is not extensible."],
    185       "non_extensible_proto",         ["%0", " is not extensible"],
    186       "handler_non_object",           ["Proxy.", "%0", " called with non-object as handler"],
    187       "proto_non_object",             ["Proxy.", "%0", " called with non-object as prototype"],
    188       "trap_function_expected",       ["Proxy.", "%0", " called with non-function for '", "%1", "' trap"],
    189       "handler_trap_missing",         ["Proxy handler ", "%0", " has no '", "%1", "' trap"],
    190       "handler_trap_must_be_callable", ["Proxy handler ", "%0", " has non-callable '", "%1", "' trap"],
    191       "handler_returned_false",       ["Proxy handler ", "%0", " returned false from '", "%1", "' trap"],
    192       "handler_returned_undefined",   ["Proxy handler ", "%0", " returned undefined from '", "%1", "' trap"],
    193       "proxy_prop_not_configurable",  ["Proxy handler ", "%0", " returned non-configurable descriptor for property '", "%2", "' from '", "%1", "' trap"],
    194       "proxy_non_object_prop_names",  ["Trap '", "%1", "' returned non-object ", "%0"],
    195       "proxy_repeated_prop_name",     ["Trap '", "%1", "' returned repeated property name '", "%2", "'"],
    196       "invalid_weakmap_key",          ["Invalid value used as weak map key"],
    197       // RangeError
    198       "invalid_array_length",         ["Invalid array length"],
    199       "stack_overflow",               ["Maximum call stack size exceeded"],
    200       "invalid_time_value",           ["Invalid time value"],
    201       // SyntaxError
    202       "unable_to_parse",              ["Parse error"],
    203       "invalid_regexp_flags",         ["Invalid flags supplied to RegExp constructor '", "%0", "'"],
    204       "invalid_regexp",               ["Invalid RegExp pattern /", "%0", "/"],
    205       "illegal_break",                ["Illegal break statement"],
    206       "illegal_continue",             ["Illegal continue statement"],
    207       "illegal_return",               ["Illegal return statement"],
    208       "illegal_let",                  ["Illegal let declaration outside extended mode"],
    209       "error_loading_debugger",       ["Error loading debugger"],
    210       "no_input_to_regexp",           ["No input to ", "%0"],
    211       "invalid_json",                 ["String '", "%0", "' is not valid JSON"],
    212       "circular_structure",           ["Converting circular structure to JSON"],
    213       "called_on_non_object",         ["%0", " called on non-object"],
    214       "called_on_null_or_undefined",  ["%0", " called on null or undefined"],
    215       "array_indexof_not_defined",    ["Array.getIndexOf: Argument undefined"],
    216       "object_not_extensible",        ["Can't add property ", "%0", ", object is not extensible"],
    217       "illegal_access",               ["Illegal access"],
    218       "invalid_preparser_data",       ["Invalid preparser data for function ", "%0"],
    219       "strict_mode_with",             ["Strict mode code may not include a with statement"],
    220       "strict_catch_variable",        ["Catch variable may not be eval or arguments in strict mode"],
    221       "too_many_arguments",           ["Too many arguments in function call (only 32766 allowed)"],
    222       "too_many_parameters",          ["Too many parameters in function definition (only 32766 allowed)"],
    223       "too_many_variables",           ["Too many variables declared (only 32767 allowed)"],
    224       "strict_param_name",            ["Parameter name eval or arguments is not allowed in strict mode"],
    225       "strict_param_dupe",            ["Strict mode function may not have duplicate parameter names"],
    226       "strict_var_name",              ["Variable name may not be eval or arguments in strict mode"],
    227       "strict_function_name",         ["Function name may not be eval or arguments in strict mode"],
    228       "strict_octal_literal",         ["Octal literals are not allowed in strict mode."],
    229       "strict_duplicate_property",    ["Duplicate data property in object literal not allowed in strict mode"],
    230       "accessor_data_property",       ["Object literal may not have data and accessor property with the same name"],
    231       "accessor_get_set",             ["Object literal may not have multiple get/set accessors with the same name"],
    232       "strict_lhs_assignment",        ["Assignment to eval or arguments is not allowed in strict mode"],
    233       "strict_lhs_postfix",           ["Postfix increment/decrement may not have eval or arguments operand in strict mode"],
    234       "strict_lhs_prefix",            ["Prefix increment/decrement may not have eval or arguments operand in strict mode"],
    235       "strict_reserved_word",         ["Use of future reserved word in strict mode"],
    236       "strict_delete",                ["Delete of an unqualified identifier in strict mode."],
    237       "strict_delete_property",       ["Cannot delete property '", "%0", "' of ", "%1"],
    238       "strict_const",                 ["Use of const in strict mode."],
    239       "strict_function",              ["In strict mode code, functions can only be declared at top level or immediately within another function." ],
    240       "strict_read_only_property",    ["Cannot assign to read only property '", "%0", "' of ", "%1"],
    241       "strict_cannot_assign",         ["Cannot assign to read only '", "%0", "' in strict mode"],
    242       "strict_poison_pill",           ["'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them"],
    243       "strict_caller",                ["Illegal access to a strict mode caller function."],
    244       "unprotected_let",              ["Illegal let declaration in unprotected statement context."],
    245       "unprotected_const",            ["Illegal const declaration in unprotected statement context."],
    246       "cant_prevent_ext_external_array_elements", ["Cannot prevent extension of an object with external array elements"],
    247       "redef_external_array_element", ["Cannot redefine a property of an object with external array elements"],
    248       "harmony_const_assign",         ["Assignment to constant variable."],
    249       "invalid_module_path",          ["Module does not export '", "%0", "', or export is not itself a module"],
    250       "module_type_error",            ["Module '", "%0", "' used improperly"],
    251     ];
    252     var messages = { __proto__ : null };
    253     for (var i = 0; i < messagesDictionary.length; i += 2) {
    254       var key = messagesDictionary[i];
    255       var format = messagesDictionary[i + 1];
    256 
    257       for (var j = 0; j < format.length; j++) {
    258         %IgnoreAttributesAndSetProperty(format, %_NumberToString(j), format[j],
    259                                         DONT_DELETE | READ_ONLY | DONT_ENUM);
    260       }
    261       %IgnoreAttributesAndSetProperty(format, 'length', format.length,
    262                                       DONT_DELETE | READ_ONLY | DONT_ENUM);
    263       %PreventExtensions(format);
    264       %IgnoreAttributesAndSetProperty(messages,
    265                                       key,
    266                                       format,
    267                                       DONT_DELETE | DONT_ENUM | READ_ONLY);
    268     }
    269     %PreventExtensions(messages);
    270     %IgnoreAttributesAndSetProperty(builtins, "kMessages",
    271                                     messages,
    272                                     DONT_DELETE | DONT_ENUM | READ_ONLY);
    273   }
    274   var message_type = %MessageGetType(message);
    275   var format = kMessages[message_type];
    276   if (!format) return "<unknown message " + message_type + ">";
    277   return FormatString(format, message);
    278 }
    279 
    280 
    281 function GetLineNumber(message) {
    282   var start_position = %MessageGetStartPosition(message);
    283   if (start_position == -1) return kNoLineNumberInfo;
    284   var script = %MessageGetScript(message);
    285   var location = script.locationFromPosition(start_position, true);
    286   if (location == null) return kNoLineNumberInfo;
    287   return location.line + 1;
    288 }
    289 
    290 
    291 // Returns the source code line containing the given source
    292 // position, or the empty string if the position is invalid.
    293 function GetSourceLine(message) {
    294   var script = %MessageGetScript(message);
    295   var start_position = %MessageGetStartPosition(message);
    296   var location = script.locationFromPosition(start_position, true);
    297   if (location == null) return "";
    298   location.restrict();
    299   return location.sourceText();
    300 }
    301 
    302 
    303 function MakeTypeError(type, args) {
    304   return MakeGenericError($TypeError, type, args);
    305 }
    306 
    307 
    308 function MakeRangeError(type, args) {
    309   return MakeGenericError($RangeError, type, args);
    310 }
    311 
    312 
    313 function MakeSyntaxError(type, args) {
    314   return MakeGenericError($SyntaxError, type, args);
    315 }
    316 
    317 
    318 function MakeReferenceError(type, args) {
    319   return MakeGenericError($ReferenceError, type, args);
    320 }
    321 
    322 
    323 function MakeEvalError(type, args) {
    324   return MakeGenericError($EvalError, type, args);
    325 }
    326 
    327 
    328 function MakeError(type, args) {
    329   return MakeGenericError($Error, type, args);
    330 }
    331 
    332 /**
    333  * Find a line number given a specific source position.
    334  * @param {number} position The source position.
    335  * @return {number} 0 if input too small, -1 if input too large,
    336        else the line number.
    337  */
    338 function ScriptLineFromPosition(position) {
    339   var lower = 0;
    340   var upper = this.lineCount() - 1;
    341   var line_ends = this.line_ends;
    342 
    343   // We'll never find invalid positions so bail right away.
    344   if (position > line_ends[upper]) {
    345     return -1;
    346   }
    347 
    348   // This means we don't have to safe-guard indexing line_ends[i - 1].
    349   if (position <= line_ends[0]) {
    350     return 0;
    351   }
    352 
    353   // Binary search to find line # from position range.
    354   while (upper >= 1) {
    355     var i = (lower + upper) >> 1;
    356 
    357     if (position > line_ends[i]) {
    358       lower = i + 1;
    359     } else if (position <= line_ends[i - 1]) {
    360       upper = i - 1;
    361     } else {
    362       return i;
    363     }
    364   }
    365 
    366   return -1;
    367 }
    368 
    369 /**
    370  * Get information on a specific source position.
    371  * @param {number} position The source position
    372  * @param {boolean} include_resource_offset Set to true to have the resource
    373  *     offset added to the location
    374  * @return {SourceLocation}
    375  *     If line is negative or not in the source null is returned.
    376  */
    377 function ScriptLocationFromPosition(position,
    378                                     include_resource_offset) {
    379   var line = this.lineFromPosition(position);
    380   if (line == -1) return null;
    381 
    382   // Determine start, end and column.
    383   var line_ends = this.line_ends;
    384   var start = line == 0 ? 0 : line_ends[line - 1] + 1;
    385   var end = line_ends[line];
    386   if (end > 0 && %_CallFunction(this.source, end - 1, StringCharAt) == '\r') {
    387     end--;
    388   }
    389   var column = position - start;
    390 
    391   // Adjust according to the offset within the resource.
    392   if (include_resource_offset) {
    393     line += this.line_offset;
    394     if (line == this.line_offset) {
    395       column += this.column_offset;
    396     }
    397   }
    398 
    399   return new SourceLocation(this, position, line, column, start, end);
    400 }
    401 
    402 
    403 /**
    404  * Get information on a specific source line and column possibly offset by a
    405  * fixed source position. This function is used to find a source position from
    406  * a line and column position. The fixed source position offset is typically
    407  * used to find a source position in a function based on a line and column in
    408  * the source for the function alone. The offset passed will then be the
    409  * start position of the source for the function within the full script source.
    410  * @param {number} opt_line The line within the source. Default value is 0
    411  * @param {number} opt_column The column in within the line. Default value is 0
    412  * @param {number} opt_offset_position The offset from the begining of the
    413  *     source from where the line and column calculation starts.
    414  *     Default value is 0
    415  * @return {SourceLocation}
    416  *     If line is negative or not in the source null is returned.
    417  */
    418 function ScriptLocationFromLine(opt_line, opt_column, opt_offset_position) {
    419   // Default is the first line in the script. Lines in the script is relative
    420   // to the offset within the resource.
    421   var line = 0;
    422   if (!IS_UNDEFINED(opt_line)) {
    423     line = opt_line - this.line_offset;
    424   }
    425 
    426   // Default is first column. If on the first line add the offset within the
    427   // resource.
    428   var column = opt_column || 0;
    429   if (line == 0) {
    430     column -= this.column_offset;
    431   }
    432 
    433   var offset_position = opt_offset_position || 0;
    434   if (line < 0 || column < 0 || offset_position < 0) return null;
    435   if (line == 0) {
    436     return this.locationFromPosition(offset_position + column, false);
    437   } else {
    438     // Find the line where the offset position is located.
    439     var offset_line = this.lineFromPosition(offset_position);
    440 
    441     if (offset_line == -1 || offset_line + line >= this.lineCount()) {
    442       return null;
    443     }
    444 
    445     return this.locationFromPosition(
    446         this.line_ends[offset_line + line - 1] + 1 + column);  // line > 0 here.
    447   }
    448 }
    449 
    450 
    451 /**
    452  * Get a slice of source code from the script. The boundaries for the slice is
    453  * specified in lines.
    454  * @param {number} opt_from_line The first line (zero bound) in the slice.
    455  *     Default is 0
    456  * @param {number} opt_to_column The last line (zero bound) in the slice (non
    457  *     inclusive). Default is the number of lines in the script
    458  * @return {SourceSlice} The source slice or null of the parameters where
    459  *     invalid
    460  */
    461 function ScriptSourceSlice(opt_from_line, opt_to_line) {
    462   var from_line = IS_UNDEFINED(opt_from_line) ? this.line_offset
    463                                               : opt_from_line;
    464   var to_line = IS_UNDEFINED(opt_to_line) ? this.line_offset + this.lineCount()
    465                                           : opt_to_line;
    466 
    467   // Adjust according to the offset within the resource.
    468   from_line -= this.line_offset;
    469   to_line -= this.line_offset;
    470   if (from_line < 0) from_line = 0;
    471   if (to_line > this.lineCount()) to_line = this.lineCount();
    472 
    473   // Check parameters.
    474   if (from_line >= this.lineCount() ||
    475       to_line < 0 ||
    476       from_line > to_line) {
    477     return null;
    478   }
    479 
    480   var line_ends = this.line_ends;
    481   var from_position = from_line == 0 ? 0 : line_ends[from_line - 1] + 1;
    482   var to_position = to_line == 0 ? 0 : line_ends[to_line - 1] + 1;
    483 
    484   // Return a source slice with line numbers re-adjusted to the resource.
    485   return new SourceSlice(this,
    486                          from_line + this.line_offset,
    487                          to_line + this.line_offset,
    488                           from_position, to_position);
    489 }
    490 
    491 
    492 function ScriptSourceLine(opt_line) {
    493   // Default is the first line in the script. Lines in the script are relative
    494   // to the offset within the resource.
    495   var line = 0;
    496   if (!IS_UNDEFINED(opt_line)) {
    497     line = opt_line - this.line_offset;
    498   }
    499 
    500   // Check parameter.
    501   if (line < 0 || this.lineCount() <= line) {
    502     return null;
    503   }
    504 
    505   // Return the source line.
    506   var line_ends = this.line_ends;
    507   var start = line == 0 ? 0 : line_ends[line - 1] + 1;
    508   var end = line_ends[line];
    509   return %_CallFunction(this.source, start, end, StringSubstring);
    510 }
    511 
    512 
    513 /**
    514  * Returns the number of source lines.
    515  * @return {number}
    516  *     Number of source lines.
    517  */
    518 function ScriptLineCount() {
    519   // Return number of source lines.
    520   return this.line_ends.length;
    521 }
    522 
    523 
    524 /**
    525  * Returns the name of script if available, contents of sourceURL comment
    526  * otherwise. See
    527  * http://fbug.googlecode.com/svn/branches/firebug1.1/docs/ReleaseNotes_1.1.txt
    528  * for details on using //@ sourceURL comment to identify scritps that don't
    529  * have name.
    530  *
    531  * @return {?string} script name if present, value for //@ sourceURL comment
    532  * otherwise.
    533  */
    534 function ScriptNameOrSourceURL() {
    535   if (this.name) {
    536     return this.name;
    537   }
    538 
    539   // The result is cached as on long scripts it takes noticable time to search
    540   // for the sourceURL.
    541   if (this.hasCachedNameOrSourceURL)
    542       return this.cachedNameOrSourceURL;
    543   this.hasCachedNameOrSourceURL = true;
    544 
    545   // TODO(608): the spaces in a regexp below had to be escaped as \040
    546   // because this file is being processed by js2c whose handling of spaces
    547   // in regexps is broken. Also, ['"] are excluded from allowed URLs to
    548   // avoid matches against sources that invoke evals with sourceURL.
    549   // A better solution would be to detect these special comments in
    550   // the scanner/parser.
    551   var source = ToString(this.source);
    552   var sourceUrlPos = %StringIndexOf(source, "sourceURL=", 0);
    553   this.cachedNameOrSourceURL = this.name;
    554   if (sourceUrlPos > 4) {
    555     var sourceUrlPattern =
    556         /\/\/@[\040\t]sourceURL=[\040\t]*([^\s\'\"]*)[\040\t]*$/gm;
    557     // Don't reuse lastMatchInfo here, so we create a new array with room
    558     // for four captures (array with length one longer than the index
    559     // of the fourth capture, where the numbering is zero-based).
    560     var matchInfo = new InternalArray(CAPTURE(3) + 1);
    561     var match =
    562         %_RegExpExec(sourceUrlPattern, source, sourceUrlPos - 4, matchInfo);
    563     if (match) {
    564       this.cachedNameOrSourceURL =
    565           SubString(source, matchInfo[CAPTURE(2)], matchInfo[CAPTURE(3)]);
    566     }
    567   }
    568   return this.cachedNameOrSourceURL;
    569 }
    570 
    571 
    572 SetUpLockedPrototype(Script,
    573   $Array("source", "name", "line_ends", "line_offset", "column_offset",
    574          "cachedNameOrSourceURL", "hasCachedNameOrSourceURL" ),
    575   $Array(
    576     "lineFromPosition", ScriptLineFromPosition,
    577     "locationFromPosition", ScriptLocationFromPosition,
    578     "locationFromLine", ScriptLocationFromLine,
    579     "sourceSlice", ScriptSourceSlice,
    580     "sourceLine", ScriptSourceLine,
    581     "lineCount", ScriptLineCount,
    582     "nameOrSourceURL", ScriptNameOrSourceURL
    583   )
    584 );
    585 
    586 
    587 /**
    588  * Class for source location. A source location is a position within some
    589  * source with the following properties:
    590  *   script   : script object for the source
    591  *   line     : source line number
    592  *   column   : source column within the line
    593  *   position : position within the source
    594  *   start    : position of start of source context (inclusive)
    595  *   end      : position of end of source context (not inclusive)
    596  * Source text for the source context is the character interval
    597  * [start, end[. In most cases end will point to a newline character.
    598  * It might point just past the final position of the source if the last
    599  * source line does not end with a newline character.
    600  * @param {Script} script The Script object for which this is a location
    601  * @param {number} position Source position for the location
    602  * @param {number} line The line number for the location
    603  * @param {number} column The column within the line for the location
    604  * @param {number} start Source position for start of source context
    605  * @param {number} end Source position for end of source context
    606  * @constructor
    607  */
    608 function SourceLocation(script, position, line, column, start, end) {
    609   this.script = script;
    610   this.position = position;
    611   this.line = line;
    612   this.column = column;
    613   this.start = start;
    614   this.end = end;
    615 }
    616 
    617 var kLineLengthLimit = 78;
    618 
    619 /**
    620  * Restrict source location start and end positions to make the source slice
    621  * no more that a certain number of characters wide.
    622  * @param {number} opt_limit The with limit of the source text with a default
    623  *     of 78
    624  * @param {number} opt_before The number of characters to prefer before the
    625  *     position with a default value of 10 less that the limit
    626  */
    627 function SourceLocationRestrict(opt_limit, opt_before) {
    628   // Find the actual limit to use.
    629   var limit;
    630   var before;
    631   if (!IS_UNDEFINED(opt_limit)) {
    632     limit = opt_limit;
    633   } else {
    634     limit = kLineLengthLimit;
    635   }
    636   if (!IS_UNDEFINED(opt_before)) {
    637     before = opt_before;
    638   } else {
    639     // If no before is specified center for small limits and perfer more source
    640     // before the the position that after for longer limits.
    641     if (limit <= 20) {
    642       before = $floor(limit / 2);
    643     } else {
    644       before = limit - 10;
    645     }
    646   }
    647   if (before >= limit) {
    648     before = limit - 1;
    649   }
    650 
    651   // If the [start, end[ interval is too big we restrict
    652   // it in one or both ends. We make sure to always produce
    653   // restricted intervals of maximum allowed size.
    654   if (this.end - this.start > limit) {
    655     var start_limit = this.position - before;
    656     var end_limit = this.position + limit - before;
    657     if (this.start < start_limit && end_limit < this.end) {
    658       this.start = start_limit;
    659       this.end = end_limit;
    660     } else if (this.start < start_limit) {
    661       this.start = this.end - limit;
    662     } else {
    663       this.end = this.start + limit;
    664     }
    665   }
    666 }
    667 
    668 
    669 /**
    670  * Get the source text for a SourceLocation
    671  * @return {String}
    672  *     Source text for this location.
    673  */
    674 function SourceLocationSourceText() {
    675   return %_CallFunction(this.script.source,
    676                         this.start,
    677                         this.end,
    678                         StringSubstring);
    679 }
    680 
    681 
    682 SetUpLockedPrototype(SourceLocation,
    683   $Array("script", "position", "line", "column", "start", "end"),
    684   $Array(
    685     "restrict", SourceLocationRestrict,
    686     "sourceText", SourceLocationSourceText
    687  )
    688 );
    689 
    690 
    691 /**
    692  * Class for a source slice. A source slice is a part of a script source with
    693  * the following properties:
    694  *   script        : script object for the source
    695  *   from_line     : line number for the first line in the slice
    696  *   to_line       : source line number for the last line in the slice
    697  *   from_position : position of the first character in the slice
    698  *   to_position   : position of the last character in the slice
    699  * The to_line and to_position are not included in the slice, that is the lines
    700  * in the slice are [from_line, to_line[. Likewise the characters in the slice
    701  * are [from_position, to_position[.
    702  * @param {Script} script The Script object for the source slice
    703  * @param {number} from_line
    704  * @param {number} to_line
    705  * @param {number} from_position
    706  * @param {number} to_position
    707  * @constructor
    708  */
    709 function SourceSlice(script, from_line, to_line, from_position, to_position) {
    710   this.script = script;
    711   this.from_line = from_line;
    712   this.to_line = to_line;
    713   this.from_position = from_position;
    714   this.to_position = to_position;
    715 }
    716 
    717 /**
    718  * Get the source text for a SourceSlice
    719  * @return {String} Source text for this slice. The last line will include
    720  *     the line terminating characters (if any)
    721  */
    722 function SourceSliceSourceText() {
    723   return %_CallFunction(this.script.source,
    724                         this.from_position,
    725                         this.to_position,
    726                         StringSubstring);
    727 }
    728 
    729 SetUpLockedPrototype(SourceSlice,
    730   $Array("script", "from_line", "to_line", "from_position", "to_position"),
    731   $Array("sourceText", SourceSliceSourceText)
    732 );
    733 
    734 
    735 // Returns the offset of the given position within the containing
    736 // line.
    737 function GetPositionInLine(message) {
    738   var script = %MessageGetScript(message);
    739   var start_position = %MessageGetStartPosition(message);
    740   var location = script.locationFromPosition(start_position, false);
    741   if (location == null) return -1;
    742   location.restrict();
    743   return start_position - location.start;
    744 }
    745 
    746 
    747 function GetStackTraceLine(recv, fun, pos, isGlobal) {
    748   return FormatSourcePosition(new CallSite(recv, fun, pos));
    749 }
    750 
    751 // ----------------------------------------------------------------------------
    752 // Error implementation
    753 
    754 // Defines accessors for a property that is calculated the first time
    755 // the property is read.
    756 function DefineOneShotAccessor(obj, name, fun) {
    757   // Note that the accessors consistently operate on 'obj', not 'this'.
    758   // Since the object may occur in someone else's prototype chain we
    759   // can't rely on 'this' being the same as 'obj'.
    760   var hasBeenSet = false;
    761   var value;
    762   var getter = function() {
    763     if (hasBeenSet) {
    764       return value;
    765     }
    766     hasBeenSet = true;
    767     value = fun(obj);
    768     return value;
    769   };
    770   var setter = function(v) {
    771     hasBeenSet = true;
    772     value = v;
    773   };
    774   %DefineOrRedefineAccessorProperty(obj, name, getter, setter, DONT_ENUM);
    775 }
    776 
    777 function CallSite(receiver, fun, pos) {
    778   this.receiver = receiver;
    779   this.fun = fun;
    780   this.pos = pos;
    781 }
    782 
    783 function CallSiteGetThis() {
    784   return this.receiver;
    785 }
    786 
    787 function CallSiteGetTypeName() {
    788   var constructor = this.receiver.constructor;
    789   if (!constructor) {
    790     return %_CallFunction(this.receiver, ObjectToString);
    791   }
    792   var constructorName = constructor.name;
    793   if (!constructorName) {
    794     return %_CallFunction(this.receiver, ObjectToString);
    795   }
    796   return constructorName;
    797 }
    798 
    799 function CallSiteIsToplevel() {
    800   if (this.receiver == null) {
    801     return true;
    802   }
    803   return IS_GLOBAL(this.receiver);
    804 }
    805 
    806 function CallSiteIsEval() {
    807   var script = %FunctionGetScript(this.fun);
    808   return script && script.compilation_type == COMPILATION_TYPE_EVAL;
    809 }
    810 
    811 function CallSiteGetEvalOrigin() {
    812   var script = %FunctionGetScript(this.fun);
    813   return FormatEvalOrigin(script);
    814 }
    815 
    816 function CallSiteGetScriptNameOrSourceURL() {
    817   var script = %FunctionGetScript(this.fun);
    818   return script ? script.nameOrSourceURL() : null;
    819 }
    820 
    821 function CallSiteGetFunction() {
    822   return this.fun;
    823 }
    824 
    825 function CallSiteGetFunctionName() {
    826   // See if the function knows its own name
    827   var name = this.fun.name;
    828   if (name) {
    829     return name;
    830   } else {
    831     return %FunctionGetInferredName(this.fun);
    832   }
    833   // Maybe this is an evaluation?
    834   var script = %FunctionGetScript(this.fun);
    835   if (script && script.compilation_type == COMPILATION_TYPE_EVAL) {
    836     return "eval";
    837   }
    838   return null;
    839 }
    840 
    841 function CallSiteGetMethodName() {
    842   // See if we can find a unique property on the receiver that holds
    843   // this function.
    844   var ownName = this.fun.name;
    845   if (ownName && this.receiver &&
    846       (%_CallFunction(this.receiver,
    847                       ownName,
    848                       ObjectLookupGetter) === this.fun ||
    849        %_CallFunction(this.receiver,
    850                       ownName,
    851                       ObjectLookupSetter) === this.fun ||
    852        this.receiver[ownName] === this.fun)) {
    853     // To handle DontEnum properties we guess that the method has
    854     // the same name as the function.
    855     return ownName;
    856   }
    857   var name = null;
    858   for (var prop in this.receiver) {
    859     if (this.receiver.__lookupGetter__(prop) === this.fun ||
    860         this.receiver.__lookupSetter__(prop) === this.fun ||
    861         (!this.receiver.__lookupGetter__(prop) &&
    862          this.receiver[prop] === this.fun)) {
    863       // If we find more than one match bail out to avoid confusion.
    864       if (name) {
    865         return null;
    866       }
    867       name = prop;
    868     }
    869   }
    870   if (name) {
    871     return name;
    872   }
    873   return null;
    874 }
    875 
    876 function CallSiteGetFileName() {
    877   var script = %FunctionGetScript(this.fun);
    878   return script ? script.name : null;
    879 }
    880 
    881 function CallSiteGetLineNumber() {
    882   if (this.pos == -1) {
    883     return null;
    884   }
    885   var script = %FunctionGetScript(this.fun);
    886   var location = null;
    887   if (script) {
    888     location = script.locationFromPosition(this.pos, true);
    889   }
    890   return location ? location.line + 1 : null;
    891 }
    892 
    893 function CallSiteGetColumnNumber() {
    894   if (this.pos == -1) {
    895     return null;
    896   }
    897   var script = %FunctionGetScript(this.fun);
    898   var location = null;
    899   if (script) {
    900     location = script.locationFromPosition(this.pos, true);
    901   }
    902   return location ? location.column + 1: null;
    903 }
    904 
    905 function CallSiteIsNative() {
    906   var script = %FunctionGetScript(this.fun);
    907   return script ? (script.type == TYPE_NATIVE) : false;
    908 }
    909 
    910 function CallSiteGetPosition() {
    911   return this.pos;
    912 }
    913 
    914 function CallSiteIsConstructor() {
    915   var constructor = this.receiver ? this.receiver.constructor : null;
    916   if (!constructor) {
    917     return false;
    918   }
    919   return this.fun === constructor;
    920 }
    921 
    922 SetUpLockedPrototype(CallSite, $Array("receiver", "fun", "pos"), $Array(
    923   "getThis", CallSiteGetThis,
    924   "getTypeName", CallSiteGetTypeName,
    925   "isToplevel", CallSiteIsToplevel,
    926   "isEval", CallSiteIsEval,
    927   "getEvalOrigin", CallSiteGetEvalOrigin,
    928   "getScriptNameOrSourceURL", CallSiteGetScriptNameOrSourceURL,
    929   "getFunction", CallSiteGetFunction,
    930   "getFunctionName", CallSiteGetFunctionName,
    931   "getMethodName", CallSiteGetMethodName,
    932   "getFileName", CallSiteGetFileName,
    933   "getLineNumber", CallSiteGetLineNumber,
    934   "getColumnNumber", CallSiteGetColumnNumber,
    935   "isNative", CallSiteIsNative,
    936   "getPosition", CallSiteGetPosition,
    937   "isConstructor", CallSiteIsConstructor
    938 ));
    939 
    940 
    941 function FormatEvalOrigin(script) {
    942   var sourceURL = script.nameOrSourceURL();
    943   if (sourceURL) {
    944     return sourceURL;
    945   }
    946 
    947   var eval_origin = "eval at ";
    948   if (script.eval_from_function_name) {
    949     eval_origin += script.eval_from_function_name;
    950   } else {
    951     eval_origin +=  "<anonymous>";
    952   }
    953 
    954   var eval_from_script = script.eval_from_script;
    955   if (eval_from_script) {
    956     if (eval_from_script.compilation_type == COMPILATION_TYPE_EVAL) {
    957       // eval script originated from another eval.
    958       eval_origin += " (" + FormatEvalOrigin(eval_from_script) + ")";
    959     } else {
    960       // eval script originated from "real" source.
    961       if (eval_from_script.name) {
    962         eval_origin += " (" + eval_from_script.name;
    963         var location = eval_from_script.locationFromPosition(
    964             script.eval_from_script_position, true);
    965         if (location) {
    966           eval_origin += ":" + (location.line + 1);
    967           eval_origin += ":" + (location.column + 1);
    968         }
    969         eval_origin += ")";
    970       } else {
    971         eval_origin += " (unknown source)";
    972       }
    973     }
    974   }
    975 
    976   return eval_origin;
    977 }
    978 
    979 function FormatSourcePosition(frame) {
    980   var fileName;
    981   var fileLocation = "";
    982   if (frame.isNative()) {
    983     fileLocation = "native";
    984   } else if (frame.isEval()) {
    985     fileName = frame.getScriptNameOrSourceURL();
    986     if (!fileName) {
    987       fileLocation = frame.getEvalOrigin();
    988     }
    989   } else {
    990     fileName = frame.getFileName();
    991   }
    992 
    993   if (fileName) {
    994     fileLocation += fileName;
    995     var lineNumber = frame.getLineNumber();
    996     if (lineNumber != null) {
    997       fileLocation += ":" + lineNumber;
    998       var columnNumber = frame.getColumnNumber();
    999       if (columnNumber) {
   1000         fileLocation += ":" + columnNumber;
   1001       }
   1002     }
   1003   }
   1004 
   1005   if (!fileLocation) {
   1006     fileLocation = "unknown source";
   1007   }
   1008   var line = "";
   1009   var functionName = frame.getFunction().name;
   1010   var addPrefix = true;
   1011   var isConstructor = frame.isConstructor();
   1012   var isMethodCall = !(frame.isToplevel() || isConstructor);
   1013   if (isMethodCall) {
   1014     var methodName = frame.getMethodName();
   1015     line += frame.getTypeName() + ".";
   1016     if (functionName) {
   1017       line += functionName;
   1018       if (methodName && (methodName != functionName)) {
   1019         line += " [as " + methodName + "]";
   1020       }
   1021     } else {
   1022       line += methodName || "<anonymous>";
   1023     }
   1024   } else if (isConstructor) {
   1025     line += "new " + (functionName || "<anonymous>");
   1026   } else if (functionName) {
   1027     line += functionName;
   1028   } else {
   1029     line += fileLocation;
   1030     addPrefix = false;
   1031   }
   1032   if (addPrefix) {
   1033     line += " (" + fileLocation + ")";
   1034   }
   1035   return line;
   1036 }
   1037 
   1038 function FormatStackTrace(error, frames) {
   1039   var lines = [];
   1040   try {
   1041     lines.push(error.toString());
   1042   } catch (e) {
   1043     try {
   1044       lines.push("<error: " + e + ">");
   1045     } catch (ee) {
   1046       lines.push("<error>");
   1047     }
   1048   }
   1049   for (var i = 0; i < frames.length; i++) {
   1050     var frame = frames[i];
   1051     var line;
   1052     try {
   1053       line = FormatSourcePosition(frame);
   1054     } catch (e) {
   1055       try {
   1056         line = "<error: " + e + ">";
   1057       } catch (ee) {
   1058         // Any code that reaches this point is seriously nasty!
   1059         line = "<error>";
   1060       }
   1061     }
   1062     lines.push("    at " + line);
   1063   }
   1064   return lines.join("\n");
   1065 }
   1066 
   1067 function FormatRawStackTrace(error, raw_stack) {
   1068   var frames = [ ];
   1069   for (var i = 0; i < raw_stack.length; i += 4) {
   1070     var recv = raw_stack[i];
   1071     var fun = raw_stack[i + 1];
   1072     var code = raw_stack[i + 2];
   1073     var pc = raw_stack[i + 3];
   1074     var pos = %FunctionGetPositionForOffset(code, pc);
   1075     frames.push(new CallSite(recv, fun, pos));
   1076   }
   1077   if (IS_FUNCTION($Error.prepareStackTrace)) {
   1078     return $Error.prepareStackTrace(error, frames);
   1079   } else {
   1080     return FormatStackTrace(error, frames);
   1081   }
   1082 }
   1083 
   1084 
   1085 function captureStackTrace(obj, cons_opt) {
   1086   var stackTraceLimit = $Error.stackTraceLimit;
   1087   if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return;
   1088   if (stackTraceLimit < 0 || stackTraceLimit > 10000) {
   1089     stackTraceLimit = 10000;
   1090   }
   1091   var raw_stack = %CollectStackTrace(obj,
   1092                                      cons_opt ? cons_opt : captureStackTrace,
   1093                                      stackTraceLimit);
   1094   DefineOneShotAccessor(obj, 'stack', function (obj) {
   1095     return FormatRawStackTrace(obj, raw_stack);
   1096   });
   1097 }
   1098 
   1099 
   1100 function SetUpError() {
   1101   // Define special error type constructors.
   1102 
   1103   var DefineError = function(f) {
   1104     // Store the error function in both the global object
   1105     // and the runtime object. The function is fetched
   1106     // from the runtime object when throwing errors from
   1107     // within the runtime system to avoid strange side
   1108     // effects when overwriting the error functions from
   1109     // user code.
   1110     var name = f.name;
   1111     %SetProperty(global, name, f, DONT_ENUM);
   1112     %SetProperty(builtins, '$' + name, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
   1113     // Configure the error function.
   1114     if (name == 'Error') {
   1115       // The prototype of the Error object must itself be an error.
   1116       // However, it can't be an instance of the Error object because
   1117       // it hasn't been properly configured yet.  Instead we create a
   1118       // special not-a-true-error-but-close-enough object.
   1119       var ErrorPrototype = function() {};
   1120       %FunctionSetPrototype(ErrorPrototype, $Object.prototype);
   1121       %FunctionSetInstanceClassName(ErrorPrototype, 'Error');
   1122       %FunctionSetPrototype(f, new ErrorPrototype());
   1123     } else {
   1124       %FunctionSetPrototype(f, new $Error());
   1125     }
   1126     %FunctionSetInstanceClassName(f, 'Error');
   1127     %SetProperty(f.prototype, 'constructor', f, DONT_ENUM);
   1128     // The name property on the prototype of error objects is not
   1129     // specified as being read-one and dont-delete. However, allowing
   1130     // overwriting allows leaks of error objects between script blocks
   1131     // in the same context in a browser setting. Therefore we fix the
   1132     // name.
   1133     %SetProperty(f.prototype, "name", name,
   1134                  DONT_ENUM | DONT_DELETE | READ_ONLY)  ;
   1135     %SetCode(f, function(m) {
   1136       if (%_IsConstructCall()) {
   1137         // Define all the expected properties directly on the error
   1138         // object. This avoids going through getters and setters defined
   1139         // on prototype objects.
   1140         %IgnoreAttributesAndSetProperty(this, 'stack', void 0, DONT_ENUM);
   1141         %IgnoreAttributesAndSetProperty(this, 'arguments', void 0, DONT_ENUM);
   1142         %IgnoreAttributesAndSetProperty(this, 'type', void 0, DONT_ENUM);
   1143         if (m === kAddMessageAccessorsMarker) {
   1144           // DefineOneShotAccessor always inserts a message property and
   1145           // ignores setters.
   1146           DefineOneShotAccessor(this, 'message', function (obj) {
   1147               return FormatMessage(%NewMessageObject(obj.type, obj.arguments));
   1148           });
   1149         } else if (!IS_UNDEFINED(m)) {
   1150           %IgnoreAttributesAndSetProperty(this,
   1151                                           'message',
   1152                                           ToString(m),
   1153                                           DONT_ENUM);
   1154         }
   1155         captureStackTrace(this, f);
   1156       } else {
   1157         return new f(m);
   1158       }
   1159     });
   1160     %SetNativeFlag(f);
   1161   };
   1162 
   1163   DefineError(function Error() { });
   1164   DefineError(function TypeError() { });
   1165   DefineError(function RangeError() { });
   1166   DefineError(function SyntaxError() { });
   1167   DefineError(function ReferenceError() { });
   1168   DefineError(function EvalError() { });
   1169   DefineError(function URIError() { });
   1170 }
   1171 
   1172 SetUpError();
   1173 
   1174 $Error.captureStackTrace = captureStackTrace;
   1175 
   1176 %SetProperty($Error.prototype, 'message', '', DONT_ENUM);
   1177 
   1178 // Global list of error objects visited during ErrorToString. This is
   1179 // used to detect cycles in error toString formatting.
   1180 var visited_errors = new InternalArray();
   1181 var cyclic_error_marker = new $Object();
   1182 
   1183 function ErrorToStringDetectCycle(error) {
   1184   if (!%PushIfAbsent(visited_errors, error)) throw cyclic_error_marker;
   1185   try {
   1186     var type = error.type;
   1187     var name = error.name;
   1188     name = IS_UNDEFINED(name) ? "Error" : TO_STRING_INLINE(name);
   1189     var message = error.message;
   1190     var hasMessage = %_CallFunction(error, "message", ObjectHasOwnProperty);
   1191     if (type && !hasMessage) {
   1192       message = FormatMessage(%NewMessageObject(type, error.arguments));
   1193     }
   1194     message = IS_UNDEFINED(message) ? "" : TO_STRING_INLINE(message);
   1195     if (name === "") return message;
   1196     if (message === "") return name;
   1197     return name + ": " + message;
   1198   } finally {
   1199     visited_errors.length = visited_errors.length - 1;
   1200   }
   1201 }
   1202 
   1203 function ErrorToString() {
   1204   if (!IS_SPEC_OBJECT(this)) {
   1205     throw MakeTypeError("called_on_non_object", ["Error.prototype.toString"]);
   1206   }
   1207 
   1208   try {
   1209     return ErrorToStringDetectCycle(this);
   1210   } catch(e) {
   1211     // If this error message was encountered already return the empty
   1212     // string for it instead of recursively formatting it.
   1213     if (e === cyclic_error_marker) {
   1214       return '';
   1215     }
   1216     throw e;
   1217   }
   1218 }
   1219 
   1220 
   1221 InstallFunctions($Error.prototype, DONT_ENUM, ['toString', ErrorToString]);
   1222 
   1223 // Boilerplate for exceptions for stack overflows. Used from
   1224 // Isolate::StackOverflow().
   1225 var kStackOverflowBoilerplate = MakeRangeError('stack_overflow', []);
   1226