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.
5 // -------------------------------------------------------------------
8 var $internalErrorSymbol;
13 var MakeReferenceError;
18 (function(global, utils) {
20 %CheckIsBootstrapping();
22 // -------------------------------------------------------------------
25 var GlobalObject = global.Object;
26 var InternalArray = utils.InternalArray;
27 var ObjectDefineProperty = utils.ObjectDefineProperty;
35 var Float32x4ToString;
44 utils.Import(function(from) {
45 ArrayJoin = from.ArrayJoin;
46 ObjectToString = from.ObjectToString;
47 StringCharAt = from.StringCharAt;
48 StringIndexOf = from.StringIndexOf;
49 StringSubstring = from.StringSubstring;
50 Float32x4ToString = from.Float32x4ToString;
51 Int32x4ToString = from.Int32x4ToString;
52 Bool32x4ToString = from.Bool32x4ToString;
53 Int16x8ToString = from.Int16x8ToString;
54 Bool16x8ToString = from.Bool16x8ToString;
55 Int8x16ToString = from.Int8x16ToString;
56 Bool8x16ToString = from.Bool8x16ToString;
59 // -------------------------------------------------------------------
65 var GlobalSyntaxError;
66 var GlobalReferenceError;
70 function NoSideEffectsObjectToString() {
71 if (IS_UNDEFINED(this)) return "[object Undefined]";
72 if (IS_NULL(this)) return "[object Null]";
73 return "[object " + %_ClassOf(TO_OBJECT(this)) + "]";
77 function NoSideEffectToString(obj) {
78 if (IS_STRING(obj)) return obj;
79 if (IS_NUMBER(obj)) return %_NumberToString(obj);
80 if (IS_BOOLEAN(obj)) return obj ? 'true' : 'false';
81 if (IS_UNDEFINED(obj)) return 'undefined';
82 if (IS_NULL(obj)) return 'null';
83 if (IS_FUNCTION(obj)) {
84 var str = %_CallFunction(obj, obj, $functionSourceString);
85 if (str.length > 128) {
86 str = %_SubString(str, 0, 111) + "...<omitted>..." +
87 %_SubString(str, str.length - 2, str.length);
91 if (IS_SYMBOL(obj)) return %_CallFunction(obj, $symbolToString);
92 if (IS_SIMD_VALUE(obj)) {
93 switch (typeof(obj)) {
94 case 'float32x4': return %_CallFunction(obj, Float32x4ToString);
95 case 'int32x4': return %_CallFunction(obj, Int32x4ToString);
96 case 'bool32x4': return %_CallFunction(obj, Bool32x4ToString);
97 case 'int16x8': return %_CallFunction(obj, Int16x8ToString);
98 case 'bool16x8': return %_CallFunction(obj, Bool16x8ToString);
99 case 'int16x8': return %_CallFunction(obj, Int16x8ToString);
100 case 'bool16x8': return %_CallFunction(obj, Bool16x8ToString);
104 && %GetDataProperty(obj, "toString") === ObjectToString) {
105 var constructor = %GetDataProperty(obj, "constructor");
106 if (typeof constructor == "function") {
107 var constructorName = constructor.name;
108 if (IS_STRING(constructorName) && constructorName !== "") {
109 return "#<" + constructorName + ">";
113 if (CanBeSafelyTreatedAsAnErrorObject(obj)) {
114 return %_CallFunction(obj, ErrorToString);
117 return %_CallFunction(obj, NoSideEffectsObjectToString);
120 // To determine whether we can safely stringify an object using ErrorToString
121 // without the risk of side-effects, we need to check whether the object is
122 // either an instance of a native error type (via '%_ClassOf'), or has Error
123 // in its prototype chain and hasn't overwritten 'toString' with something
124 // strange and unusual.
125 function CanBeSafelyTreatedAsAnErrorObject(obj) {
126 switch (%_ClassOf(obj)) {
130 case 'ReferenceError':
137 var objToString = %GetDataProperty(obj, "toString");
138 return obj instanceof GlobalError && objToString === ErrorToString;
142 // When formatting internally created error messages, do not
143 // invoke overwritten error toString methods but explicitly use
144 // the error to string method. This is to avoid leaking error
145 // objects between script tags in a browser setting.
146 function ToStringCheckErrorObject(obj) {
147 if (CanBeSafelyTreatedAsAnErrorObject(obj)) {
148 return %_CallFunction(obj, ErrorToString);
150 return $toString(obj);
155 function ToDetailString(obj) {
156 if (obj != null && IS_OBJECT(obj) && obj.toString === ObjectToString) {
157 var constructor = obj.constructor;
158 if (typeof constructor == "function") {
159 var constructorName = constructor.name;
160 if (IS_STRING(constructorName) && constructorName !== "") {
161 return "#<" + constructorName + ">";
165 return ToStringCheckErrorObject(obj);
169 function MakeGenericError(constructor, type, arg0, arg1, arg2) {
170 var error = new constructor(FormatMessage(type, arg0, arg1, arg2));
171 error[$internalErrorSymbol] = true;
177 * Set up the Script function and constructor.
179 %FunctionSetInstanceClassName(Script, 'Script');
180 %AddNamedProperty(Script.prototype, 'constructor', Script,
181 DONT_ENUM | DONT_DELETE | READ_ONLY);
182 %SetCode(Script, function(x) {
183 // Script objects can only be created by the VM.
184 throw MakeError(kUnsupported);
188 // Helper functions; called from the runtime system.
189 function FormatMessage(type, arg0, arg1, arg2) {
190 var arg0 = NoSideEffectToString(arg0);
191 var arg1 = NoSideEffectToString(arg1);
192 var arg2 = NoSideEffectToString(arg2);
194 return %FormatMessageString(type, arg0, arg1, arg2);
201 function GetLineNumber(message) {
202 var start_position = %MessageGetStartPosition(message);
203 if (start_position == -1) return kNoLineNumberInfo;
204 var script = %MessageGetScript(message);
205 var location = script.locationFromPosition(start_position, true);
206 if (location == null) return kNoLineNumberInfo;
207 return location.line + 1;
211 //Returns the offset of the given position within the containing line.
212 function GetColumnNumber(message) {
213 var script = %MessageGetScript(message);
214 var start_position = %MessageGetStartPosition(message);
215 var location = script.locationFromPosition(start_position, true);
216 if (location == null) return -1;
217 return location.column;
221 // Returns the source code line containing the given source
222 // position, or the empty string if the position is invalid.
223 function GetSourceLine(message) {
224 var script = %MessageGetScript(message);
225 var start_position = %MessageGetStartPosition(message);
226 var location = script.locationFromPosition(start_position, true);
227 if (location == null) return "";
228 return location.sourceText();
233 * Find a line number given a specific source position.
234 * @param {number} position The source position.
235 * @return {number} 0 if input too small, -1 if input too large,
236 else the line number.
238 function ScriptLineFromPosition(position) {
240 var upper = this.lineCount() - 1;
241 var line_ends = this.line_ends;
243 // We'll never find invalid positions so bail right away.
244 if (position > line_ends[upper]) {
248 // This means we don't have to safe-guard indexing line_ends[i - 1].
249 if (position <= line_ends[0]) {
253 // Binary search to find line # from position range.
255 var i = (lower + upper) >> 1;
257 if (position > line_ends[i]) {
259 } else if (position <= line_ends[i - 1]) {
270 * Get information on a specific source position.
271 * @param {number} position The source position
272 * @param {boolean} include_resource_offset Set to true to have the resource
273 * offset added to the location
274 * @return {SourceLocation}
275 * If line is negative or not in the source null is returned.
277 function ScriptLocationFromPosition(position,
278 include_resource_offset) {
279 var line = this.lineFromPosition(position);
280 if (line == -1) return null;
282 // Determine start, end and column.
283 var line_ends = this.line_ends;
284 var start = line == 0 ? 0 : line_ends[line - 1] + 1;
285 var end = line_ends[line];
286 if (end > 0 && %_CallFunction(this.source, end - 1, StringCharAt) == '\r') {
289 var column = position - start;
291 // Adjust according to the offset within the resource.
292 if (include_resource_offset) {
293 line += this.line_offset;
294 if (line == this.line_offset) {
295 column += this.column_offset;
299 return new SourceLocation(this, position, line, column, start, end);
304 * Get information on a specific source line and column possibly offset by a
305 * fixed source position. This function is used to find a source position from
306 * a line and column position. The fixed source position offset is typically
307 * used to find a source position in a function based on a line and column in
308 * the source for the function alone. The offset passed will then be the
309 * start position of the source for the function within the full script source.
310 * @param {number} opt_line The line within the source. Default value is 0
311 * @param {number} opt_column The column in within the line. Default value is 0
312 * @param {number} opt_offset_position The offset from the begining of the
313 * source from where the line and column calculation starts.
315 * @return {SourceLocation}
316 * If line is negative or not in the source null is returned.
318 function ScriptLocationFromLine(opt_line, opt_column, opt_offset_position) {
319 // Default is the first line in the script. Lines in the script is relative
320 // to the offset within the resource.
322 if (!IS_UNDEFINED(opt_line)) {
323 line = opt_line - this.line_offset;
326 // Default is first column. If on the first line add the offset within the
328 var column = opt_column || 0;
330 column -= this.column_offset;
333 var offset_position = opt_offset_position || 0;
334 if (line < 0 || column < 0 || offset_position < 0) return null;
336 return this.locationFromPosition(offset_position + column, false);
338 // Find the line where the offset position is located.
339 var offset_line = this.lineFromPosition(offset_position);
341 if (offset_line == -1 || offset_line + line >= this.lineCount()) {
345 return this.locationFromPosition(
346 this.line_ends[offset_line + line - 1] + 1 + column); // line > 0 here.
352 * Get a slice of source code from the script. The boundaries for the slice is
353 * specified in lines.
354 * @param {number} opt_from_line The first line (zero bound) in the slice.
356 * @param {number} opt_to_column The last line (zero bound) in the slice (non
357 * inclusive). Default is the number of lines in the script
358 * @return {SourceSlice} The source slice or null of the parameters where
361 function ScriptSourceSlice(opt_from_line, opt_to_line) {
362 var from_line = IS_UNDEFINED(opt_from_line) ? this.line_offset
364 var to_line = IS_UNDEFINED(opt_to_line) ? this.line_offset + this.lineCount()
367 // Adjust according to the offset within the resource.
368 from_line -= this.line_offset;
369 to_line -= this.line_offset;
370 if (from_line < 0) from_line = 0;
371 if (to_line > this.lineCount()) to_line = this.lineCount();
374 if (from_line >= this.lineCount() ||
376 from_line > to_line) {
380 var line_ends = this.line_ends;
381 var from_position = from_line == 0 ? 0 : line_ends[from_line - 1] + 1;
382 var to_position = to_line == 0 ? 0 : line_ends[to_line - 1] + 1;
384 // Return a source slice with line numbers re-adjusted to the resource.
385 return new SourceSlice(this,
386 from_line + this.line_offset,
387 to_line + this.line_offset,
388 from_position, to_position);
392 function ScriptSourceLine(opt_line) {
393 // Default is the first line in the script. Lines in the script are relative
394 // to the offset within the resource.
396 if (!IS_UNDEFINED(opt_line)) {
397 line = opt_line - this.line_offset;
401 if (line < 0 || this.lineCount() <= line) {
405 // Return the source line.
406 var line_ends = this.line_ends;
407 var start = line == 0 ? 0 : line_ends[line - 1] + 1;
408 var end = line_ends[line];
409 return %_CallFunction(this.source, start, end, StringSubstring);
414 * Returns the number of source lines.
416 * Number of source lines.
418 function ScriptLineCount() {
419 // Return number of source lines.
420 return this.line_ends.length;
425 * Returns the position of the nth line end.
427 * Zero-based position of the nth line end in the script.
429 function ScriptLineEnd(n) {
430 return this.line_ends[n];
435 * If sourceURL comment is available returns sourceURL comment contents.
436 * Otherwise, script name is returned. See
437 * http://fbug.googlecode.com/svn/branches/firebug1.1/docs/ReleaseNotes_1.1.txt
438 * and Source Map Revision 3 proposal for details on using //# sourceURL and
439 * deprecated //@ sourceURL comment to identify scripts that don't have name.
441 * @return {?string} script name if present, value for //# sourceURL or
442 * deprecated //@ sourceURL comment otherwise.
444 function ScriptNameOrSourceURL() {
445 if (this.source_url) return this.source_url;
450 utils.SetUpLockedPrototype(Script, [
454 "source_mapping_url",
459 "lineFromPosition", ScriptLineFromPosition,
460 "locationFromPosition", ScriptLocationFromPosition,
461 "locationFromLine", ScriptLocationFromLine,
462 "sourceSlice", ScriptSourceSlice,
463 "sourceLine", ScriptSourceLine,
464 "lineCount", ScriptLineCount,
465 "nameOrSourceURL", ScriptNameOrSourceURL,
466 "lineEnd", ScriptLineEnd
472 * Class for source location. A source location is a position within some
473 * source with the following properties:
474 * script : script object for the source
475 * line : source line number
476 * column : source column within the line
477 * position : position within the source
478 * start : position of start of source context (inclusive)
479 * end : position of end of source context (not inclusive)
480 * Source text for the source context is the character interval
481 * [start, end[. In most cases end will point to a newline character.
482 * It might point just past the final position of the source if the last
483 * source line does not end with a newline character.
484 * @param {Script} script The Script object for which this is a location
485 * @param {number} position Source position for the location
486 * @param {number} line The line number for the location
487 * @param {number} column The column within the line for the location
488 * @param {number} start Source position for start of source context
489 * @param {number} end Source position for end of source context
492 function SourceLocation(script, position, line, column, start, end) {
493 this.script = script;
494 this.position = position;
496 this.column = column;
503 * Get the source text for a SourceLocation
505 * Source text for this location.
507 function SourceLocationSourceText() {
508 return %_CallFunction(this.script.source,
515 utils.SetUpLockedPrototype(SourceLocation,
516 ["script", "position", "line", "column", "start", "end"],
517 ["sourceText", SourceLocationSourceText]
522 * Class for a source slice. A source slice is a part of a script source with
523 * the following properties:
524 * script : script object for the source
525 * from_line : line number for the first line in the slice
526 * to_line : source line number for the last line in the slice
527 * from_position : position of the first character in the slice
528 * to_position : position of the last character in the slice
529 * The to_line and to_position are not included in the slice, that is the lines
530 * in the slice are [from_line, to_line[. Likewise the characters in the slice
531 * are [from_position, to_position[.
532 * @param {Script} script The Script object for the source slice
533 * @param {number} from_line
534 * @param {number} to_line
535 * @param {number} from_position
536 * @param {number} to_position
539 function SourceSlice(script, from_line, to_line, from_position, to_position) {
540 this.script = script;
541 this.from_line = from_line;
542 this.to_line = to_line;
543 this.from_position = from_position;
544 this.to_position = to_position;
548 * Get the source text for a SourceSlice
549 * @return {String} Source text for this slice. The last line will include
550 * the line terminating characters (if any)
552 function SourceSliceSourceText() {
553 return %_CallFunction(this.script.source,
559 utils.SetUpLockedPrototype(SourceSlice,
560 ["script", "from_line", "to_line", "from_position", "to_position"],
561 ["sourceText", SourceSliceSourceText]
565 function GetStackTraceLine(recv, fun, pos, isGlobal) {
566 return new CallSite(recv, fun, pos, false).toString();
569 // ----------------------------------------------------------------------------
570 // Error implementation
572 var CallSiteReceiverKey = NEW_PRIVATE("CallSite#receiver");
573 var CallSiteFunctionKey = NEW_PRIVATE("CallSite#function");
574 var CallSitePositionKey = NEW_PRIVATE("CallSite#position");
575 var CallSiteStrictModeKey = NEW_PRIVATE("CallSite#strict_mode");
577 function CallSite(receiver, fun, pos, strict_mode) {
578 SET_PRIVATE(this, CallSiteReceiverKey, receiver);
579 SET_PRIVATE(this, CallSiteFunctionKey, fun);
580 SET_PRIVATE(this, CallSitePositionKey, pos);
581 SET_PRIVATE(this, CallSiteStrictModeKey, strict_mode);
584 function CallSiteGetThis() {
585 return GET_PRIVATE(this, CallSiteStrictModeKey)
586 ? UNDEFINED : GET_PRIVATE(this, CallSiteReceiverKey);
589 function CallSiteGetFunction() {
590 return GET_PRIVATE(this, CallSiteStrictModeKey)
591 ? UNDEFINED : GET_PRIVATE(this, CallSiteFunctionKey);
594 function CallSiteGetPosition() {
595 return GET_PRIVATE(this, CallSitePositionKey);
598 function CallSiteGetTypeName() {
599 return GetTypeName(GET_PRIVATE(this, CallSiteReceiverKey), false);
602 function CallSiteIsToplevel() {
603 var receiver = GET_PRIVATE(this, CallSiteReceiverKey);
604 var fun = GET_PRIVATE(this, CallSiteFunctionKey);
605 var pos = GET_PRIVATE(this, CallSitePositionKey);
606 return %CallSiteIsToplevelRT(receiver, fun, pos);
609 function CallSiteIsEval() {
610 var receiver = GET_PRIVATE(this, CallSiteReceiverKey);
611 var fun = GET_PRIVATE(this, CallSiteFunctionKey);
612 var pos = GET_PRIVATE(this, CallSitePositionKey);
613 return %CallSiteIsEvalRT(receiver, fun, pos);
616 function CallSiteGetEvalOrigin() {
617 var script = %FunctionGetScript(GET_PRIVATE(this, CallSiteFunctionKey));
618 return FormatEvalOrigin(script);
621 function CallSiteGetScriptNameOrSourceURL() {
622 var receiver = GET_PRIVATE(this, CallSiteReceiverKey);
623 var fun = GET_PRIVATE(this, CallSiteFunctionKey);
624 var pos = GET_PRIVATE(this, CallSitePositionKey);
625 return %CallSiteGetScriptNameOrSourceUrlRT(receiver, fun, pos);
628 function CallSiteGetFunctionName() {
629 // See if the function knows its own name
630 var receiver = GET_PRIVATE(this, CallSiteReceiverKey);
631 var fun = GET_PRIVATE(this, CallSiteFunctionKey);
632 var pos = GET_PRIVATE(this, CallSitePositionKey);
633 return %CallSiteGetFunctionNameRT(receiver, fun, pos);
636 function CallSiteGetMethodName() {
637 // See if we can find a unique property on the receiver that holds
639 var receiver = GET_PRIVATE(this, CallSiteReceiverKey);
640 var fun = GET_PRIVATE(this, CallSiteFunctionKey);
641 var pos = GET_PRIVATE(this, CallSitePositionKey);
642 return %CallSiteGetMethodNameRT(receiver, fun, pos);
645 function CallSiteGetFileName() {
646 var receiver = GET_PRIVATE(this, CallSiteReceiverKey);
647 var fun = GET_PRIVATE(this, CallSiteFunctionKey);
648 var pos = GET_PRIVATE(this, CallSitePositionKey);
649 return %CallSiteGetFileNameRT(receiver, fun, pos);
652 function CallSiteGetLineNumber() {
653 var receiver = GET_PRIVATE(this, CallSiteReceiverKey);
654 var fun = GET_PRIVATE(this, CallSiteFunctionKey);
655 var pos = GET_PRIVATE(this, CallSitePositionKey);
656 return %CallSiteGetLineNumberRT(receiver, fun, pos);
659 function CallSiteGetColumnNumber() {
660 var receiver = GET_PRIVATE(this, CallSiteReceiverKey);
661 var fun = GET_PRIVATE(this, CallSiteFunctionKey);
662 var pos = GET_PRIVATE(this, CallSitePositionKey);
663 return %CallSiteGetColumnNumberRT(receiver, fun, pos);
666 function CallSiteIsNative() {
667 var receiver = GET_PRIVATE(this, CallSiteReceiverKey);
668 var fun = GET_PRIVATE(this, CallSiteFunctionKey);
669 var pos = GET_PRIVATE(this, CallSitePositionKey);
670 return %CallSiteIsNativeRT(receiver, fun, pos);
673 function CallSiteIsConstructor() {
674 var receiver = GET_PRIVATE(this, CallSiteReceiverKey);
675 var fun = GET_PRIVATE(this, CallSiteFunctionKey);
676 var pos = GET_PRIVATE(this, CallSitePositionKey);
677 return %CallSiteIsConstructorRT(receiver, fun, pos);
680 function CallSiteToString() {
682 var fileLocation = "";
683 if (this.isNative()) {
684 fileLocation = "native";
686 fileName = this.getScriptNameOrSourceURL();
687 if (!fileName && this.isEval()) {
688 fileLocation = this.getEvalOrigin();
689 fileLocation += ", "; // Expecting source position to follow.
693 fileLocation += fileName;
695 // Source code does not originate from a file and is not native, but we
696 // can still get the source position inside the source string, e.g. in
698 fileLocation += "<anonymous>";
700 var lineNumber = this.getLineNumber();
701 if (lineNumber != null) {
702 fileLocation += ":" + lineNumber;
703 var columnNumber = this.getColumnNumber();
705 fileLocation += ":" + columnNumber;
711 var functionName = this.getFunctionName();
712 var addSuffix = true;
713 var isConstructor = this.isConstructor();
714 var isMethodCall = !(this.isToplevel() || isConstructor);
716 var typeName = GetTypeName(GET_PRIVATE(this, CallSiteReceiverKey), true);
717 var methodName = this.getMethodName();
720 %_CallFunction(functionName, typeName, StringIndexOf) != 0) {
721 line += typeName + ".";
723 line += functionName;
725 (%_CallFunction(functionName, "." + methodName, StringIndexOf) !=
726 functionName.length - methodName.length - 1)) {
727 line += " [as " + methodName + "]";
730 line += typeName + "." + (methodName || "<anonymous>");
732 } else if (isConstructor) {
733 line += "new " + (functionName || "<anonymous>");
734 } else if (functionName) {
735 line += functionName;
737 line += fileLocation;
741 line += " (" + fileLocation + ")";
746 utils.SetUpLockedPrototype(CallSite, ["receiver", "fun", "pos"], [
747 "getThis", CallSiteGetThis,
748 "getTypeName", CallSiteGetTypeName,
749 "isToplevel", CallSiteIsToplevel,
750 "isEval", CallSiteIsEval,
751 "getEvalOrigin", CallSiteGetEvalOrigin,
752 "getScriptNameOrSourceURL", CallSiteGetScriptNameOrSourceURL,
753 "getFunction", CallSiteGetFunction,
754 "getFunctionName", CallSiteGetFunctionName,
755 "getMethodName", CallSiteGetMethodName,
756 "getFileName", CallSiteGetFileName,
757 "getLineNumber", CallSiteGetLineNumber,
758 "getColumnNumber", CallSiteGetColumnNumber,
759 "isNative", CallSiteIsNative,
760 "getPosition", CallSiteGetPosition,
761 "isConstructor", CallSiteIsConstructor,
762 "toString", CallSiteToString
766 function FormatEvalOrigin(script) {
767 var sourceURL = script.nameOrSourceURL();
772 var eval_origin = "eval at ";
773 if (script.eval_from_function_name) {
774 eval_origin += script.eval_from_function_name;
776 eval_origin += "<anonymous>";
779 var eval_from_script = script.eval_from_script;
780 if (eval_from_script) {
781 if (eval_from_script.compilation_type == COMPILATION_TYPE_EVAL) {
782 // eval script originated from another eval.
783 eval_origin += " (" + FormatEvalOrigin(eval_from_script) + ")";
785 // eval script originated from "real" source.
786 if (eval_from_script.name) {
787 eval_origin += " (" + eval_from_script.name;
788 var location = eval_from_script.locationFromPosition(
789 script.eval_from_script_position, true);
791 eval_origin += ":" + (location.line + 1);
792 eval_origin += ":" + (location.column + 1);
796 eval_origin += " (unknown source)";
805 function FormatErrorString(error) {
807 return %_CallFunction(error, ErrorToString);
810 return "<error: " + e + ">";
818 function GetStackFrames(raw_stack) {
819 var frames = new InternalArray();
820 var sloppy_frames = raw_stack[0];
821 for (var i = 1; i < raw_stack.length; i += 4) {
822 var recv = raw_stack[i];
823 var fun = raw_stack[i + 1];
824 var code = raw_stack[i + 2];
825 var pc = raw_stack[i + 3];
826 var pos = %_IsSmi(code) ? code : %FunctionGetPositionForOffset(code, pc);
828 frames.push(new CallSite(recv, fun, pos, (sloppy_frames < 0)));
834 // Flag to prevent recursive call of Error.prepareStackTrace.
835 var formatting_custom_stack_trace = false;
838 function FormatStackTrace(obj, raw_stack) {
839 var frames = GetStackFrames(raw_stack);
840 if (IS_FUNCTION(GlobalError.prepareStackTrace) &&
841 !formatting_custom_stack_trace) {
843 %MoveArrayContents(frames, array);
844 formatting_custom_stack_trace = true;
845 var stack_trace = UNDEFINED;
847 stack_trace = GlobalError.prepareStackTrace(obj, array);
849 throw e; // The custom formatting function threw. Rethrow.
851 formatting_custom_stack_trace = false;
856 var lines = new InternalArray();
857 lines.push(FormatErrorString(obj));
858 for (var i = 0; i < frames.length; i++) {
859 var frame = frames[i];
862 line = frame.toString();
865 line = "<error: " + e + ">";
867 // Any code that reaches this point is seriously nasty!
871 lines.push(" at " + line);
873 return %_CallFunction(lines, "\n", ArrayJoin);
877 function GetTypeName(receiver, requireConstructor) {
878 if (IS_NULL_OR_UNDEFINED(receiver)) return null;
879 var constructor = receiver.constructor;
881 return requireConstructor ? null :
882 %_CallFunction(receiver, NoSideEffectsObjectToString);
884 var constructorName = constructor.name;
885 if (!constructorName) {
886 return requireConstructor ? null :
887 %_CallFunction(receiver, NoSideEffectsObjectToString);
889 return constructorName;
892 var formatted_stack_trace_symbol = NEW_PRIVATE("formatted stack trace");
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;
901 var formatted_stack_trace =
902 GET_PRIVATE(holder, formatted_stack_trace_symbol);
903 if (IS_UNDEFINED(formatted_stack_trace)) {
904 // No formatted stack trace available.
905 var stack_trace = GET_PRIVATE(holder, $stackTraceSymbol);
906 if (IS_UNDEFINED(stack_trace)) {
907 // Neither formatted nor structured stack trace available.
908 // Look further up the prototype chain.
909 holder = %_GetPrototype(holder);
912 formatted_stack_trace = FormatStackTrace(holder, stack_trace);
913 SET_PRIVATE(holder, $stackTraceSymbol, UNDEFINED);
914 SET_PRIVATE(holder, formatted_stack_trace_symbol, formatted_stack_trace);
916 return formatted_stack_trace;
922 // If the receiver equals the holder, set the formatted stack trace that the
924 var StackTraceSetter = function(v) {
925 if (HAS_PRIVATE(this, $stackTraceSymbol)) {
926 SET_PRIVATE(this, $stackTraceSymbol, UNDEFINED);
927 SET_PRIVATE(this, formatted_stack_trace_symbol, v);
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() {};
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
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());
958 %FunctionSetPrototype(f, new GlobalError());
959 %InternalSetPrototype(f, GlobalError);
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);
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() { });
989 %AddNamedProperty(GlobalError.prototype, 'message', '', DONT_ENUM);
991 function ErrorToString() {
992 if (!IS_SPEC_OBJECT(this)) {
993 throw MakeTypeError(kCalledOnNonObject, "Error.prototype.toString");
996 return %ErrorToStringRT(this);
999 utils.InstallFunctions(GlobalError.prototype, DONT_ENUM,
1000 ['toString', ErrorToString]);
1002 $errorToString = ErrorToString;
1004 MakeError = function(type, arg0, arg1, arg2) {
1005 return MakeGenericError(GlobalError, type, arg0, arg1, arg2);
1008 MakeRangeError = function(type, arg0, arg1, arg2) {
1009 return MakeGenericError(GlobalRangeError, type, arg0, arg1, arg2);
1012 MakeSyntaxError = function(type, arg0, arg1, arg2) {
1013 return MakeGenericError(GlobalSyntaxError, type, arg0, arg1, arg2);
1016 MakeTypeError = function(type, arg0, arg1, arg2) {
1017 return MakeGenericError(GlobalTypeError, type, arg0, arg1, arg2);
1020 MakeURIError = function() {
1021 return MakeGenericError(GlobalURIError, kURIMalformed);
1024 // Boilerplate for exceptions for stack overflows. Used from
1025 // Isolate::StackOverflow().
1026 var StackOverflowBoilerplate = MakeRangeError(kStackOverflow);
1027 %DefineAccessorPropertyUnchecked(StackOverflowBoilerplate, 'stack',
1028 StackTraceGetter, StackTraceSetter,
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);
1040 GlobalError.captureStackTrace = captureStackTrace;
1042 utils.ExportToRuntime(function(to) {
1043 to.Error = GlobalError;
1044 to.EvalError = GlobalEvalError;
1045 to.RangeError = GlobalRangeError;
1046 to.ReferenceError = GlobalReferenceError;
1047 to.SyntaxError = GlobalSyntaxError;
1048 to.TypeError = GlobalTypeError;
1049 to.URIError = GlobalURIError;
1050 to.GetStackTraceLine = GetStackTraceLine;
1051 to.NoSideEffectToString = NoSideEffectToString;
1052 to.ToDetailString = ToDetailString;
1053 to.MakeError = MakeGenericError;
1054 to.MessageGetLineNumber = GetLineNumber;
1055 to.MessageGetColumnNumber = GetColumnNumber;
1056 to.MessageGetSourceLine = GetSourceLine;
1057 to.StackOverflowBoilerplate = StackOverflowBoilerplate;