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