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