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