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