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