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