Home | History | Annotate | Download | only in js
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // -------------------------------------------------------------------
      6 
      7 (function(global, utils) {
      8 
      9 %CheckIsBootstrapping();
     10 
     11 // -------------------------------------------------------------------
     12 // Imports
     13 
     14 var ArrayJoin;
     15 var Bool16x8ToString;
     16 var Bool32x4ToString;
     17 var Bool8x16ToString;
     18 var callSiteReceiverSymbol =
     19     utils.ImportNow("call_site_receiver_symbol");
     20 var callSiteFunctionSymbol =
     21     utils.ImportNow("call_site_function_symbol");
     22 var callSitePositionSymbol =
     23     utils.ImportNow("call_site_position_symbol");
     24 var callSiteStrictSymbol =
     25     utils.ImportNow("call_site_strict_symbol");
     26 var FLAG_harmony_tostring;
     27 var Float32x4ToString;
     28 var formattedStackTraceSymbol =
     29     utils.ImportNow("formatted_stack_trace_symbol");
     30 var GlobalObject = global.Object;
     31 var Int16x8ToString;
     32 var Int32x4ToString;
     33 var Int8x16ToString;
     34 var InternalArray = utils.InternalArray;
     35 var internalErrorSymbol = utils.ImportNow("internal_error_symbol");
     36 var ObjectDefineProperty;
     37 var ObjectToString = utils.ImportNow("object_to_string");
     38 var Script = utils.ImportNow("Script");
     39 var stackTraceSymbol = utils.ImportNow("stack_trace_symbol");
     40 var StringCharAt;
     41 var StringIndexOf;
     42 var StringSubstring;
     43 var SymbolToString;
     44 var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
     45 var Uint16x8ToString;
     46 var Uint32x4ToString;
     47 var Uint8x16ToString;
     48 
     49 utils.Import(function(from) {
     50   ArrayJoin = from.ArrayJoin;
     51   Bool16x8ToString = from.Bool16x8ToString;
     52   Bool32x4ToString = from.Bool32x4ToString;
     53   Bool8x16ToString = from.Bool8x16ToString;
     54   Float32x4ToString = from.Float32x4ToString;
     55   Int16x8ToString = from.Int16x8ToString;
     56   Int32x4ToString = from.Int32x4ToString;
     57   Int8x16ToString = from.Int8x16ToString;
     58   ObjectDefineProperty = from.ObjectDefineProperty;
     59   StringCharAt = from.StringCharAt;
     60   StringIndexOf = from.StringIndexOf;
     61   StringSubstring = from.StringSubstring;
     62   SymbolToString = from.SymbolToString;
     63   Uint16x8ToString = from.Uint16x8ToString;
     64   Uint32x4ToString = from.Uint32x4ToString;
     65   Uint8x16ToString = from.Uint8x16ToString;
     66 });
     67 
     68 utils.ImportFromExperimental(function(from) {
     69   FLAG_harmony_tostring = from.FLAG_harmony_tostring;
     70 });
     71 
     72 // -------------------------------------------------------------------
     73 
     74 var GlobalError;
     75 var GlobalTypeError;
     76 var GlobalRangeError;
     77 var GlobalURIError;
     78 var GlobalSyntaxError;
     79 var GlobalReferenceError;
     80 var GlobalEvalError;
     81 
     82 
     83 function NoSideEffectsObjectToString() {
     84   if (IS_UNDEFINED(this)) return "[object Undefined]";
     85   if (IS_NULL(this)) return "[object Null]";
     86   var O = TO_OBJECT(this);
     87   var builtinTag = %_ClassOf(O);
     88   var tag;
     89   if (FLAG_harmony_tostring) {
     90     tag = %GetDataProperty(O, toStringTagSymbol);
     91     if (!IS_STRING(tag)) {
     92       tag = builtinTag;
     93     }
     94   } else {
     95     tag = builtinTag;
     96   }
     97   return `[object ${tag}]`;
     98 }
     99 
    100 function IsErrorObject(obj) {
    101   return HAS_PRIVATE(obj, stackTraceSymbol);
    102 }
    103 
    104 function NoSideEffectsErrorToString() {
    105   var name = %GetDataProperty(this, "name");
    106   var message = %GetDataProperty(this, "message");
    107   name = IS_UNDEFINED(name) ? "Error" : NoSideEffectsToString(name);
    108   message = IS_UNDEFINED(message) ? "" : NoSideEffectsToString(message);
    109   if (name == "") return message;
    110   if (message == "") return name;
    111   return `${name}: ${message}`;
    112 }
    113 
    114 function NoSideEffectsToString(obj) {
    115   if (IS_STRING(obj)) return obj;
    116   if (IS_NUMBER(obj)) return %_NumberToString(obj);
    117   if (IS_BOOLEAN(obj)) return obj ? 'true' : 'false';
    118   if (IS_UNDEFINED(obj)) return 'undefined';
    119   if (IS_NULL(obj)) return 'null';
    120   if (IS_FUNCTION(obj)) {
    121     var str = %FunctionToString(obj);
    122     if (str.length > 128) {
    123       str = %_SubString(str, 0, 111) + "...<omitted>..." +
    124             %_SubString(str, str.length - 2, str.length);
    125     }
    126     return str;
    127   }
    128   if (IS_SYMBOL(obj)) return %_Call(SymbolToString, obj);
    129   if (IS_SIMD_VALUE(obj)) {
    130     switch (typeof(obj)) {
    131       case 'float32x4': return %_Call(Float32x4ToString, obj);
    132       case 'int32x4':   return %_Call(Int32x4ToString, obj);
    133       case 'int16x8':   return %_Call(Int16x8ToString, obj);
    134       case 'int8x16':   return %_Call(Int8x16ToString, obj);
    135       case 'uint32x4':   return %_Call(Uint32x4ToString, obj);
    136       case 'uint16x8':   return %_Call(Uint16x8ToString, obj);
    137       case 'uint8x16':   return %_Call(Uint8x16ToString, obj);
    138       case 'bool32x4':  return %_Call(Bool32x4ToString, obj);
    139       case 'bool16x8':  return %_Call(Bool16x8ToString, obj);
    140       case 'bool8x16':  return %_Call(Bool8x16ToString, obj);
    141     }
    142   }
    143 
    144   if (IS_RECEIVER(obj)) {
    145     // When internally formatting error objects, use a side-effects-free version
    146     // of Error.prototype.toString independent of the actually installed
    147     // toString method.
    148     if (IsErrorObject(obj) ||
    149         %GetDataProperty(obj, "toString") === ErrorToString) {
    150       return %_Call(NoSideEffectsErrorToString, obj);
    151     }
    152 
    153     if (%GetDataProperty(obj, "toString") === ObjectToString) {
    154       var constructor = %GetDataProperty(obj, "constructor");
    155       if (IS_FUNCTION(constructor)) {
    156         var constructor_name = %FunctionGetName(constructor);
    157         if (constructor_name != "") return `#<${constructor_name}>`;
    158       }
    159     }
    160   }
    161 
    162   return %_Call(NoSideEffectsObjectToString, obj);
    163 }
    164 
    165 
    166 function MakeGenericError(constructor, type, arg0, arg1, arg2) {
    167   var error = new constructor(FormatMessage(type, arg0, arg1, arg2));
    168   error[internalErrorSymbol] = true;
    169   return error;
    170 }
    171 
    172 
    173 /**
    174  * Set up the Script function and constructor.
    175  */
    176 %FunctionSetInstanceClassName(Script, 'Script');
    177 %AddNamedProperty(Script.prototype, 'constructor', Script,
    178                   DONT_ENUM | DONT_DELETE | READ_ONLY);
    179 %SetCode(Script, function(x) {
    180   // Script objects can only be created by the VM.
    181   throw MakeError(kUnsupported);
    182 });
    183 
    184 
    185 // Helper functions; called from the runtime system.
    186 function FormatMessage(type, arg0, arg1, arg2) {
    187   var arg0 = NoSideEffectsToString(arg0);
    188   var arg1 = NoSideEffectsToString(arg1);
    189   var arg2 = NoSideEffectsToString(arg2);
    190   try {
    191     return %FormatMessageString(type, arg0, arg1, arg2);
    192   } catch (e) {
    193     return "<error>";
    194   }
    195 }
    196 
    197 
    198 function GetLineNumber(message) {
    199   var start_position = %MessageGetStartPosition(message);
    200   if (start_position == -1) return kNoLineNumberInfo;
    201   var script = %MessageGetScript(message);
    202   var location = script.locationFromPosition(start_position, true);
    203   if (location == null) return kNoLineNumberInfo;
    204   return location.line + 1;
    205 }
    206 
    207 
    208 //Returns the offset of the given position within the containing line.
    209 function GetColumnNumber(message) {
    210   var script = %MessageGetScript(message);
    211   var start_position = %MessageGetStartPosition(message);
    212   var location = script.locationFromPosition(start_position, true);
    213   if (location == null) return -1;
    214   return location.column;
    215 }
    216 
    217 
    218 // Returns the source code line containing the given source
    219 // position, or the empty string if the position is invalid.
    220 function GetSourceLine(message) {
    221   var script = %MessageGetScript(message);
    222   var start_position = %MessageGetStartPosition(message);
    223   var location = script.locationFromPosition(start_position, true);
    224   if (location == null) return "";
    225   return location.sourceText();
    226 }
    227 
    228 
    229 /**
    230  * Find a line number given a specific source position.
    231  * @param {number} position The source position.
    232  * @return {number} 0 if input too small, -1 if input too large,
    233        else the line number.
    234  */
    235 function ScriptLineFromPosition(position) {
    236   var lower = 0;
    237   var upper = this.lineCount() - 1;
    238   var line_ends = this.line_ends;
    239 
    240   // We'll never find invalid positions so bail right away.
    241   if (position > line_ends[upper]) {
    242     return -1;
    243   }
    244 
    245   // This means we don't have to safe-guard indexing line_ends[i - 1].
    246   if (position <= line_ends[0]) {
    247     return 0;
    248   }
    249 
    250   // Binary search to find line # from position range.
    251   while (upper >= 1) {
    252     var i = (lower + upper) >> 1;
    253 
    254     if (position > line_ends[i]) {
    255       lower = i + 1;
    256     } else if (position <= line_ends[i - 1]) {
    257       upper = i - 1;
    258     } else {
    259       return i;
    260     }
    261   }
    262 
    263   return -1;
    264 }
    265 
    266 /**
    267  * Get information on a specific source position.
    268  * @param {number} position The source position
    269  * @param {boolean} include_resource_offset Set to true to have the resource
    270  *     offset added to the location
    271  * @return {SourceLocation}
    272  *     If line is negative or not in the source null is returned.
    273  */
    274 function ScriptLocationFromPosition(position,
    275                                     include_resource_offset) {
    276   var line = this.lineFromPosition(position);
    277   if (line == -1) return null;
    278 
    279   // Determine start, end and column.
    280   var line_ends = this.line_ends;
    281   var start = line == 0 ? 0 : line_ends[line - 1] + 1;
    282   var end = line_ends[line];
    283   if (end > 0 && %_Call(StringCharAt, this.source, end - 1) == '\r') {
    284     end--;
    285   }
    286   var column = position - start;
    287 
    288   // Adjust according to the offset within the resource.
    289   if (include_resource_offset) {
    290     line += this.line_offset;
    291     if (line == this.line_offset) {
    292       column += this.column_offset;
    293     }
    294   }
    295 
    296   return new SourceLocation(this, position, line, column, start, end);
    297 }
    298 
    299 
    300 /**
    301  * Get information on a specific source line and column possibly offset by a
    302  * fixed source position. This function is used to find a source position from
    303  * a line and column position. The fixed source position offset is typically
    304  * used to find a source position in a function based on a line and column in
    305  * the source for the function alone. The offset passed will then be the
    306  * start position of the source for the function within the full script source.
    307  * @param {number} opt_line The line within the source. Default value is 0
    308  * @param {number} opt_column The column in within the line. Default value is 0
    309  * @param {number} opt_offset_position The offset from the begining of the
    310  *     source from where the line and column calculation starts.
    311  *     Default value is 0
    312  * @return {SourceLocation}
    313  *     If line is negative or not in the source null is returned.
    314  */
    315 function ScriptLocationFromLine(opt_line, opt_column, opt_offset_position) {
    316   // Default is the first line in the script. Lines in the script is relative
    317   // to the offset within the resource.
    318   var line = 0;
    319   if (!IS_UNDEFINED(opt_line)) {
    320     line = opt_line - this.line_offset;
    321   }
    322 
    323   // Default is first column. If on the first line add the offset within the
    324   // resource.
    325   var column = opt_column || 0;
    326   if (line == 0) {
    327     column -= this.column_offset;
    328   }
    329 
    330   var offset_position = opt_offset_position || 0;
    331   if (line < 0 || column < 0 || offset_position < 0) return null;
    332   if (line == 0) {
    333     return this.locationFromPosition(offset_position + column, false);
    334   } else {
    335     // Find the line where the offset position is located.
    336     var offset_line = this.lineFromPosition(offset_position);
    337 
    338     if (offset_line == -1 || offset_line + line >= this.lineCount()) {
    339       return null;
    340     }
    341 
    342     return this.locationFromPosition(
    343         this.line_ends[offset_line + line - 1] + 1 + column);  // line > 0 here.
    344   }
    345 }
    346 
    347 
    348 /**
    349  * Get a slice of source code from the script. The boundaries for the slice is
    350  * specified in lines.
    351  * @param {number} opt_from_line The first line (zero bound) in the slice.
    352  *     Default is 0
    353  * @param {number} opt_to_column The last line (zero bound) in the slice (non
    354  *     inclusive). Default is the number of lines in the script
    355  * @return {SourceSlice} The source slice or null of the parameters where
    356  *     invalid
    357  */
    358 function ScriptSourceSlice(opt_from_line, opt_to_line) {
    359   var from_line = IS_UNDEFINED(opt_from_line) ? this.line_offset
    360                                               : opt_from_line;
    361   var to_line = IS_UNDEFINED(opt_to_line) ? this.line_offset + this.lineCount()
    362                                           : opt_to_line;
    363 
    364   // Adjust according to the offset within the resource.
    365   from_line -= this.line_offset;
    366   to_line -= this.line_offset;
    367   if (from_line < 0) from_line = 0;
    368   if (to_line > this.lineCount()) to_line = this.lineCount();
    369 
    370   // Check parameters.
    371   if (from_line >= this.lineCount() ||
    372       to_line < 0 ||
    373       from_line > to_line) {
    374     return null;
    375   }
    376 
    377   var line_ends = this.line_ends;
    378   var from_position = from_line == 0 ? 0 : line_ends[from_line - 1] + 1;
    379   var to_position = to_line == 0 ? 0 : line_ends[to_line - 1] + 1;
    380 
    381   // Return a source slice with line numbers re-adjusted to the resource.
    382   return new SourceSlice(this,
    383                          from_line + this.line_offset,
    384                          to_line + this.line_offset,
    385                           from_position, to_position);
    386 }
    387 
    388 
    389 function ScriptSourceLine(opt_line) {
    390   // Default is the first line in the script. Lines in the script are relative
    391   // to the offset within the resource.
    392   var line = 0;
    393   if (!IS_UNDEFINED(opt_line)) {
    394     line = opt_line - this.line_offset;
    395   }
    396 
    397   // Check parameter.
    398   if (line < 0 || this.lineCount() <= line) {
    399     return null;
    400   }
    401 
    402   // Return the source line.
    403   var line_ends = this.line_ends;
    404   var start = line == 0 ? 0 : line_ends[line - 1] + 1;
    405   var end = line_ends[line];
    406   return %_Call(StringSubstring, this.source, start, end);
    407 }
    408 
    409 
    410 /**
    411  * Returns the number of source lines.
    412  * @return {number}
    413  *     Number of source lines.
    414  */
    415 function ScriptLineCount() {
    416   // Return number of source lines.
    417   return this.line_ends.length;
    418 }
    419 
    420 
    421 /**
    422  * Returns the position of the nth line end.
    423  * @return {number}
    424  *     Zero-based position of the nth line end in the script.
    425  */
    426 function ScriptLineEnd(n) {
    427   return this.line_ends[n];
    428 }
    429 
    430 
    431 /**
    432  * If sourceURL comment is available returns sourceURL comment contents.
    433  * Otherwise, script name is returned. See
    434  * http://fbug.googlecode.com/svn/branches/firebug1.1/docs/ReleaseNotes_1.1.txt
    435  * and Source Map Revision 3 proposal for details on using //# sourceURL and
    436  * deprecated //@ sourceURL comment to identify scripts that don't have name.
    437  *
    438  * @return {?string} script name if present, value for //# sourceURL comment or
    439  * deprecated //@ sourceURL comment otherwise.
    440  */
    441 function ScriptNameOrSourceURL() {
    442   if (this.source_url) return this.source_url;
    443   return this.name;
    444 }
    445 
    446 
    447 utils.SetUpLockedPrototype(Script, [
    448     "source",
    449     "name",
    450     "source_url",
    451     "source_mapping_url",
    452     "line_ends",
    453     "line_offset",
    454     "column_offset"
    455   ], [
    456     "lineFromPosition", ScriptLineFromPosition,
    457     "locationFromPosition", ScriptLocationFromPosition,
    458     "locationFromLine", ScriptLocationFromLine,
    459     "sourceSlice", ScriptSourceSlice,
    460     "sourceLine", ScriptSourceLine,
    461     "lineCount", ScriptLineCount,
    462     "nameOrSourceURL", ScriptNameOrSourceURL,
    463     "lineEnd", ScriptLineEnd
    464   ]
    465 );
    466 
    467 
    468 /**
    469  * Class for source location. A source location is a position within some
    470  * source with the following properties:
    471  *   script   : script object for the source
    472  *   line     : source line number
    473  *   column   : source column within the line
    474  *   position : position within the source
    475  *   start    : position of start of source context (inclusive)
    476  *   end      : position of end of source context (not inclusive)
    477  * Source text for the source context is the character interval
    478  * [start, end[. In most cases end will point to a newline character.
    479  * It might point just past the final position of the source if the last
    480  * source line does not end with a newline character.
    481  * @param {Script} script The Script object for which this is a location
    482  * @param {number} position Source position for the location
    483  * @param {number} line The line number for the location
    484  * @param {number} column The column within the line for the location
    485  * @param {number} start Source position for start of source context
    486  * @param {number} end Source position for end of source context
    487  * @constructor
    488  */
    489 function SourceLocation(script, position, line, column, start, end) {
    490   this.script = script;
    491   this.position = position;
    492   this.line = line;
    493   this.column = column;
    494   this.start = start;
    495   this.end = end;
    496 }
    497 
    498 
    499 /**
    500  * Get the source text for a SourceLocation
    501  * @return {String}
    502  *     Source text for this location.
    503  */
    504 function SourceLocationSourceText() {
    505   return %_Call(StringSubstring, this.script.source, this.start, this.end);
    506 }
    507 
    508 
    509 utils.SetUpLockedPrototype(SourceLocation,
    510   ["script", "position", "line", "column", "start", "end"],
    511   ["sourceText", SourceLocationSourceText]
    512 );
    513 
    514 
    515 /**
    516  * Class for a source slice. A source slice is a part of a script source with
    517  * the following properties:
    518  *   script        : script object for the source
    519  *   from_line     : line number for the first line in the slice
    520  *   to_line       : source line number for the last line in the slice
    521  *   from_position : position of the first character in the slice
    522  *   to_position   : position of the last character in the slice
    523  * The to_line and to_position are not included in the slice, that is the lines
    524  * in the slice are [from_line, to_line[. Likewise the characters in the slice
    525  * are [from_position, to_position[.
    526  * @param {Script} script The Script object for the source slice
    527  * @param {number} from_line
    528  * @param {number} to_line
    529  * @param {number} from_position
    530  * @param {number} to_position
    531  * @constructor
    532  */
    533 function SourceSlice(script, from_line, to_line, from_position, to_position) {
    534   this.script = script;
    535   this.from_line = from_line;
    536   this.to_line = to_line;
    537   this.from_position = from_position;
    538   this.to_position = to_position;
    539 }
    540 
    541 /**
    542  * Get the source text for a SourceSlice
    543  * @return {String} Source text for this slice. The last line will include
    544  *     the line terminating characters (if any)
    545  */
    546 function SourceSliceSourceText() {
    547   return %_Call(StringSubstring,
    548                 this.script.source,
    549                 this.from_position,
    550                 this.to_position);
    551 }
    552 
    553 utils.SetUpLockedPrototype(SourceSlice,
    554   ["script", "from_line", "to_line", "from_position", "to_position"],
    555   ["sourceText", SourceSliceSourceText]
    556 );
    557 
    558 
    559 function GetStackTraceLine(recv, fun, pos, isGlobal) {
    560   return new CallSite(recv, fun, pos, false).toString();
    561 }
    562 
    563 // ----------------------------------------------------------------------------
    564 // Error implementation
    565 
    566 function CallSite(receiver, fun, pos, strict_mode) {
    567   if (!IS_FUNCTION(fun)) {
    568     throw MakeTypeError(kCallSiteExpectsFunction, typeof fun);
    569   }
    570 
    571   if (IS_UNDEFINED(new.target)) {
    572     return new CallSite(receiver, fun, pos, strict_mode);
    573   }
    574 
    575   SET_PRIVATE(this, callSiteReceiverSymbol, receiver);
    576   SET_PRIVATE(this, callSiteFunctionSymbol, fun);
    577   SET_PRIVATE(this, callSitePositionSymbol, TO_INT32(pos));
    578   SET_PRIVATE(this, callSiteStrictSymbol, TO_BOOLEAN(strict_mode));
    579 }
    580 
    581 function CallSiteGetThis() {
    582   return GET_PRIVATE(this, callSiteStrictSymbol)
    583       ? UNDEFINED : GET_PRIVATE(this, callSiteReceiverSymbol);
    584 }
    585 
    586 function CallSiteGetFunction() {
    587   return GET_PRIVATE(this, callSiteStrictSymbol)
    588       ? UNDEFINED : GET_PRIVATE(this, callSiteFunctionSymbol);
    589 }
    590 
    591 function CallSiteGetPosition() {
    592   return GET_PRIVATE(this, callSitePositionSymbol);
    593 }
    594 
    595 function CallSiteGetTypeName() {
    596   return GetTypeName(GET_PRIVATE(this, callSiteReceiverSymbol), false);
    597 }
    598 
    599 function CallSiteIsToplevel() {
    600   return %CallSiteIsToplevelRT(this);
    601 }
    602 
    603 function CallSiteIsEval() {
    604   return %CallSiteIsEvalRT(this);
    605 }
    606 
    607 function CallSiteGetEvalOrigin() {
    608   var script = %FunctionGetScript(GET_PRIVATE(this, callSiteFunctionSymbol));
    609   return FormatEvalOrigin(script);
    610 }
    611 
    612 function CallSiteGetScriptNameOrSourceURL() {
    613   return %CallSiteGetScriptNameOrSourceUrlRT(this);
    614 }
    615 
    616 function CallSiteGetFunctionName() {
    617   // See if the function knows its own name
    618   return %CallSiteGetFunctionNameRT(this);
    619 }
    620 
    621 function CallSiteGetMethodName() {
    622   // See if we can find a unique property on the receiver that holds
    623   // this function.
    624   return %CallSiteGetMethodNameRT(this);
    625 }
    626 
    627 function CallSiteGetFileName() {
    628   return %CallSiteGetFileNameRT(this);
    629 }
    630 
    631 function CallSiteGetLineNumber() {
    632   return %CallSiteGetLineNumberRT(this);
    633 }
    634 
    635 function CallSiteGetColumnNumber() {
    636   return %CallSiteGetColumnNumberRT(this);
    637 }
    638 
    639 function CallSiteIsNative() {
    640   return %CallSiteIsNativeRT(this);
    641 }
    642 
    643 function CallSiteIsConstructor() {
    644   return %CallSiteIsConstructorRT(this);
    645 }
    646 
    647 function CallSiteToString() {
    648   var fileName;
    649   var fileLocation = "";
    650   if (this.isNative()) {
    651     fileLocation = "native";
    652   } else {
    653     fileName = this.getScriptNameOrSourceURL();
    654     if (!fileName && this.isEval()) {
    655       fileLocation = this.getEvalOrigin();
    656       fileLocation += ", ";  // Expecting source position to follow.
    657     }
    658 
    659     if (fileName) {
    660       fileLocation += fileName;
    661     } else {
    662       // Source code does not originate from a file and is not native, but we
    663       // can still get the source position inside the source string, e.g. in
    664       // an eval string.
    665       fileLocation += "<anonymous>";
    666     }
    667     var lineNumber = this.getLineNumber();
    668     if (lineNumber != null) {
    669       fileLocation += ":" + lineNumber;
    670       var columnNumber = this.getColumnNumber();
    671       if (columnNumber) {
    672         fileLocation += ":" + columnNumber;
    673       }
    674     }
    675   }
    676 
    677   var line = "";
    678   var functionName = this.getFunctionName();
    679   var addSuffix = true;
    680   var isConstructor = this.isConstructor();
    681   var isMethodCall = !(this.isToplevel() || isConstructor);
    682   if (isMethodCall) {
    683     var typeName = GetTypeName(GET_PRIVATE(this, callSiteReceiverSymbol), true);
    684     var methodName = this.getMethodName();
    685     if (functionName) {
    686       if (typeName && %_Call(StringIndexOf, functionName, typeName) != 0) {
    687         line += typeName + ".";
    688       }
    689       line += functionName;
    690       if (methodName &&
    691           (%_Call(StringIndexOf, functionName, "." + methodName) !=
    692            functionName.length - methodName.length - 1)) {
    693         line += " [as " + methodName + "]";
    694       }
    695     } else {
    696       line += typeName + "." + (methodName || "<anonymous>");
    697     }
    698   } else if (isConstructor) {
    699     line += "new " + (functionName || "<anonymous>");
    700   } else if (functionName) {
    701     line += functionName;
    702   } else {
    703     line += fileLocation;
    704     addSuffix = false;
    705   }
    706   if (addSuffix) {
    707     line += " (" + fileLocation + ")";
    708   }
    709   return line;
    710 }
    711 
    712 utils.SetUpLockedPrototype(CallSite, ["receiver", "fun", "pos"], [
    713   "getThis", CallSiteGetThis,
    714   "getTypeName", CallSiteGetTypeName,
    715   "isToplevel", CallSiteIsToplevel,
    716   "isEval", CallSiteIsEval,
    717   "getEvalOrigin", CallSiteGetEvalOrigin,
    718   "getScriptNameOrSourceURL", CallSiteGetScriptNameOrSourceURL,
    719   "getFunction", CallSiteGetFunction,
    720   "getFunctionName", CallSiteGetFunctionName,
    721   "getMethodName", CallSiteGetMethodName,
    722   "getFileName", CallSiteGetFileName,
    723   "getLineNumber", CallSiteGetLineNumber,
    724   "getColumnNumber", CallSiteGetColumnNumber,
    725   "isNative", CallSiteIsNative,
    726   "getPosition", CallSiteGetPosition,
    727   "isConstructor", CallSiteIsConstructor,
    728   "toString", CallSiteToString
    729 ]);
    730 
    731 
    732 function FormatEvalOrigin(script) {
    733   var sourceURL = script.nameOrSourceURL();
    734   if (sourceURL) {
    735     return sourceURL;
    736   }
    737 
    738   var eval_origin = "eval at ";
    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 += " (" + FormatEvalOrigin(eval_from_script) + ")";
    750     } else {
    751       // eval script originated from "real" source.
    752       if (eval_from_script.name) {
    753         eval_origin += " (" + eval_from_script.name;
    754         var location = eval_from_script.locationFromPosition(
    755             script.eval_from_script_position, true);
    756         if (location) {
    757           eval_origin += ":" + (location.line + 1);
    758           eval_origin += ":" + (location.column + 1);
    759         }
    760         eval_origin += ")";
    761       } else {
    762         eval_origin += " (unknown source)";
    763       }
    764     }
    765   }
    766 
    767   return eval_origin;
    768 }
    769 
    770 
    771 function FormatErrorString(error) {
    772   try {
    773     return %_Call(ErrorToString, error);
    774   } catch (e) {
    775     try {
    776       return "<error: " + e + ">";
    777     } catch (ee) {
    778       return "<error>";
    779     }
    780   }
    781 }
    782 
    783 
    784 function GetStackFrames(raw_stack) {
    785   var frames = new InternalArray();
    786   var sloppy_frames = raw_stack[0];
    787   for (var i = 1; i < raw_stack.length; i += 4) {
    788     var recv = raw_stack[i];
    789     var fun = raw_stack[i + 1];
    790     var code = raw_stack[i + 2];
    791     var pc = raw_stack[i + 3];
    792     var pos = %_IsSmi(code) ? code : %FunctionGetPositionForOffset(code, pc);
    793     sloppy_frames--;
    794     frames.push(new CallSite(recv, fun, pos, (sloppy_frames < 0)));
    795   }
    796   return frames;
    797 }
    798 
    799 
    800 // Flag to prevent recursive call of Error.prepareStackTrace.
    801 var formatting_custom_stack_trace = false;
    802 
    803 
    804 function FormatStackTrace(obj, raw_stack) {
    805   var frames = GetStackFrames(raw_stack);
    806   if (IS_FUNCTION(GlobalError.prepareStackTrace) &&
    807       !formatting_custom_stack_trace) {
    808     var array = [];
    809     %MoveArrayContents(frames, array);
    810     formatting_custom_stack_trace = true;
    811     var stack_trace = UNDEFINED;
    812     try {
    813       stack_trace = GlobalError.prepareStackTrace(obj, array);
    814     } catch (e) {
    815       throw e;  // The custom formatting function threw.  Rethrow.
    816     } finally {
    817       formatting_custom_stack_trace = false;
    818     }
    819     return stack_trace;
    820   }
    821 
    822   var lines = new InternalArray();
    823   lines.push(FormatErrorString(obj));
    824   for (var i = 0; i < frames.length; i++) {
    825     var frame = frames[i];
    826     var line;
    827     try {
    828       line = frame.toString();
    829     } catch (e) {
    830       try {
    831         line = "<error: " + e + ">";
    832       } catch (ee) {
    833         // Any code that reaches this point is seriously nasty!
    834         line = "<error>";
    835       }
    836     }
    837     lines.push("    at " + line);
    838   }
    839   return %_Call(ArrayJoin, lines, "\n");
    840 }
    841 
    842 
    843 function GetTypeName(receiver, requireConstructor) {
    844   if (IS_NULL_OR_UNDEFINED(receiver)) return null;
    845   if (IS_PROXY(receiver)) return "Proxy";
    846 
    847   var constructor = %GetDataProperty(TO_OBJECT(receiver), "constructor");
    848   if (!IS_FUNCTION(constructor)) {
    849     return requireConstructor ? null : %_Call(NoSideEffectsToString, receiver);
    850   }
    851   return %FunctionGetName(constructor);
    852 }
    853 
    854 
    855 // Format the stack trace if not yet done, and return it.
    856 // Cache the formatted stack trace on the holder.
    857 var StackTraceGetter = function() {
    858   var formatted_stack_trace = UNDEFINED;
    859   var holder = this;
    860   while (holder) {
    861     var formatted_stack_trace =
    862       GET_PRIVATE(holder, formattedStackTraceSymbol);
    863     if (IS_UNDEFINED(formatted_stack_trace)) {
    864       // No formatted stack trace available.
    865       var stack_trace = GET_PRIVATE(holder, stackTraceSymbol);
    866       if (IS_UNDEFINED(stack_trace)) {
    867         // Neither formatted nor structured stack trace available.
    868         // Look further up the prototype chain.
    869         holder = %_GetPrototype(holder);
    870         continue;
    871       }
    872       formatted_stack_trace = FormatStackTrace(holder, stack_trace);
    873       SET_PRIVATE(holder, stackTraceSymbol, UNDEFINED);
    874       SET_PRIVATE(holder, formattedStackTraceSymbol, formatted_stack_trace);
    875     }
    876     return formatted_stack_trace;
    877   }
    878   return UNDEFINED;
    879 };
    880 
    881 
    882 // If the receiver equals the holder, set the formatted stack trace that the
    883 // getter returns.
    884 var StackTraceSetter = function(v) {
    885   if (IsErrorObject(this)) {
    886     SET_PRIVATE(this, stackTraceSymbol, UNDEFINED);
    887     SET_PRIVATE(this, formattedStackTraceSymbol, v);
    888   }
    889 };
    890 
    891 
    892 // Use a dummy function since we do not actually want to capture a stack trace
    893 // when constructing the initial Error prototytpes.
    894 var captureStackTrace = function() {};
    895 
    896 
    897 // Set up special error type constructors.
    898 function SetUpError(error_function) {
    899   %FunctionSetInstanceClassName(error_function, 'Error');
    900   var name = error_function.name;
    901   var prototype = new GlobalObject();
    902   if (name !== 'Error') {
    903     %InternalSetPrototype(error_function, GlobalError);
    904     %InternalSetPrototype(prototype, GlobalError.prototype);
    905   }
    906   %FunctionSetPrototype(error_function, prototype);
    907 
    908   %AddNamedProperty(error_function.prototype, 'name', name, DONT_ENUM);
    909   %AddNamedProperty(error_function.prototype, 'message', '', DONT_ENUM);
    910   %AddNamedProperty(
    911       error_function.prototype, 'constructor', error_function, DONT_ENUM);
    912 
    913   %SetCode(error_function, function(m) {
    914     if (IS_UNDEFINED(new.target)) return new error_function(m);
    915 
    916     try { captureStackTrace(this, error_function); } catch (e) { }
    917     // Define all the expected properties directly on the error
    918     // object. This avoids going through getters and setters defined
    919     // on prototype objects.
    920     if (!IS_UNDEFINED(m)) {
    921       %AddNamedProperty(this, 'message', TO_STRING(m), DONT_ENUM);
    922     }
    923   });
    924 
    925   %SetNativeFlag(error_function);
    926   return error_function;
    927 };
    928 
    929 GlobalError = SetUpError(global.Error);
    930 GlobalEvalError = SetUpError(global.EvalError);
    931 GlobalRangeError = SetUpError(global.RangeError);
    932 GlobalReferenceError = SetUpError(global.ReferenceError);
    933 GlobalSyntaxError = SetUpError(global.SyntaxError);
    934 GlobalTypeError = SetUpError(global.TypeError);
    935 GlobalURIError = SetUpError(global.URIError);
    936 
    937 utils.InstallFunctions(GlobalError.prototype, DONT_ENUM,
    938                        ['toString', ErrorToString]);
    939 
    940 function ErrorToString() {
    941   if (!IS_RECEIVER(this)) {
    942     throw MakeTypeError(kCalledOnNonObject, "Error.prototype.toString");
    943   }
    944 
    945   var name = this.name;
    946   name = IS_UNDEFINED(name) ? "Error" : TO_STRING(name);
    947 
    948   var message = this.message;
    949   message = IS_UNDEFINED(message) ? "" : TO_STRING(message);
    950 
    951   if (name == "") return message;
    952   if (message == "") return name;
    953   return `${name}: ${message}`
    954 }
    955 
    956 function MakeError(type, arg0, arg1, arg2) {
    957   return MakeGenericError(GlobalError, type, arg0, arg1, arg2);
    958 }
    959 
    960 function MakeRangeError(type, arg0, arg1, arg2) {
    961   return MakeGenericError(GlobalRangeError, type, arg0, arg1, arg2);
    962 }
    963 
    964 function MakeSyntaxError(type, arg0, arg1, arg2) {
    965   return MakeGenericError(GlobalSyntaxError, type, arg0, arg1, arg2);
    966 }
    967 
    968 function MakeTypeError(type, arg0, arg1, arg2) {
    969   return MakeGenericError(GlobalTypeError, type, arg0, arg1, arg2);
    970 }
    971 
    972 function MakeURIError() {
    973   return MakeGenericError(GlobalURIError, kURIMalformed);
    974 }
    975 
    976 // Boilerplate for exceptions for stack overflows. Used from
    977 // Isolate::StackOverflow().
    978 var StackOverflowBoilerplate = MakeRangeError(kStackOverflow);
    979 utils.InstallGetterSetter(StackOverflowBoilerplate, 'stack',
    980                           StackTraceGetter, StackTraceSetter)
    981 
    982 // Define actual captureStackTrace function after everything has been set up.
    983 captureStackTrace = function captureStackTrace(obj, cons_opt) {
    984   // Define accessors first, as this may fail and throw.
    985   ObjectDefineProperty(obj, 'stack', { get: StackTraceGetter,
    986                                        set: StackTraceSetter,
    987                                        configurable: true });
    988   %CollectStackTrace(obj, cons_opt ? cons_opt : captureStackTrace);
    989 };
    990 
    991 GlobalError.captureStackTrace = captureStackTrace;
    992 
    993 %InstallToContext([
    994   "get_stack_trace_line_fun", GetStackTraceLine,
    995   "make_error_function", MakeGenericError,
    996   "make_range_error", MakeRangeError,
    997   "make_type_error", MakeTypeError,
    998   "message_get_column_number", GetColumnNumber,
    999   "message_get_line_number", GetLineNumber,
   1000   "message_get_source_line", GetSourceLine,
   1001   "no_side_effects_to_string_fun", NoSideEffectsToString,
   1002   "stack_overflow_boilerplate", StackOverflowBoilerplate,
   1003 ]);
   1004 
   1005 utils.Export(function(to) {
   1006   to.ErrorToString = ErrorToString;
   1007   to.MakeError = MakeError;
   1008   to.MakeRangeError = MakeRangeError;
   1009   to.MakeSyntaxError = MakeSyntaxError;
   1010   to.MakeTypeError = MakeTypeError;
   1011   to.MakeURIError = MakeURIError;
   1012 });
   1013 
   1014 });
   1015