[runtime] Replace %to_string_fun with %_ToString.
[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 Uint16x8ToString;
53 var Uint32x4ToString;
54 var Uint8x16ToString;
55
56 utils.Import(function(from) {
57   ArrayJoin = from.ArrayJoin;
58   Bool16x8ToString = from.Bool16x8ToString;
59   Bool32x4ToString = from.Bool32x4ToString;
60   Bool8x16ToString = from.Bool8x16ToString;
61   Float32x4ToString = from.Float32x4ToString;
62   FunctionSourceString = from.FunctionSourceString;
63   Int16x8ToString = from.Int16x8ToString;
64   Int32x4ToString = from.Int32x4ToString;
65   Int8x16ToString = from.Int8x16ToString;
66   ObjectDefineProperty = from.ObjectDefineProperty;
67   ObjectToString = from.ObjectToString;
68   StringCharAt = from.StringCharAt;
69   StringIndexOf = from.StringIndexOf;
70   StringSubstring = from.StringSubstring;
71   SymbolToString = from.SymbolToString;
72   Uint16x8ToString = from.Uint16x8ToString;
73   Uint32x4ToString = from.Uint32x4ToString;
74   Uint8x16ToString = from.Uint8x16ToString;
75 });
76
77 // -------------------------------------------------------------------
78
79 var GlobalError;
80 var GlobalTypeError;
81 var GlobalRangeError;
82 var GlobalURIError;
83 var GlobalSyntaxError;
84 var GlobalReferenceError;
85 var GlobalEvalError;
86
87
88 function NoSideEffectsObjectToString() {
89   if (IS_UNDEFINED(this)) return "[object Undefined]";
90   if (IS_NULL(this)) return "[object Null]";
91   return "[object " + %_ClassOf(TO_OBJECT(this)) + "]";
92 }
93
94
95 function NoSideEffectToString(obj) {
96   if (IS_STRING(obj)) return obj;
97   if (IS_NUMBER(obj)) return %_NumberToString(obj);
98   if (IS_BOOLEAN(obj)) return obj ? 'true' : 'false';
99   if (IS_UNDEFINED(obj)) return 'undefined';
100   if (IS_NULL(obj)) return 'null';
101   if (IS_FUNCTION(obj)) {
102     var str = %_CallFunction(obj, obj, FunctionSourceString);
103     if (str.length > 128) {
104       str = %_SubString(str, 0, 111) + "...<omitted>..." +
105             %_SubString(str, str.length - 2, str.length);
106     }
107     return str;
108   }
109   if (IS_SYMBOL(obj)) return %_CallFunction(obj, SymbolToString);
110   if (IS_SIMD_VALUE(obj)) {
111     switch (typeof(obj)) {
112       case 'float32x4': return %_CallFunction(obj, Float32x4ToString);
113       case 'int32x4':   return %_CallFunction(obj, Int32x4ToString);
114       case 'int16x8':   return %_CallFunction(obj, Int16x8ToString);
115       case 'int8x16':   return %_CallFunction(obj, Int8x16ToString);
116       case 'uint32x4':   return %_CallFunction(obj, Uint32x4ToString);
117       case 'uint16x8':   return %_CallFunction(obj, Uint16x8ToString);
118       case 'uint8x16':   return %_CallFunction(obj, Uint8x16ToString);
119       case 'bool32x4':  return %_CallFunction(obj, Bool32x4ToString);
120       case 'bool16x8':  return %_CallFunction(obj, Bool16x8ToString);
121       case 'bool8x16':  return %_CallFunction(obj, Bool8x16ToString);
122     }
123   }
124   if (IS_OBJECT(obj)
125       && %GetDataProperty(obj, "toString") === ObjectToString) {
126     var constructor = %GetDataProperty(obj, "constructor");
127     if (typeof constructor == "function") {
128       var constructorName = constructor.name;
129       if (IS_STRING(constructorName) && constructorName !== "") {
130         return "#<" + constructorName + ">";
131       }
132     }
133   }
134   if (CanBeSafelyTreatedAsAnErrorObject(obj)) {
135     return %_CallFunction(obj, ErrorToString);
136   }
137
138   return %_CallFunction(obj, NoSideEffectsObjectToString);
139 }
140
141 // To determine whether we can safely stringify an object using ErrorToString
142 // without the risk of side-effects, we need to check whether the object is
143 // either an instance of a native error type (via '%_ClassOf'), or has Error
144 // in its prototype chain and hasn't overwritten 'toString' with something
145 // strange and unusual.
146 function CanBeSafelyTreatedAsAnErrorObject(obj) {
147   switch (%_ClassOf(obj)) {
148     case 'Error':
149     case 'EvalError':
150     case 'RangeError':
151     case 'ReferenceError':
152     case 'SyntaxError':
153     case 'TypeError':
154     case 'URIError':
155       return true;
156   }
157
158   var objToString = %GetDataProperty(obj, "toString");
159   return obj instanceof GlobalError && objToString === ErrorToString;
160 }
161
162
163 // When formatting internally created error messages, do not
164 // invoke overwritten error toString methods but explicitly use
165 // the error to string method. This is to avoid leaking error
166 // objects between script tags in a browser setting.
167 function ToStringCheckErrorObject(obj) {
168   if (CanBeSafelyTreatedAsAnErrorObject(obj)) {
169     return %_CallFunction(obj, ErrorToString);
170   } else {
171     return TO_STRING(obj);
172   }
173 }
174
175
176 function ToDetailString(obj) {
177   if (obj != null && IS_OBJECT(obj) && obj.toString === ObjectToString) {
178     var constructor = obj.constructor;
179     if (typeof constructor == "function") {
180       var constructorName = constructor.name;
181       if (IS_STRING(constructorName) && constructorName !== "") {
182         return "#<" + constructorName + ">";
183       }
184     }
185   }
186   return ToStringCheckErrorObject(obj);
187 }
188
189
190 function MakeGenericError(constructor, type, arg0, arg1, arg2) {
191   var error = new constructor(FormatMessage(type, arg0, arg1, arg2));
192   error[internalErrorSymbol] = true;
193   return error;
194 }
195
196
197 /**
198  * Set up the Script function and constructor.
199  */
200 %FunctionSetInstanceClassName(Script, 'Script');
201 %AddNamedProperty(Script.prototype, 'constructor', Script,
202                   DONT_ENUM | DONT_DELETE | READ_ONLY);
203 %SetCode(Script, function(x) {
204   // Script objects can only be created by the VM.
205   throw MakeError(kUnsupported);
206 });
207
208
209 // Helper functions; called from the runtime system.
210 function FormatMessage(type, arg0, arg1, arg2) {
211   var arg0 = NoSideEffectToString(arg0);
212   var arg1 = NoSideEffectToString(arg1);
213   var arg2 = NoSideEffectToString(arg2);
214   try {
215     return %FormatMessageString(type, arg0, arg1, arg2);
216   } catch (e) {
217     return "<error>";
218   }
219 }
220
221
222 function GetLineNumber(message) {
223   var start_position = %MessageGetStartPosition(message);
224   if (start_position == -1) return kNoLineNumberInfo;
225   var script = %MessageGetScript(message);
226   var location = script.locationFromPosition(start_position, true);
227   if (location == null) return kNoLineNumberInfo;
228   return location.line + 1;
229 }
230
231
232 //Returns the offset of the given position within the containing line.
233 function GetColumnNumber(message) {
234   var script = %MessageGetScript(message);
235   var start_position = %MessageGetStartPosition(message);
236   var location = script.locationFromPosition(start_position, true);
237   if (location == null) return -1;
238   return location.column;
239 }
240
241
242 // Returns the source code line containing the given source
243 // position, or the empty string if the position is invalid.
244 function GetSourceLine(message) {
245   var script = %MessageGetScript(message);
246   var start_position = %MessageGetStartPosition(message);
247   var location = script.locationFromPosition(start_position, true);
248   if (location == null) return "";
249   return location.sourceText();
250 }
251
252
253 /**
254  * Find a line number given a specific source position.
255  * @param {number} position The source position.
256  * @return {number} 0 if input too small, -1 if input too large,
257        else the line number.
258  */
259 function ScriptLineFromPosition(position) {
260   var lower = 0;
261   var upper = this.lineCount() - 1;
262   var line_ends = this.line_ends;
263
264   // We'll never find invalid positions so bail right away.
265   if (position > line_ends[upper]) {
266     return -1;
267   }
268
269   // This means we don't have to safe-guard indexing line_ends[i - 1].
270   if (position <= line_ends[0]) {
271     return 0;
272   }
273
274   // Binary search to find line # from position range.
275   while (upper >= 1) {
276     var i = (lower + upper) >> 1;
277
278     if (position > line_ends[i]) {
279       lower = i + 1;
280     } else if (position <= line_ends[i - 1]) {
281       upper = i - 1;
282     } else {
283       return i;
284     }
285   }
286
287   return -1;
288 }
289
290 /**
291  * Get information on a specific source position.
292  * @param {number} position The source position
293  * @param {boolean} include_resource_offset Set to true to have the resource
294  *     offset added to the location
295  * @return {SourceLocation}
296  *     If line is negative or not in the source null is returned.
297  */
298 function ScriptLocationFromPosition(position,
299                                     include_resource_offset) {
300   var line = this.lineFromPosition(position);
301   if (line == -1) return null;
302
303   // Determine start, end and column.
304   var line_ends = this.line_ends;
305   var start = line == 0 ? 0 : line_ends[line - 1] + 1;
306   var end = line_ends[line];
307   if (end > 0 && %_CallFunction(this.source, end - 1, StringCharAt) == '\r') {
308     end--;
309   }
310   var column = position - start;
311
312   // Adjust according to the offset within the resource.
313   if (include_resource_offset) {
314     line += this.line_offset;
315     if (line == this.line_offset) {
316       column += this.column_offset;
317     }
318   }
319
320   return new SourceLocation(this, position, line, column, start, end);
321 }
322
323
324 /**
325  * Get information on a specific source line and column possibly offset by a
326  * fixed source position. This function is used to find a source position from
327  * a line and column position. The fixed source position offset is typically
328  * used to find a source position in a function based on a line and column in
329  * the source for the function alone. The offset passed will then be the
330  * start position of the source for the function within the full script source.
331  * @param {number} opt_line The line within the source. Default value is 0
332  * @param {number} opt_column The column in within the line. Default value is 0
333  * @param {number} opt_offset_position The offset from the begining of the
334  *     source from where the line and column calculation starts.
335  *     Default value is 0
336  * @return {SourceLocation}
337  *     If line is negative or not in the source null is returned.
338  */
339 function ScriptLocationFromLine(opt_line, opt_column, opt_offset_position) {
340   // Default is the first line in the script. Lines in the script is relative
341   // to the offset within the resource.
342   var line = 0;
343   if (!IS_UNDEFINED(opt_line)) {
344     line = opt_line - this.line_offset;
345   }
346
347   // Default is first column. If on the first line add the offset within the
348   // resource.
349   var column = opt_column || 0;
350   if (line == 0) {
351     column -= this.column_offset;
352   }
353
354   var offset_position = opt_offset_position || 0;
355   if (line < 0 || column < 0 || offset_position < 0) return null;
356   if (line == 0) {
357     return this.locationFromPosition(offset_position + column, false);
358   } else {
359     // Find the line where the offset position is located.
360     var offset_line = this.lineFromPosition(offset_position);
361
362     if (offset_line == -1 || offset_line + line >= this.lineCount()) {
363       return null;
364     }
365
366     return this.locationFromPosition(
367         this.line_ends[offset_line + line - 1] + 1 + column);  // line > 0 here.
368   }
369 }
370
371
372 /**
373  * Get a slice of source code from the script. The boundaries for the slice is
374  * specified in lines.
375  * @param {number} opt_from_line The first line (zero bound) in the slice.
376  *     Default is 0
377  * @param {number} opt_to_column The last line (zero bound) in the slice (non
378  *     inclusive). Default is the number of lines in the script
379  * @return {SourceSlice} The source slice or null of the parameters where
380  *     invalid
381  */
382 function ScriptSourceSlice(opt_from_line, opt_to_line) {
383   var from_line = IS_UNDEFINED(opt_from_line) ? this.line_offset
384                                               : opt_from_line;
385   var to_line = IS_UNDEFINED(opt_to_line) ? this.line_offset + this.lineCount()
386                                           : opt_to_line;
387
388   // Adjust according to the offset within the resource.
389   from_line -= this.line_offset;
390   to_line -= this.line_offset;
391   if (from_line < 0) from_line = 0;
392   if (to_line > this.lineCount()) to_line = this.lineCount();
393
394   // Check parameters.
395   if (from_line >= this.lineCount() ||
396       to_line < 0 ||
397       from_line > to_line) {
398     return null;
399   }
400
401   var line_ends = this.line_ends;
402   var from_position = from_line == 0 ? 0 : line_ends[from_line - 1] + 1;
403   var to_position = to_line == 0 ? 0 : line_ends[to_line - 1] + 1;
404
405   // Return a source slice with line numbers re-adjusted to the resource.
406   return new SourceSlice(this,
407                          from_line + this.line_offset,
408                          to_line + this.line_offset,
409                           from_position, to_position);
410 }
411
412
413 function ScriptSourceLine(opt_line) {
414   // Default is the first line in the script. Lines in the script are relative
415   // to the offset within the resource.
416   var line = 0;
417   if (!IS_UNDEFINED(opt_line)) {
418     line = opt_line - this.line_offset;
419   }
420
421   // Check parameter.
422   if (line < 0 || this.lineCount() <= line) {
423     return null;
424   }
425
426   // Return the source line.
427   var line_ends = this.line_ends;
428   var start = line == 0 ? 0 : line_ends[line - 1] + 1;
429   var end = line_ends[line];
430   return %_CallFunction(this.source, start, end, StringSubstring);
431 }
432
433
434 /**
435  * Returns the number of source lines.
436  * @return {number}
437  *     Number of source lines.
438  */
439 function ScriptLineCount() {
440   // Return number of source lines.
441   return this.line_ends.length;
442 }
443
444
445 /**
446  * Returns the position of the nth line end.
447  * @return {number}
448  *     Zero-based position of the nth line end in the script.
449  */
450 function ScriptLineEnd(n) {
451   return this.line_ends[n];
452 }
453
454
455 /**
456  * If sourceURL comment is available returns sourceURL comment contents.
457  * Otherwise, script name is returned. See
458  * http://fbug.googlecode.com/svn/branches/firebug1.1/docs/ReleaseNotes_1.1.txt
459  * and Source Map Revision 3 proposal for details on using //# sourceURL and
460  * deprecated //@ sourceURL comment to identify scripts that don't have name.
461  *
462  * @return {?string} script name if present, value for //# sourceURL or
463  * deprecated //@ sourceURL comment otherwise.
464  */
465 function ScriptNameOrSourceURL() {
466   if (this.source_url) return this.source_url;
467   return this.name;
468 }
469
470
471 utils.SetUpLockedPrototype(Script, [
472     "source",
473     "name",
474     "source_url",
475     "source_mapping_url",
476     "line_ends",
477     "line_offset",
478     "column_offset"
479   ], [
480     "lineFromPosition", ScriptLineFromPosition,
481     "locationFromPosition", ScriptLocationFromPosition,
482     "locationFromLine", ScriptLocationFromLine,
483     "sourceSlice", ScriptSourceSlice,
484     "sourceLine", ScriptSourceLine,
485     "lineCount", ScriptLineCount,
486     "nameOrSourceURL", ScriptNameOrSourceURL,
487     "lineEnd", ScriptLineEnd
488   ]
489 );
490
491
492 /**
493  * Class for source location. A source location is a position within some
494  * source with the following properties:
495  *   script   : script object for the source
496  *   line     : source line number
497  *   column   : source column within the line
498  *   position : position within the source
499  *   start    : position of start of source context (inclusive)
500  *   end      : position of end of source context (not inclusive)
501  * Source text for the source context is the character interval
502  * [start, end[. In most cases end will point to a newline character.
503  * It might point just past the final position of the source if the last
504  * source line does not end with a newline character.
505  * @param {Script} script The Script object for which this is a location
506  * @param {number} position Source position for the location
507  * @param {number} line The line number for the location
508  * @param {number} column The column within the line for the location
509  * @param {number} start Source position for start of source context
510  * @param {number} end Source position for end of source context
511  * @constructor
512  */
513 function SourceLocation(script, position, line, column, start, end) {
514   this.script = script;
515   this.position = position;
516   this.line = line;
517   this.column = column;
518   this.start = start;
519   this.end = end;
520 }
521
522
523 /**
524  * Get the source text for a SourceLocation
525  * @return {String}
526  *     Source text for this location.
527  */
528 function SourceLocationSourceText() {
529   return %_CallFunction(this.script.source,
530                         this.start,
531                         this.end,
532                         StringSubstring);
533 }
534
535
536 utils.SetUpLockedPrototype(SourceLocation,
537   ["script", "position", "line", "column", "start", "end"],
538   ["sourceText", SourceLocationSourceText]
539 );
540
541
542 /**
543  * Class for a source slice. A source slice is a part of a script source with
544  * the following properties:
545  *   script        : script object for the source
546  *   from_line     : line number for the first line in the slice
547  *   to_line       : source line number for the last line in the slice
548  *   from_position : position of the first character in the slice
549  *   to_position   : position of the last character in the slice
550  * The to_line and to_position are not included in the slice, that is the lines
551  * in the slice are [from_line, to_line[. Likewise the characters in the slice
552  * are [from_position, to_position[.
553  * @param {Script} script The Script object for the source slice
554  * @param {number} from_line
555  * @param {number} to_line
556  * @param {number} from_position
557  * @param {number} to_position
558  * @constructor
559  */
560 function SourceSlice(script, from_line, to_line, from_position, to_position) {
561   this.script = script;
562   this.from_line = from_line;
563   this.to_line = to_line;
564   this.from_position = from_position;
565   this.to_position = to_position;
566 }
567
568 /**
569  * Get the source text for a SourceSlice
570  * @return {String} Source text for this slice. The last line will include
571  *     the line terminating characters (if any)
572  */
573 function SourceSliceSourceText() {
574   return %_CallFunction(this.script.source,
575                         this.from_position,
576                         this.to_position,
577                         StringSubstring);
578 }
579
580 utils.SetUpLockedPrototype(SourceSlice,
581   ["script", "from_line", "to_line", "from_position", "to_position"],
582   ["sourceText", SourceSliceSourceText]
583 );
584
585
586 function GetStackTraceLine(recv, fun, pos, isGlobal) {
587   return new CallSite(recv, fun, pos, false).toString();
588 }
589
590 // ----------------------------------------------------------------------------
591 // Error implementation
592
593 function CallSite(receiver, fun, pos, strict_mode) {
594   SET_PRIVATE(this, callSiteReceiverSymbol, receiver);
595   SET_PRIVATE(this, callSiteFunctionSymbol, fun);
596   SET_PRIVATE(this, callSitePositionSymbol, pos);
597   SET_PRIVATE(this, callSiteStrictSymbol, strict_mode);
598 }
599
600 function CallSiteGetThis() {
601   return GET_PRIVATE(this, callSiteStrictSymbol)
602       ? UNDEFINED : GET_PRIVATE(this, callSiteReceiverSymbol);
603 }
604
605 function CallSiteGetFunction() {
606   return GET_PRIVATE(this, callSiteStrictSymbol)
607       ? UNDEFINED : GET_PRIVATE(this, callSiteFunctionSymbol);
608 }
609
610 function CallSiteGetPosition() {
611   return GET_PRIVATE(this, callSitePositionSymbol);
612 }
613
614 function CallSiteGetTypeName() {
615   return GetTypeName(GET_PRIVATE(this, callSiteReceiverSymbol), false);
616 }
617
618 function CallSiteIsToplevel() {
619   return %CallSiteIsToplevelRT(this);
620 }
621
622 function CallSiteIsEval() {
623   return %CallSiteIsEvalRT(this);
624 }
625
626 function CallSiteGetEvalOrigin() {
627   var script = %FunctionGetScript(GET_PRIVATE(this, callSiteFunctionSymbol));
628   return FormatEvalOrigin(script);
629 }
630
631 function CallSiteGetScriptNameOrSourceURL() {
632   return %CallSiteGetScriptNameOrSourceUrlRT(this);
633 }
634
635 function CallSiteGetFunctionName() {
636   // See if the function knows its own name
637   return %CallSiteGetFunctionNameRT(this);
638 }
639
640 function CallSiteGetMethodName() {
641   // See if we can find a unique property on the receiver that holds
642   // this function.
643   return %CallSiteGetMethodNameRT(this);
644 }
645
646 function CallSiteGetFileName() {
647   return %CallSiteGetFileNameRT(this);
648 }
649
650 function CallSiteGetLineNumber() {
651   return %CallSiteGetLineNumberRT(this);
652 }
653
654 function CallSiteGetColumnNumber() {
655   return %CallSiteGetColumnNumberRT(this);
656 }
657
658 function CallSiteIsNative() {
659   return %CallSiteIsNativeRT(this);
660 }
661
662 function CallSiteIsConstructor() {
663   return %CallSiteIsConstructorRT(this);
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, callSiteReceiverSymbol), 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
879 // Format the stack trace if not yet done, and return it.
880 // Cache the formatted stack trace on the holder.
881 var StackTraceGetter = function() {
882   var formatted_stack_trace = UNDEFINED;
883   var holder = this;
884   while (holder) {
885     var formatted_stack_trace =
886       GET_PRIVATE(holder, formattedStackTraceSymbol);
887     if (IS_UNDEFINED(formatted_stack_trace)) {
888       // No formatted stack trace available.
889       var stack_trace = GET_PRIVATE(holder, stackTraceSymbol);
890       if (IS_UNDEFINED(stack_trace)) {
891         // Neither formatted nor structured stack trace available.
892         // Look further up the prototype chain.
893         holder = %_GetPrototype(holder);
894         continue;
895       }
896       formatted_stack_trace = FormatStackTrace(holder, stack_trace);
897       SET_PRIVATE(holder, stackTraceSymbol, UNDEFINED);
898       SET_PRIVATE(holder, formattedStackTraceSymbol, formatted_stack_trace);
899     }
900     return formatted_stack_trace;
901   }
902   return UNDEFINED;
903 };
904
905
906 // If the receiver equals the holder, set the formatted stack trace that the
907 // getter returns.
908 var StackTraceSetter = function(v) {
909   if (HAS_PRIVATE(this, stackTraceSymbol)) {
910     SET_PRIVATE(this, stackTraceSymbol, UNDEFINED);
911     SET_PRIVATE(this, formattedStackTraceSymbol, v);
912   }
913 };
914
915
916 // Use a dummy function since we do not actually want to capture a stack trace
917 // when constructing the initial Error prototytpes.
918 var captureStackTrace = function() {};
919
920
921 // Define special error type constructors.
922 function DefineError(global, f) {
923   // Store the error function in both the global object
924   // and the runtime object. The function is fetched
925   // from the runtime object when throwing errors from
926   // within the runtime system to avoid strange side
927   // effects when overwriting the error functions from
928   // user code.
929   var name = f.name;
930   %AddNamedProperty(global, name, f, DONT_ENUM);
931   // Configure the error function.
932   if (name == 'Error') {
933     // The prototype of the Error object must itself be an error.
934     // However, it can't be an instance of the Error object because
935     // it hasn't been properly configured yet.  Instead we create a
936     // special not-a-true-error-but-close-enough object.
937     var ErrorPrototype = function() {};
938     %FunctionSetPrototype(ErrorPrototype, GlobalObject.prototype);
939     %FunctionSetInstanceClassName(ErrorPrototype, 'Error');
940     %FunctionSetPrototype(f, new ErrorPrototype());
941   } else {
942     %FunctionSetPrototype(f, new GlobalError());
943     %InternalSetPrototype(f, GlobalError);
944   }
945   %FunctionSetInstanceClassName(f, 'Error');
946   %AddNamedProperty(f.prototype, 'constructor', f, DONT_ENUM);
947   %AddNamedProperty(f.prototype, 'name', name, DONT_ENUM);
948   %SetCode(f, function(m) {
949     if (%_IsConstructCall()) {
950       try { captureStackTrace(this, f); } catch (e) { }
951       // Define all the expected properties directly on the error
952       // object. This avoids going through getters and setters defined
953       // on prototype objects.
954       if (!IS_UNDEFINED(m)) {
955         %AddNamedProperty(this, 'message', TO_STRING(m), DONT_ENUM);
956       }
957     } else {
958       return new f(m);
959     }
960   });
961   %SetNativeFlag(f);
962   return f;
963 };
964
965 GlobalError = DefineError(global, function Error() { });
966 GlobalEvalError = DefineError(global, function EvalError() { });
967 GlobalRangeError = DefineError(global, function RangeError() { });
968 GlobalReferenceError = DefineError(global, function ReferenceError() { });
969 GlobalSyntaxError = DefineError(global, function SyntaxError() { });
970 GlobalTypeError = DefineError(global, function TypeError() { });
971 GlobalURIError = DefineError(global, function URIError() { });
972
973 %AddNamedProperty(GlobalError.prototype, 'message', '', DONT_ENUM);
974
975 function ErrorToString() {
976   if (!IS_SPEC_OBJECT(this)) {
977     throw MakeTypeError(kCalledOnNonObject, "Error.prototype.toString");
978   }
979
980   return %ErrorToStringRT(this);
981 }
982
983 utils.InstallFunctions(GlobalError.prototype, DONT_ENUM,
984                        ['toString', ErrorToString]);
985
986 $errorToString = ErrorToString;
987
988 MakeError = function(type, arg0, arg1, arg2) {
989   return MakeGenericError(GlobalError, type, arg0, arg1, arg2);
990 }
991
992 MakeRangeError = function(type, arg0, arg1, arg2) {
993   return MakeGenericError(GlobalRangeError, type, arg0, arg1, arg2);
994 }
995
996 MakeSyntaxError = function(type, arg0, arg1, arg2) {
997   return MakeGenericError(GlobalSyntaxError, type, arg0, arg1, arg2);
998 }
999
1000 MakeTypeError = function(type, arg0, arg1, arg2) {
1001   return MakeGenericError(GlobalTypeError, type, arg0, arg1, arg2);
1002 }
1003
1004 MakeURIError = function() {
1005   return MakeGenericError(GlobalURIError, kURIMalformed);
1006 }
1007
1008 // Boilerplate for exceptions for stack overflows. Used from
1009 // Isolate::StackOverflow().
1010 var StackOverflowBoilerplate = MakeRangeError(kStackOverflow);
1011 %DefineAccessorPropertyUnchecked(StackOverflowBoilerplate, 'stack',
1012                                  StackTraceGetter, StackTraceSetter,
1013                                  DONT_ENUM);
1014
1015 // Define actual captureStackTrace function after everything has been set up.
1016 captureStackTrace = function captureStackTrace(obj, cons_opt) {
1017   // Define accessors first, as this may fail and throw.
1018   ObjectDefineProperty(obj, 'stack', { get: StackTraceGetter,
1019                                        set: StackTraceSetter,
1020                                        configurable: true });
1021   %CollectStackTrace(obj, cons_opt ? cons_opt : captureStackTrace);
1022 };
1023
1024 GlobalError.captureStackTrace = captureStackTrace;
1025
1026 %InstallToContext([
1027   "error_function", GlobalError,
1028   "eval_error_function", GlobalEvalError,
1029   "get_stack_trace_line_fun", GetStackTraceLine,
1030   "make_error_function", MakeGenericError,
1031   "make_range_error", MakeRangeError,
1032   "make_type_error", MakeTypeError,
1033   "message_get_column_number", GetColumnNumber,
1034   "message_get_line_number", GetLineNumber,
1035   "message_get_source_line", GetSourceLine,
1036   "no_side_effect_to_string_fun", NoSideEffectToString,
1037   "range_error_function", GlobalRangeError,
1038   "reference_error_function", GlobalReferenceError,
1039   "stack_overflow_boilerplate", StackOverflowBoilerplate,
1040   "syntax_error_function", GlobalSyntaxError,
1041   "to_detail_string_fun", ToDetailString,
1042   "type_error_function", GlobalTypeError,
1043   "uri_error_function", GlobalURIError,
1044 ]);
1045
1046 });