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