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 // Lazily initialized.
     42 var kVowelSounds = 0;
     43 var kCapitalVowelSounds = 0;
     44 
     45 // If this object gets passed to an error constructor the error will
     46 // get an accessor for .message that constructs a descriptive error
     47 // message on access.
     48 var kAddMessageAccessorsMarker = { };
     49 
     50 
     51 function GetInstanceName(cons) {
     52   if (cons.length == 0) {
     53     return "";
     54   }
     55   var first = %StringToLowerCase(StringCharAt.call(cons, 0));
     56   if (kVowelSounds === 0) {
     57     kVowelSounds = {a: true, e: true, i: true, o: true, u: true, y: true};
     58     kCapitalVowelSounds = {a: true, e: true, i: true, o: true, u: true, h: true,
     59         f: true, l: true, m: true, n: true, r: true, s: true, x: true, y: true};
     60   }
     61   var vowel_mapping = kVowelSounds;
     62   if (cons.length > 1 && (StringCharAt.call(cons, 0) != first)) {
     63     // First char is upper case
     64     var second = %StringToLowerCase(StringCharAt.call(cons, 1));
     65     // Second char is upper case
     66     if (StringCharAt.call(cons, 1) != second) {
     67       vowel_mapping = kCapitalVowelSounds;
     68     }
     69   }
     70   var s = vowel_mapping[first] ? "an " : "a ";
     71   return s + cons;
     72 }
     73 
     74 
     75 var kMessages = 0;
     76 
     77 
     78 function FormatString(format, args) {
     79   var result = format;
     80   for (var i = 0; i < args.length; i++) {
     81     var str;
     82     try { str = ToDetailString(args[i]); }
     83     catch (e) { str = "#<error>"; }
     84     result = ArrayJoin.call(StringSplit.call(result, "%" + i), str);
     85   }
     86   return result;
     87 }
     88 
     89 
     90 function ToDetailString(obj) {
     91   if (obj != null && IS_OBJECT(obj) && obj.toString === $Object.prototype.toString) {
     92     var constructor = obj.constructor;
     93     if (!constructor) return ToString(obj);
     94     var constructorName = constructor.name;
     95     if (!constructorName) return ToString(obj);
     96     return "#<" + GetInstanceName(constructorName) + ">";
     97   } else {
     98     return ToString(obj);
     99   }
    100 }
    101 
    102 
    103 function MakeGenericError(constructor, type, args) {
    104   if (IS_UNDEFINED(args)) {
    105     args = [];
    106   }
    107   var e = new constructor(kAddMessageAccessorsMarker);
    108   e.type = type;
    109   e.arguments = args;
    110   return e;
    111 }
    112 
    113 
    114 /**
    115  * Setup the Script function and constructor.
    116  */
    117 %FunctionSetInstanceClassName(Script, 'Script');
    118 %SetProperty(Script.prototype, 'constructor', Script, DONT_ENUM);
    119 %SetCode(Script, function(x) {
    120   // Script objects can only be created by the VM.
    121   throw new $Error("Not supported");
    122 });
    123 
    124 
    125 // Helper functions; called from the runtime system.
    126 function FormatMessage(message) {
    127   if (kMessages === 0) {
    128     kMessages = {
    129       // Error
    130       cyclic_proto:                 "Cyclic __proto__ value",
    131       // TypeError
    132       unexpected_token:             "Unexpected token %0",
    133       unexpected_token_number:      "Unexpected number",
    134       unexpected_token_string:      "Unexpected string",
    135       unexpected_token_identifier:  "Unexpected identifier",
    136       unexpected_eos:               "Unexpected end of input",
    137       malformed_regexp:             "Invalid regular expression: /%0/: %1",
    138       unterminated_regexp:          "Invalid regular expression: missing /",
    139       regexp_flags:                 "Cannot supply flags when constructing one RegExp from another",
    140       invalid_lhs_in_assignment:    "Invalid left-hand side in assignment",
    141       invalid_lhs_in_for_in:        "Invalid left-hand side in for-in",
    142       invalid_lhs_in_postfix_op:    "Invalid left-hand side expression in postfix operation",
    143       invalid_lhs_in_prefix_op:     "Invalid left-hand side expression in prefix operation",
    144       multiple_defaults_in_switch:  "More than one default clause in switch statement",
    145       newline_after_throw:          "Illegal newline after throw",
    146       redeclaration:                "%0 '%1' has already been declared",
    147       no_catch_or_finally:          "Missing catch or finally after try",
    148       unknown_label:                "Undefined label '%0'",
    149       uncaught_exception:           "Uncaught %0",
    150       stack_trace:                  "Stack Trace:\n%0",
    151       called_non_callable:          "%0 is not a function",
    152       undefined_method:             "Object %1 has no method '%0'",
    153       property_not_function:        "Property '%0' of object %1 is not a function",
    154       cannot_convert_to_primitive:  "Cannot convert object to primitive value",
    155       not_constructor:              "%0 is not a constructor",
    156       not_defined:                  "%0 is not defined",
    157       non_object_property_load:     "Cannot read property '%0' of %1",
    158       non_object_property_store:    "Cannot set property '%0' of %1",
    159       non_object_property_call:     "Cannot call method '%0' of %1",
    160       with_expression:              "%0 has no properties",
    161       illegal_invocation:           "Illegal invocation",
    162       no_setter_in_callback:        "Cannot set property %0 of %1 which has only a getter",
    163       apply_non_function:           "Function.prototype.apply was called on %0, which is a %1 and not a function",
    164       apply_wrong_args:             "Function.prototype.apply: Arguments list has wrong type",
    165       invalid_in_operator_use:      "Cannot use 'in' operator to search for '%0' in %1",
    166       instanceof_function_expected: "Expecting a function in instanceof check, but got %0",
    167       instanceof_nonobject_proto:   "Function has non-object prototype '%0' in instanceof check",
    168       null_to_object:               "Cannot convert null to object",
    169       reduce_no_initial:            "Reduce of empty array with no initial value",
    170       getter_must_be_callable:      "Getter must be a function: %0",
    171       setter_must_be_callable:      "Setter must be a function: %0",
    172       value_and_accessor:           "Invalid property.  A property cannot both have accessors and be writable or have a value: %0",
    173       proto_object_or_null:         "Object prototype may only be an Object or null",
    174       property_desc_object:         "Property description must be an object: %0",
    175       redefine_disallowed:          "Cannot redefine property: %0",
    176       define_disallowed:            "Cannot define property, object is not extensible: %0",
    177       // RangeError
    178       invalid_array_length:         "Invalid array length",
    179       stack_overflow:               "Maximum call stack size exceeded",
    180       apply_overflow:               "Function.prototype.apply cannot support %0 arguments",
    181       // SyntaxError
    182       unable_to_parse:              "Parse error",
    183       duplicate_regexp_flag:        "Duplicate RegExp flag %0",
    184       invalid_regexp:               "Invalid RegExp pattern /%0/",
    185       illegal_break:                "Illegal break statement",
    186       illegal_continue:             "Illegal continue statement",
    187       illegal_return:               "Illegal return statement",
    188       error_loading_debugger:       "Error loading debugger",
    189       no_input_to_regexp:           "No input to %0",
    190       result_not_primitive:         "Result of %0 must be a primitive, was %1",
    191       invalid_json:                 "String '%0' is not valid JSON",
    192       circular_structure:           "Converting circular structure to JSON",
    193       obj_ctor_property_non_object: "Object.%0 called on non-object",
    194       array_indexof_not_defined:    "Array.getIndexOf: Argument undefined"
    195     };
    196   }
    197   var format = kMessages[message.type];
    198   if (!format) return "<unknown message " + message.type + ">";
    199   return FormatString(format, message.args);
    200 }
    201 
    202 
    203 function GetLineNumber(message) {
    204   if (message.startPos == -1) return -1;
    205   var location = message.script.locationFromPosition(message.startPos, true);
    206   if (location == null) return -1;
    207   return location.line + 1;
    208 }
    209 
    210 
    211 // Returns the source code line containing the given source
    212 // position, or the empty string if the position is invalid.
    213 function GetSourceLine(message) {
    214   var location = message.script.locationFromPosition(message.startPos, true);
    215   if (location == null) return "";
    216   location.restrict();
    217   return location.sourceText();
    218 }
    219 
    220 
    221 function MakeTypeError(type, args) {
    222   return MakeGenericError($TypeError, type, args);
    223 }
    224 
    225 
    226 function MakeRangeError(type, args) {
    227   return MakeGenericError($RangeError, type, args);
    228 }
    229 
    230 
    231 function MakeSyntaxError(type, args) {
    232   return MakeGenericError($SyntaxError, type, args);
    233 }
    234 
    235 
    236 function MakeReferenceError(type, args) {
    237   return MakeGenericError($ReferenceError, type, args);
    238 }
    239 
    240 
    241 function MakeEvalError(type, args) {
    242   return MakeGenericError($EvalError, type, args);
    243 }
    244 
    245 
    246 function MakeError(type, args) {
    247   return MakeGenericError($Error, type, args);
    248 }
    249 
    250 /**
    251  * Find a line number given a specific source position.
    252  * @param {number} position The source position.
    253  * @return {number} 0 if input too small, -1 if input too large,
    254        else the line number.
    255  */
    256 Script.prototype.lineFromPosition = function(position) {
    257   var lower = 0;
    258   var upper = this.lineCount() - 1;
    259   var line_ends = this.line_ends;
    260 
    261   // We'll never find invalid positions so bail right away.
    262   if (position > line_ends[upper]) {
    263     return -1;
    264   }
    265 
    266   // This means we don't have to safe-guard indexing line_ends[i - 1].
    267   if (position <= line_ends[0]) {
    268     return 0;
    269   }
    270 
    271   // Binary search to find line # from position range.
    272   while (upper >= 1) {
    273     var i = (lower + upper) >> 1;
    274 
    275     if (position > line_ends[i]) {
    276       lower = i + 1;
    277     } else if (position <= line_ends[i - 1]) {
    278       upper = i - 1;
    279     } else {
    280       return i;
    281     }
    282   }
    283   return -1;
    284 }
    285 
    286 /**
    287  * Get information on a specific source position.
    288  * @param {number} position The source position
    289  * @param {boolean} include_resource_offset Set to true to have the resource
    290  *     offset added to the location
    291  * @return {SourceLocation}
    292  *     If line is negative or not in the source null is returned.
    293  */
    294 Script.prototype.locationFromPosition = function (position,
    295                                                   include_resource_offset) {
    296   var line = this.lineFromPosition(position);
    297   if (line == -1) return null;
    298 
    299   // Determine start, end and column.
    300   var line_ends = this.line_ends;
    301   var start = line == 0 ? 0 : line_ends[line - 1] + 1;
    302   var end = line_ends[line];
    303   if (end > 0 && StringCharAt.call(this.source, end - 1) == '\r') end--;
    304   var column = position - start;
    305 
    306   // Adjust according to the offset within the resource.
    307   if (include_resource_offset) {
    308     line += this.line_offset;
    309     if (line == this.line_offset) {
    310       column += this.column_offset;
    311     }
    312   }
    313 
    314   return new SourceLocation(this, position, line, column, start, end);
    315 };
    316 
    317 
    318 /**
    319  * Get information on a specific source line and column possibly offset by a
    320  * fixed source position. This function is used to find a source position from
    321  * a line and column position. The fixed source position offset is typically
    322  * used to find a source position in a function based on a line and column in
    323  * the source for the function alone. The offset passed will then be the
    324  * start position of the source for the function within the full script source.
    325  * @param {number} opt_line The line within the source. Default value is 0
    326  * @param {number} opt_column The column in within the line. Default value is 0
    327  * @param {number} opt_offset_position The offset from the begining of the
    328  *     source from where the line and column calculation starts. Default value is 0
    329  * @return {SourceLocation}
    330  *     If line is negative or not in the source null is returned.
    331  */
    332 Script.prototype.locationFromLine = function (opt_line, opt_column, opt_offset_position) {
    333   // Default is the first line in the script. Lines in the script is relative
    334   // to the offset within the resource.
    335   var line = 0;
    336   if (!IS_UNDEFINED(opt_line)) {
    337     line = opt_line - this.line_offset;
    338   }
    339 
    340   // Default is first column. If on the first line add the offset within the
    341   // resource.
    342   var column = opt_column || 0;
    343   if (line == 0) {
    344     column -= this.column_offset
    345   }
    346 
    347   var offset_position = opt_offset_position || 0;
    348   if (line < 0 || column < 0 || offset_position < 0) return null;
    349   if (line == 0) {
    350     return this.locationFromPosition(offset_position + column, false);
    351   } else {
    352     // Find the line where the offset position is located.
    353     var offset_line = this.lineFromPosition(offset_position);
    354 
    355     if (offset_line == -1 || offset_line + line >= this.lineCount()) {
    356       return null;
    357     }
    358 
    359     return this.locationFromPosition(this.line_ends[offset_line + line - 1] + 1 + column);  // line > 0 here.
    360   }
    361 }
    362 
    363 
    364 /**
    365  * Get a slice of source code from the script. The boundaries for the slice is
    366  * specified in lines.
    367  * @param {number} opt_from_line The first line (zero bound) in the slice.
    368  *     Default is 0
    369  * @param {number} opt_to_column The last line (zero bound) in the slice (non
    370  *     inclusive). Default is the number of lines in the script
    371  * @return {SourceSlice} The source slice or null of the parameters where
    372  *     invalid
    373  */
    374 Script.prototype.sourceSlice = function (opt_from_line, opt_to_line) {
    375   var from_line = IS_UNDEFINED(opt_from_line) ? this.line_offset : opt_from_line;
    376   var to_line = IS_UNDEFINED(opt_to_line) ? this.line_offset + this.lineCount() : opt_to_line
    377 
    378   // Adjust according to the offset within the resource.
    379   from_line -= this.line_offset;
    380   to_line -= this.line_offset;
    381   if (from_line < 0) from_line = 0;
    382   if (to_line > this.lineCount()) to_line = this.lineCount();
    383 
    384   // Check parameters.
    385   if (from_line >= this.lineCount() ||
    386       to_line < 0 ||
    387       from_line > to_line) {
    388     return null;
    389   }
    390 
    391   var line_ends = this.line_ends;
    392   var from_position = from_line == 0 ? 0 : line_ends[from_line - 1] + 1;
    393   var to_position = to_line == 0 ? 0 : line_ends[to_line - 1] + 1;
    394 
    395   // Return a source slice with line numbers re-adjusted to the resource.
    396   return new SourceSlice(this, from_line + this.line_offset, to_line + this.line_offset,
    397                          from_position, to_position);
    398 }
    399 
    400 
    401 Script.prototype.sourceLine = function (opt_line) {
    402   // Default is the first line in the script. Lines in the script are relative
    403   // to the offset within the resource.
    404   var line = 0;
    405   if (!IS_UNDEFINED(opt_line)) {
    406     line = opt_line - this.line_offset;
    407   }
    408 
    409   // Check parameter.
    410   if (line < 0 || this.lineCount() <= line) {
    411     return null;
    412   }
    413 
    414   // Return the source line.
    415   var line_ends = this.line_ends;
    416   var start = line == 0 ? 0 : line_ends[line - 1] + 1;
    417   var end = line_ends[line];
    418   return StringSubstring.call(this.source, start, end);
    419 }
    420 
    421 
    422 /**
    423  * Returns the number of source lines.
    424  * @return {number}
    425  *     Number of source lines.
    426  */
    427 Script.prototype.lineCount = function() {
    428   // Return number of source lines.
    429   return this.line_ends.length;
    430 };
    431 
    432 
    433 /**
    434  * Class for source location. A source location is a position within some
    435  * source with the following properties:
    436  *   script   : script object for the source
    437  *   line     : source line number
    438  *   column   : source column within the line
    439  *   position : position within the source
    440  *   start    : position of start of source context (inclusive)
    441  *   end      : position of end of source context (not inclusive)
    442  * Source text for the source context is the character interval [start, end[. In
    443  * most cases end will point to a newline character. It might point just past
    444  * the final position of the source if the last source line does not end with a
    445  * newline character.
    446  * @param {Script} script The Script object for which this is a location
    447  * @param {number} position Source position for the location
    448  * @param {number} line The line number for the location
    449  * @param {number} column The column within the line for the location
    450  * @param {number} start Source position for start of source context
    451  * @param {number} end Source position for end of source context
    452  * @constructor
    453  */
    454 function SourceLocation(script, position, line, column, start, end) {
    455   this.script = script;
    456   this.position = position;
    457   this.line = line;
    458   this.column = column;
    459   this.start = start;
    460   this.end = end;
    461 }
    462 
    463 
    464 const kLineLengthLimit = 78;
    465 
    466 /**
    467  * Restrict source location start and end positions to make the source slice
    468  * no more that a certain number of characters wide.
    469  * @param {number} opt_limit The with limit of the source text with a default
    470  *     of 78
    471  * @param {number} opt_before The number of characters to prefer before the
    472  *     position with a default value of 10 less that the limit
    473  */
    474 SourceLocation.prototype.restrict = function (opt_limit, opt_before) {
    475   // Find the actual limit to use.
    476   var limit;
    477   var before;
    478   if (!IS_UNDEFINED(opt_limit)) {
    479     limit = opt_limit;
    480   } else {
    481     limit = kLineLengthLimit;
    482   }
    483   if (!IS_UNDEFINED(opt_before)) {
    484     before = opt_before;
    485   } else {
    486     // If no before is specified center for small limits and perfer more source
    487     // before the the position that after for longer limits.
    488     if (limit <= 20) {
    489       before = $floor(limit / 2);
    490     } else {
    491       before = limit - 10;
    492     }
    493   }
    494   if (before >= limit) {
    495     before = limit - 1;
    496   }
    497 
    498   // If the [start, end[ interval is too big we restrict
    499   // it in one or both ends. We make sure to always produce
    500   // restricted intervals of maximum allowed size.
    501   if (this.end - this.start > limit) {
    502     var start_limit = this.position - before;
    503     var end_limit = this.position + limit - before;
    504     if (this.start < start_limit && end_limit < this.end) {
    505       this.start = start_limit;
    506       this.end = end_limit;
    507     } else if (this.start < start_limit) {
    508       this.start = this.end - limit;
    509     } else {
    510       this.end = this.start + limit;
    511     }
    512   }
    513 };
    514 
    515 
    516 /**
    517  * Get the source text for a SourceLocation
    518  * @return {String}
    519  *     Source text for this location.
    520  */
    521 SourceLocation.prototype.sourceText = function () {
    522   return StringSubstring.call(this.script.source, this.start, this.end);
    523 };
    524 
    525 
    526 /**
    527  * Class for a source slice. A source slice is a part of a script source with
    528  * the following properties:
    529  *   script        : script object for the source
    530  *   from_line     : line number for the first line in the slice
    531  *   to_line       : source line number for the last line in the slice
    532  *   from_position : position of the first character in the slice
    533  *   to_position   : position of the last character in the slice
    534  * The to_line and to_position are not included in the slice, that is the lines
    535  * in the slice are [from_line, to_line[. Likewise the characters in the slice
    536  * are [from_position, to_position[.
    537  * @param {Script} script The Script object for the source slice
    538  * @param {number} from_line
    539  * @param {number} to_line
    540  * @param {number} from_position
    541  * @param {number} to_position
    542  * @constructor
    543  */
    544 function SourceSlice(script, from_line, to_line, from_position, to_position) {
    545   this.script = script;
    546   this.from_line = from_line;
    547   this.to_line = to_line;
    548   this.from_position = from_position;
    549   this.to_position = to_position;
    550 }
    551 
    552 
    553 /**
    554  * Get the source text for a SourceSlice
    555  * @return {String} Source text for this slice. The last line will include
    556  *     the line terminating characters (if any)
    557  */
    558 SourceSlice.prototype.sourceText = function () {
    559   return StringSubstring.call(this.script.source, this.from_position, this.to_position);
    560 };
    561 
    562 
    563 // Returns the offset of the given position within the containing
    564 // line.
    565 function GetPositionInLine(message) {
    566   var location = message.script.locationFromPosition(message.startPos, false);
    567   if (location == null) return -1;
    568   location.restrict();
    569   return message.startPos - location.start;
    570 }
    571 
    572 
    573 function ErrorMessage(type, args, startPos, endPos, script, stackTrace) {
    574   this.startPos = startPos;
    575   this.endPos = endPos;
    576   this.type = type;
    577   this.args = args;
    578   this.script = script;
    579   this.stackTrace = stackTrace;
    580 }
    581 
    582 
    583 function MakeMessage(type, args, startPos, endPos, script, stackTrace) {
    584   return new ErrorMessage(type, args, startPos, endPos, script, stackTrace);
    585 }
    586 
    587 
    588 function GetStackTraceLine(recv, fun, pos, isGlobal) {
    589   return FormatSourcePosition(new CallSite(recv, fun, pos));
    590 }
    591 
    592 // ----------------------------------------------------------------------------
    593 // Error implementation
    594 
    595 // Defines accessors for a property that is calculated the first time
    596 // the property is read.
    597 function DefineOneShotAccessor(obj, name, fun) {
    598   // Note that the accessors consistently operate on 'obj', not 'this'.
    599   // Since the object may occur in someone else's prototype chain we
    600   // can't rely on 'this' being the same as 'obj'.
    601   var hasBeenSet = false;
    602   var value;
    603   obj.__defineGetter__(name, function () {
    604     if (hasBeenSet) {
    605       return value;
    606     }
    607     hasBeenSet = true;
    608     value = fun(obj);
    609     return value;
    610   });
    611   obj.__defineSetter__(name, function (v) {
    612     hasBeenSet = true;
    613     value = v;
    614   });
    615 }
    616 
    617 function CallSite(receiver, fun, pos) {
    618   this.receiver = receiver;
    619   this.fun = fun;
    620   this.pos = pos;
    621 }
    622 
    623 CallSite.prototype.getThis = function () {
    624   return this.receiver;
    625 };
    626 
    627 CallSite.prototype.getTypeName = function () {
    628   var constructor = this.receiver.constructor;
    629   if (!constructor)
    630     return $Object.prototype.toString.call(this.receiver);
    631   var constructorName = constructor.name;
    632   if (!constructorName)
    633     return $Object.prototype.toString.call(this.receiver);
    634   return constructorName;
    635 };
    636 
    637 CallSite.prototype.isToplevel = function () {
    638   if (this.receiver == null)
    639     return true;
    640   return IS_GLOBAL(this.receiver);
    641 };
    642 
    643 CallSite.prototype.isEval = function () {
    644   var script = %FunctionGetScript(this.fun);
    645   return script && script.compilation_type == COMPILATION_TYPE_EVAL;
    646 };
    647 
    648 CallSite.prototype.getEvalOrigin = function () {
    649   var script = %FunctionGetScript(this.fun);
    650   return FormatEvalOrigin(script);
    651 };
    652 
    653 CallSite.prototype.getFunction = function () {
    654   return this.fun;
    655 };
    656 
    657 CallSite.prototype.getFunctionName = function () {
    658   // See if the function knows its own name
    659   var name = this.fun.name;
    660   if (name) {
    661     return name;
    662   } else {
    663     return %FunctionGetInferredName(this.fun);
    664   }
    665   // Maybe this is an evaluation?
    666   var script = %FunctionGetScript(this.fun);
    667   if (script && script.compilation_type == COMPILATION_TYPE_EVAL)
    668     return "eval";
    669   return null;
    670 };
    671 
    672 CallSite.prototype.getMethodName = function () {
    673   // See if we can find a unique property on the receiver that holds
    674   // this function.
    675   var ownName = this.fun.name;
    676   if (ownName && this.receiver && this.receiver[ownName] === this.fun)
    677     // To handle DontEnum properties we guess that the method has
    678     // the same name as the function.
    679     return ownName;
    680   var name = null;
    681   for (var prop in this.receiver) {
    682     if (this.receiver[prop] === this.fun) {
    683       // If we find more than one match bail out to avoid confusion
    684       if (name)
    685         return null;
    686       name = prop;
    687     }
    688   }
    689   if (name)
    690     return name;
    691   return null;
    692 };
    693 
    694 CallSite.prototype.getFileName = function () {
    695   var script = %FunctionGetScript(this.fun);
    696   return script ? script.name : null;
    697 };
    698 
    699 CallSite.prototype.getLineNumber = function () {
    700   if (this.pos == -1)
    701     return null;
    702   var script = %FunctionGetScript(this.fun);
    703   var location = null;
    704   if (script) {
    705     location = script.locationFromPosition(this.pos, true);
    706   }
    707   return location ? location.line + 1 : null;
    708 };
    709 
    710 CallSite.prototype.getColumnNumber = function () {
    711   if (this.pos == -1)
    712     return null;
    713   var script = %FunctionGetScript(this.fun);
    714   var location = null;
    715   if (script) {
    716     location = script.locationFromPosition(this.pos, true);
    717   }
    718   return location ? location.column + 1: null;
    719 };
    720 
    721 CallSite.prototype.isNative = function () {
    722   var script = %FunctionGetScript(this.fun);
    723   return script ? (script.type == TYPE_NATIVE) : false;
    724 };
    725 
    726 CallSite.prototype.getPosition = function () {
    727   return this.pos;
    728 };
    729 
    730 CallSite.prototype.isConstructor = function () {
    731   var constructor = this.receiver ? this.receiver.constructor : null;
    732   if (!constructor)
    733     return false;
    734   return this.fun === constructor;
    735 };
    736 
    737 function FormatEvalOrigin(script) {
    738   var eval_origin = "";
    739   if (script.eval_from_function_name) {
    740     eval_origin += script.eval_from_function_name;
    741   } else {
    742     eval_origin +=  "<anonymous>";
    743   }
    744   
    745   var eval_from_script = script.eval_from_script;
    746   if (eval_from_script) {
    747     if (eval_from_script.compilation_type == COMPILATION_TYPE_EVAL) {
    748       // eval script originated from another eval.
    749       eval_origin += " (eval at " + FormatEvalOrigin(eval_from_script) + ")";
    750     } else {
    751       // eval script originated from "real" scource.
    752       if (eval_from_script.name) {
    753         eval_origin += " (" + eval_from_script.name;
    754         var location = eval_from_script.locationFromPosition(script.eval_from_script_position, true);
    755         if (location) {
    756           eval_origin += ":" + (location.line + 1);
    757           eval_origin += ":" + (location.column + 1);
    758         }
    759         eval_origin += ")"
    760       } else {
    761         eval_origin += " (unknown source)";
    762       }
    763     }
    764   }
    765   
    766   return eval_origin;
    767 };
    768 
    769 function FormatSourcePosition(frame) {
    770   var fileLocation = "";
    771   if (frame.isNative()) {
    772     fileLocation = "native";
    773   } else if (frame.isEval()) {
    774     fileLocation = "eval at " + frame.getEvalOrigin();
    775   } else {
    776     var fileName = frame.getFileName();
    777     if (fileName) {
    778       fileLocation += fileName;
    779       var lineNumber = frame.getLineNumber();
    780       if (lineNumber != null) {
    781         fileLocation += ":" + lineNumber;
    782         var columnNumber = frame.getColumnNumber();
    783         if (columnNumber) {
    784           fileLocation += ":" + columnNumber;
    785         }
    786       }
    787     }
    788   }
    789   if (!fileLocation) {
    790     fileLocation = "unknown source";
    791   }
    792   var line = "";
    793   var functionName = frame.getFunction().name;
    794   var methodName = frame.getMethodName();
    795   var addPrefix = true;
    796   var isConstructor = frame.isConstructor();
    797   var isMethodCall = !(frame.isToplevel() || isConstructor);
    798   if (isMethodCall) {
    799     line += frame.getTypeName() + ".";
    800     if (functionName) {
    801       line += functionName;
    802       if (methodName && (methodName != functionName)) {
    803         line += " [as " + methodName + "]";
    804       }
    805     } else {
    806       line += methodName || "<anonymous>";
    807     }
    808   } else if (isConstructor) {
    809     line += "new " + (functionName || "<anonymous>");
    810   } else if (functionName) {
    811     line += functionName;
    812   } else {
    813     line += fileLocation;
    814     addPrefix = false;
    815   }
    816   if (addPrefix) {
    817     line += " (" + fileLocation + ")";
    818   }
    819   return line;
    820 }
    821 
    822 function FormatStackTrace(error, frames) {
    823   var lines = [];
    824   try {
    825     lines.push(error.toString());
    826   } catch (e) {
    827     try {
    828       lines.push("<error: " + e + ">");
    829     } catch (ee) {
    830       lines.push("<error>");
    831     }
    832   }
    833   for (var i = 0; i < frames.length; i++) {
    834     var frame = frames[i];
    835     var line;
    836     try {
    837       line = FormatSourcePosition(frame);
    838     } catch (e) {
    839       try {
    840         line = "<error: " + e + ">";
    841       } catch (ee) {
    842         // Any code that reaches this point is seriously nasty!
    843         line = "<error>";
    844       }
    845     }
    846     lines.push("    at " + line);
    847   }
    848   return lines.join("\n");
    849 }
    850 
    851 function FormatRawStackTrace(error, raw_stack) {
    852   var frames = [ ];
    853   for (var i = 0; i < raw_stack.length; i += 3) {
    854     var recv = raw_stack[i];
    855     var fun = raw_stack[i+1];
    856     var pc = raw_stack[i+2];
    857     var pos = %FunctionGetPositionForOffset(fun, pc);
    858     frames.push(new CallSite(recv, fun, pos));
    859   }
    860   if (IS_FUNCTION($Error.prepareStackTrace)) {
    861     return $Error.prepareStackTrace(error, frames);
    862   } else {
    863     return FormatStackTrace(error, frames);
    864   }
    865 }
    866 
    867 function DefineError(f) {
    868   // Store the error function in both the global object
    869   // and the runtime object. The function is fetched
    870   // from the runtime object when throwing errors from
    871   // within the runtime system to avoid strange side
    872   // effects when overwriting the error functions from
    873   // user code.
    874   var name = f.name;
    875   %SetProperty(global, name, f, DONT_ENUM);
    876   this['$' + name] = f;
    877   // Configure the error function.
    878   if (name == 'Error') {
    879     // The prototype of the Error object must itself be an error.
    880     // However, it can't be an instance of the Error object because
    881     // it hasn't been properly configured yet.  Instead we create a
    882     // special not-a-true-error-but-close-enough object.
    883     function ErrorPrototype() {}
    884     %FunctionSetPrototype(ErrorPrototype, $Object.prototype);
    885     %FunctionSetInstanceClassName(ErrorPrototype, 'Error');
    886     %FunctionSetPrototype(f, new ErrorPrototype());
    887   } else {
    888     %FunctionSetPrototype(f, new $Error());
    889   }
    890   %FunctionSetInstanceClassName(f, 'Error');
    891   %SetProperty(f.prototype, 'constructor', f, DONT_ENUM);
    892   f.prototype.name = name;
    893   %SetCode(f, function(m) {
    894     if (%_IsConstructCall()) {
    895       if (m === kAddMessageAccessorsMarker) {
    896         DefineOneShotAccessor(this, 'message', function (obj) {
    897           return FormatMessage({type: obj.type, args: obj.arguments});
    898         });
    899       } else if (!IS_UNDEFINED(m)) {
    900         this.message = ToString(m);
    901       }
    902       captureStackTrace(this, f);
    903     } else {
    904       return new f(m);
    905     }
    906   });
    907 }
    908 
    909 function captureStackTrace(obj, cons_opt) {
    910   var stackTraceLimit = $Error.stackTraceLimit;
    911   if (!stackTraceLimit) return;
    912   if (stackTraceLimit < 0 || stackTraceLimit > 10000)
    913     stackTraceLimit = 10000;
    914   var raw_stack = %CollectStackTrace(cons_opt ? cons_opt : captureStackTrace,
    915       stackTraceLimit);
    916   DefineOneShotAccessor(obj, 'stack', function (obj) {
    917     return FormatRawStackTrace(obj, raw_stack);
    918   });
    919 };
    920 
    921 $Math.__proto__ = global.Object.prototype;
    922 
    923 DefineError(function Error() { });
    924 DefineError(function TypeError() { });
    925 DefineError(function RangeError() { });
    926 DefineError(function SyntaxError() { });
    927 DefineError(function ReferenceError() { });
    928 DefineError(function EvalError() { });
    929 DefineError(function URIError() { });
    930 
    931 $Error.captureStackTrace = captureStackTrace;
    932 
    933 // Setup extra properties of the Error.prototype object.
    934 $Error.prototype.message = '';
    935 
    936 %SetProperty($Error.prototype, 'toString', function toString() {
    937   var type = this.type;
    938   if (type && !this.hasOwnProperty("message")) {
    939     return this.name + ": " + FormatMessage({ type: type, args: this.arguments });
    940   }
    941   var message = this.message;
    942   return this.name + (message ? (": " + message) : "");
    943 }, DONT_ENUM);
    944 
    945 
    946 // Boilerplate for exceptions for stack overflows. Used from
    947 // Top::StackOverflow().
    948 const kStackOverflowBoilerplate = MakeRangeError('stack_overflow', []);
    949