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 // -------------------------------------------------------------------
11 var MakeReferenceError;
16 (function(global, utils) {
18 %CheckIsBootstrapping();
20 // -------------------------------------------------------------------
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;
43 var InternalArray = utils.InternalArray;
44 var internalErrorSymbol = utils.ImportNow("internal_error_symbol");
45 var ObjectDefineProperty;
47 var stackTraceSymbol = utils.ImportNow("stack_trace_symbol");
52 var ToString = utils.ImportNow("ToString");
57 utils.Import(function(from) {
58 ArrayJoin = from.ArrayJoin;
59 Bool16x8ToString = from.Bool16x8ToString;
60 Bool32x4ToString = from.Bool32x4ToString;
61 Bool8x16ToString = from.Bool8x16ToString;
62 Float32x4ToString = from.Float32x4ToString;
63 FunctionSourceString = from.FunctionSourceString;
64 Int16x8ToString = from.Int16x8ToString;
65 Int32x4ToString = from.Int32x4ToString;
66 Int8x16ToString = from.Int8x16ToString;
67 ObjectDefineProperty = from.ObjectDefineProperty;
68 ObjectToString = from.ObjectToString;
69 StringCharAt = from.StringCharAt;
70 StringIndexOf = from.StringIndexOf;
71 StringSubstring = from.StringSubstring;
72 SymbolToString = from.SymbolToString;
73 Uint16x8ToString = from.Uint16x8ToString;
74 Uint32x4ToString = from.Uint32x4ToString;
75 Uint8x16ToString = from.Uint8x16ToString;
78 // -------------------------------------------------------------------
84 var GlobalSyntaxError;
85 var GlobalReferenceError;
89 function NoSideEffectsObjectToString() {
90 if (IS_UNDEFINED(this)) return "[object Undefined]";
91 if (IS_NULL(this)) return "[object Null]";
92 return "[object " + %_ClassOf(TO_OBJECT(this)) + "]";
96 function NoSideEffectToString(obj) {
97 if (IS_STRING(obj)) return obj;
98 if (IS_NUMBER(obj)) return %_NumberToString(obj);
99 if (IS_BOOLEAN(obj)) return obj ? 'true' : 'false';
100 if (IS_UNDEFINED(obj)) return 'undefined';
101 if (IS_NULL(obj)) return 'null';
102 if (IS_FUNCTION(obj)) {
103 var str = %_CallFunction(obj, obj, FunctionSourceString);
104 if (str.length > 128) {
105 str = %_SubString(str, 0, 111) + "...<omitted>..." +
106 %_SubString(str, str.length - 2, str.length);
110 if (IS_SYMBOL(obj)) return %_CallFunction(obj, SymbolToString);
111 if (IS_SIMD_VALUE(obj)) {
112 switch (typeof(obj)) {
113 case 'float32x4': return %_CallFunction(obj, Float32x4ToString);
114 case 'int32x4': return %_CallFunction(obj, Int32x4ToString);
115 case 'int16x8': return %_CallFunction(obj, Int16x8ToString);
116 case 'int8x16': return %_CallFunction(obj, Int8x16ToString);
117 case 'uint32x4': return %_CallFunction(obj, Uint32x4ToString);
118 case 'uint16x8': return %_CallFunction(obj, Uint16x8ToString);
119 case 'uint8x16': return %_CallFunction(obj, Uint8x16ToString);
120 case 'bool32x4': return %_CallFunction(obj, Bool32x4ToString);
121 case 'bool16x8': return %_CallFunction(obj, Bool16x8ToString);
122 case 'bool8x16': return %_CallFunction(obj, Bool8x16ToString);
126 && %GetDataProperty(obj, "toString") === ObjectToString) {
127 var constructor = %GetDataProperty(obj, "constructor");
128 if (typeof constructor == "function") {
129 var constructorName = constructor.name;
130 if (IS_STRING(constructorName) && constructorName !== "") {
131 return "#<" + constructorName + ">";
135 if (CanBeSafelyTreatedAsAnErrorObject(obj)) {
136 return %_CallFunction(obj, ErrorToString);
139 return %_CallFunction(obj, NoSideEffectsObjectToString);
142 // To determine whether we can safely stringify an object using ErrorToString
143 // without the risk of side-effects, we need to check whether the object is
144 // either an instance of a native error type (via '%_ClassOf'), or has Error
145 // in its prototype chain and hasn't overwritten 'toString' with something
146 // strange and unusual.
147 function CanBeSafelyTreatedAsAnErrorObject(obj) {
148 switch (%_ClassOf(obj)) {
152 case 'ReferenceError':
159 var objToString = %GetDataProperty(obj, "toString");
160 return obj instanceof GlobalError && objToString === ErrorToString;
164 // When formatting internally created error messages, do not
165 // invoke overwritten error toString methods but explicitly use
166 // the error to string method. This is to avoid leaking error
167 // objects between script tags in a browser setting.
168 function ToStringCheckErrorObject(obj) {
169 if (CanBeSafelyTreatedAsAnErrorObject(obj)) {
170 return %_CallFunction(obj, ErrorToString);
172 return ToString(obj);
177 function ToDetailString(obj) {
178 if (obj != null && IS_OBJECT(obj) && obj.toString === ObjectToString) {
179 var constructor = obj.constructor;
180 if (typeof constructor == "function") {
181 var constructorName = constructor.name;
182 if (IS_STRING(constructorName) && constructorName !== "") {
183 return "#<" + constructorName + ">";
187 return ToStringCheckErrorObject(obj);
191 function MakeGenericError(constructor, type, arg0, arg1, arg2) {
192 var error = new constructor(FormatMessage(type, arg0, arg1, arg2));
193 error[internalErrorSymbol] = true;
199 * Set up the Script function and constructor.
201 %FunctionSetInstanceClassName(Script, 'Script');
202 %AddNamedProperty(Script.prototype, 'constructor', Script,
203 DONT_ENUM | DONT_DELETE | READ_ONLY);
204 %SetCode(Script, function(x) {
205 // Script objects can only be created by the VM.
206 throw MakeError(kUnsupported);
210 // Helper functions; called from the runtime system.
211 function FormatMessage(type, arg0, arg1, arg2) {
212 var arg0 = NoSideEffectToString(arg0);
213 var arg1 = NoSideEffectToString(arg1);
214 var arg2 = NoSideEffectToString(arg2);
216 return %FormatMessageString(type, arg0, arg1, arg2);
223 function GetLineNumber(message) {
224 var start_position = %MessageGetStartPosition(message);
225 if (start_position == -1) return kNoLineNumberInfo;
226 var script = %MessageGetScript(message);
227 var location = script.locationFromPosition(start_position, true);
228 if (location == null) return kNoLineNumberInfo;
229 return location.line + 1;
233 //Returns the offset of the given position within the containing line.
234 function GetColumnNumber(message) {
235 var script = %MessageGetScript(message);
236 var start_position = %MessageGetStartPosition(message);
237 var location = script.locationFromPosition(start_position, true);
238 if (location == null) return -1;
239 return location.column;
243 // Returns the source code line containing the given source
244 // position, or the empty string if the position is invalid.
245 function GetSourceLine(message) {
246 var script = %MessageGetScript(message);
247 var start_position = %MessageGetStartPosition(message);
248 var location = script.locationFromPosition(start_position, true);
249 if (location == null) return "";
250 return location.sourceText();
255 * Find a line number given a specific source position.
256 * @param {number} position The source position.
257 * @return {number} 0 if input too small, -1 if input too large,
258 else the line number.
260 function ScriptLineFromPosition(position) {
262 var upper = this.lineCount() - 1;
263 var line_ends = this.line_ends;
265 // We'll never find invalid positions so bail right away.
266 if (position > line_ends[upper]) {
270 // This means we don't have to safe-guard indexing line_ends[i - 1].
271 if (position <= line_ends[0]) {
275 // Binary search to find line # from position range.
277 var i = (lower + upper) >> 1;
279 if (position > line_ends[i]) {
281 } else if (position <= line_ends[i - 1]) {
292 * Get information on a specific source position.
293 * @param {number} position The source position
294 * @param {boolean} include_resource_offset Set to true to have the resource
295 * offset added to the location
296 * @return {SourceLocation}
297 * If line is negative or not in the source null is returned.
299 function ScriptLocationFromPosition(position,
300 include_resource_offset) {
301 var line = this.lineFromPosition(position);
302 if (line == -1) return null;
304 // Determine start, end and column.
305 var line_ends = this.line_ends;
306 var start = line == 0 ? 0 : line_ends[line - 1] + 1;
307 var end = line_ends[line];
308 if (end > 0 && %_CallFunction(this.source, end - 1, StringCharAt) == '\r') {
311 var column = position - start;
313 // Adjust according to the offset within the resource.
314 if (include_resource_offset) {
315 line += this.line_offset;
316 if (line == this.line_offset) {
317 column += this.column_offset;
321 return new SourceLocation(this, position, line, column, start, end);
326 * Get information on a specific source line and column possibly offset by a
327 * fixed source position. This function is used to find a source position from
328 * a line and column position. The fixed source position offset is typically
329 * used to find a source position in a function based on a line and column in
330 * the source for the function alone. The offset passed will then be the
331 * start position of the source for the function within the full script source.
332 * @param {number} opt_line The line within the source. Default value is 0
333 * @param {number} opt_column The column in within the line. Default value is 0
334 * @param {number} opt_offset_position The offset from the begining of the
335 * source from where the line and column calculation starts.
337 * @return {SourceLocation}
338 * If line is negative or not in the source null is returned.
340 function ScriptLocationFromLine(opt_line, opt_column, opt_offset_position) {
341 // Default is the first line in the script. Lines in the script is relative
342 // to the offset within the resource.
344 if (!IS_UNDEFINED(opt_line)) {
345 line = opt_line - this.line_offset;
348 // Default is first column. If on the first line add the offset within the
350 var column = opt_column || 0;
352 column -= this.column_offset;
355 var offset_position = opt_offset_position || 0;
356 if (line < 0 || column < 0 || offset_position < 0) return null;
358 return this.locationFromPosition(offset_position + column, false);
360 // Find the line where the offset position is located.
361 var offset_line = this.lineFromPosition(offset_position);
363 if (offset_line == -1 || offset_line + line >= this.lineCount()) {
367 return this.locationFromPosition(
368 this.line_ends[offset_line + line - 1] + 1 + column); // line > 0 here.
374 * Get a slice of source code from the script. The boundaries for the slice is
375 * specified in lines.
376 * @param {number} opt_from_line The first line (zero bound) in the slice.
378 * @param {number} opt_to_column The last line (zero bound) in the slice (non
379 * inclusive). Default is the number of lines in the script
380 * @return {SourceSlice} The source slice or null of the parameters where
383 function ScriptSourceSlice(opt_from_line, opt_to_line) {
384 var from_line = IS_UNDEFINED(opt_from_line) ? this.line_offset
386 var to_line = IS_UNDEFINED(opt_to_line) ? this.line_offset + this.lineCount()
389 // Adjust according to the offset within the resource.
390 from_line -= this.line_offset;
391 to_line -= this.line_offset;
392 if (from_line < 0) from_line = 0;
393 if (to_line > this.lineCount()) to_line = this.lineCount();
396 if (from_line >= this.lineCount() ||
398 from_line > to_line) {
402 var line_ends = this.line_ends;
403 var from_position = from_line == 0 ? 0 : line_ends[from_line - 1] + 1;
404 var to_position = to_line == 0 ? 0 : line_ends[to_line - 1] + 1;
406 // Return a source slice with line numbers re-adjusted to the resource.
407 return new SourceSlice(this,
408 from_line + this.line_offset,
409 to_line + this.line_offset,
410 from_position, to_position);
414 function ScriptSourceLine(opt_line) {
415 // Default is the first line in the script. Lines in the script are relative
416 // to the offset within the resource.
418 if (!IS_UNDEFINED(opt_line)) {
419 line = opt_line - this.line_offset;
423 if (line < 0 || this.lineCount() <= line) {
427 // Return the source line.
428 var line_ends = this.line_ends;
429 var start = line == 0 ? 0 : line_ends[line - 1] + 1;
430 var end = line_ends[line];
431 return %_CallFunction(this.source, start, end, StringSubstring);
436 * Returns the number of source lines.
438 * Number of source lines.
440 function ScriptLineCount() {
441 // Return number of source lines.
442 return this.line_ends.length;
447 * Returns the position of the nth line end.
449 * Zero-based position of the nth line end in the script.
451 function ScriptLineEnd(n) {
452 return this.line_ends[n];
457 * If sourceURL comment is available returns sourceURL comment contents.
458 * Otherwise, script name is returned. See
459 * http://fbug.googlecode.com/svn/branches/firebug1.1/docs/ReleaseNotes_1.1.txt
460 * and Source Map Revision 3 proposal for details on using //# sourceURL and
461 * deprecated //@ sourceURL comment to identify scripts that don't have name.
463 * @return {?string} script name if present, value for //# sourceURL or
464 * deprecated //@ sourceURL comment otherwise.
466 function ScriptNameOrSourceURL() {
467 if (this.source_url) return this.source_url;
472 utils.SetUpLockedPrototype(Script, [
476 "source_mapping_url",
481 "lineFromPosition", ScriptLineFromPosition,
482 "locationFromPosition", ScriptLocationFromPosition,
483 "locationFromLine", ScriptLocationFromLine,
484 "sourceSlice", ScriptSourceSlice,
485 "sourceLine", ScriptSourceLine,
486 "lineCount", ScriptLineCount,
487 "nameOrSourceURL", ScriptNameOrSourceURL,
488 "lineEnd", ScriptLineEnd
494 * Class for source location. A source location is a position within some
495 * source with the following properties:
496 * script : script object for the source
497 * line : source line number
498 * column : source column within the line
499 * position : position within the source
500 * start : position of start of source context (inclusive)
501 * end : position of end of source context (not inclusive)
502 * Source text for the source context is the character interval
503 * [start, end[. In most cases end will point to a newline character.
504 * It might point just past the final position of the source if the last
505 * source line does not end with a newline character.
506 * @param {Script} script The Script object for which this is a location
507 * @param {number} position Source position for the location
508 * @param {number} line The line number for the location
509 * @param {number} column The column within the line for the location
510 * @param {number} start Source position for start of source context
511 * @param {number} end Source position for end of source context
514 function SourceLocation(script, position, line, column, start, end) {
515 this.script = script;
516 this.position = position;
518 this.column = column;
525 * Get the source text for a SourceLocation
527 * Source text for this location.
529 function SourceLocationSourceText() {
530 return %_CallFunction(this.script.source,
537 utils.SetUpLockedPrototype(SourceLocation,
538 ["script", "position", "line", "column", "start", "end"],
539 ["sourceText", SourceLocationSourceText]
544 * Class for a source slice. A source slice is a part of a script source with
545 * the following properties:
546 * script : script object for the source
547 * from_line : line number for the first line in the slice
548 * to_line : source line number for the last line in the slice
549 * from_position : position of the first character in the slice
550 * to_position : position of the last character in the slice
551 * The to_line and to_position are not included in the slice, that is the lines
552 * in the slice are [from_line, to_line[. Likewise the characters in the slice
553 * are [from_position, to_position[.
554 * @param {Script} script The Script object for the source slice
555 * @param {number} from_line
556 * @param {number} to_line
557 * @param {number} from_position
558 * @param {number} to_position
561 function SourceSlice(script, from_line, to_line, from_position, to_position) {
562 this.script = script;
563 this.from_line = from_line;
564 this.to_line = to_line;
565 this.from_position = from_position;
566 this.to_position = to_position;
570 * Get the source text for a SourceSlice
571 * @return {String} Source text for this slice. The last line will include
572 * the line terminating characters (if any)
574 function SourceSliceSourceText() {
575 return %_CallFunction(this.script.source,
581 utils.SetUpLockedPrototype(SourceSlice,
582 ["script", "from_line", "to_line", "from_position", "to_position"],
583 ["sourceText", SourceSliceSourceText]
587 function GetStackTraceLine(recv, fun, pos, isGlobal) {
588 return new CallSite(recv, fun, pos, false).toString();
591 // ----------------------------------------------------------------------------
592 // Error implementation
594 function CallSite(receiver, fun, pos, strict_mode) {
595 SET_PRIVATE(this, callSiteReceiverSymbol, receiver);
596 SET_PRIVATE(this, callSiteFunctionSymbol, fun);
597 SET_PRIVATE(this, callSitePositionSymbol, pos);
598 SET_PRIVATE(this, callSiteStrictSymbol, strict_mode);
601 function CallSiteGetThis() {
602 return GET_PRIVATE(this, callSiteStrictSymbol)
603 ? UNDEFINED : GET_PRIVATE(this, callSiteReceiverSymbol);
606 function CallSiteGetFunction() {
607 return GET_PRIVATE(this, callSiteStrictSymbol)
608 ? UNDEFINED : GET_PRIVATE(this, callSiteFunctionSymbol);
611 function CallSiteGetPosition() {
612 return GET_PRIVATE(this, callSitePositionSymbol);
615 function CallSiteGetTypeName() {
616 return GetTypeName(GET_PRIVATE(this, callSiteReceiverSymbol), false);
619 function CallSiteIsToplevel() {
620 return %CallSiteIsToplevelRT(this);
623 function CallSiteIsEval() {
624 return %CallSiteIsEvalRT(this);
627 function CallSiteGetEvalOrigin() {
628 var script = %FunctionGetScript(GET_PRIVATE(this, callSiteFunctionSymbol));
629 return FormatEvalOrigin(script);
632 function CallSiteGetScriptNameOrSourceURL() {
633 return %CallSiteGetScriptNameOrSourceUrlRT(this);
636 function CallSiteGetFunctionName() {
637 // See if the function knows its own name
638 return %CallSiteGetFunctionNameRT(this);
641 function CallSiteGetMethodName() {
642 // See if we can find a unique property on the receiver that holds
644 return %CallSiteGetMethodNameRT(this);
647 function CallSiteGetFileName() {
648 return %CallSiteGetFileNameRT(this);
651 function CallSiteGetLineNumber() {
652 return %CallSiteGetLineNumberRT(this);
655 function CallSiteGetColumnNumber() {
656 return %CallSiteGetColumnNumberRT(this);
659 function CallSiteIsNative() {
660 return %CallSiteIsNativeRT(this);
663 function CallSiteIsConstructor() {
664 return %CallSiteIsConstructorRT(this);
667 function CallSiteToString() {
669 var fileLocation = "";
670 if (this.isNative()) {
671 fileLocation = "native";
673 fileName = this.getScriptNameOrSourceURL();
674 if (!fileName && this.isEval()) {
675 fileLocation = this.getEvalOrigin();
676 fileLocation += ", "; // Expecting source position to follow.
680 fileLocation += fileName;
682 // Source code does not originate from a file and is not native, but we
683 // can still get the source position inside the source string, e.g. in
685 fileLocation += "<anonymous>";
687 var lineNumber = this.getLineNumber();
688 if (lineNumber != null) {
689 fileLocation += ":" + lineNumber;
690 var columnNumber = this.getColumnNumber();
692 fileLocation += ":" + columnNumber;
698 var functionName = this.getFunctionName();
699 var addSuffix = true;
700 var isConstructor = this.isConstructor();
701 var isMethodCall = !(this.isToplevel() || isConstructor);
703 var typeName = GetTypeName(GET_PRIVATE(this, callSiteReceiverSymbol), true);
704 var methodName = this.getMethodName();
707 %_CallFunction(functionName, typeName, StringIndexOf) != 0) {
708 line += typeName + ".";
710 line += functionName;
712 (%_CallFunction(functionName, "." + methodName, StringIndexOf) !=
713 functionName.length - methodName.length - 1)) {
714 line += " [as " + methodName + "]";
717 line += typeName + "." + (methodName || "<anonymous>");
719 } else if (isConstructor) {
720 line += "new " + (functionName || "<anonymous>");
721 } else if (functionName) {
722 line += functionName;
724 line += fileLocation;
728 line += " (" + fileLocation + ")";
733 utils.SetUpLockedPrototype(CallSite, ["receiver", "fun", "pos"], [
734 "getThis", CallSiteGetThis,
735 "getTypeName", CallSiteGetTypeName,
736 "isToplevel", CallSiteIsToplevel,
737 "isEval", CallSiteIsEval,
738 "getEvalOrigin", CallSiteGetEvalOrigin,
739 "getScriptNameOrSourceURL", CallSiteGetScriptNameOrSourceURL,
740 "getFunction", CallSiteGetFunction,
741 "getFunctionName", CallSiteGetFunctionName,
742 "getMethodName", CallSiteGetMethodName,
743 "getFileName", CallSiteGetFileName,
744 "getLineNumber", CallSiteGetLineNumber,
745 "getColumnNumber", CallSiteGetColumnNumber,
746 "isNative", CallSiteIsNative,
747 "getPosition", CallSiteGetPosition,
748 "isConstructor", CallSiteIsConstructor,
749 "toString", CallSiteToString
753 function FormatEvalOrigin(script) {
754 var sourceURL = script.nameOrSourceURL();
759 var eval_origin = "eval at ";
760 if (script.eval_from_function_name) {
761 eval_origin += script.eval_from_function_name;
763 eval_origin += "<anonymous>";
766 var eval_from_script = script.eval_from_script;
767 if (eval_from_script) {
768 if (eval_from_script.compilation_type == COMPILATION_TYPE_EVAL) {
769 // eval script originated from another eval.
770 eval_origin += " (" + FormatEvalOrigin(eval_from_script) + ")";
772 // eval script originated from "real" source.
773 if (eval_from_script.name) {
774 eval_origin += " (" + eval_from_script.name;
775 var location = eval_from_script.locationFromPosition(
776 script.eval_from_script_position, true);
778 eval_origin += ":" + (location.line + 1);
779 eval_origin += ":" + (location.column + 1);
783 eval_origin += " (unknown source)";
792 function FormatErrorString(error) {
794 return %_CallFunction(error, ErrorToString);
797 return "<error: " + e + ">";
805 function GetStackFrames(raw_stack) {
806 var frames = new InternalArray();
807 var sloppy_frames = raw_stack[0];
808 for (var i = 1; i < raw_stack.length; i += 4) {
809 var recv = raw_stack[i];
810 var fun = raw_stack[i + 1];
811 var code = raw_stack[i + 2];
812 var pc = raw_stack[i + 3];
813 var pos = %_IsSmi(code) ? code : %FunctionGetPositionForOffset(code, pc);
815 frames.push(new CallSite(recv, fun, pos, (sloppy_frames < 0)));
821 // Flag to prevent recursive call of Error.prepareStackTrace.
822 var formatting_custom_stack_trace = false;
825 function FormatStackTrace(obj, raw_stack) {
826 var frames = GetStackFrames(raw_stack);
827 if (IS_FUNCTION(GlobalError.prepareStackTrace) &&
828 !formatting_custom_stack_trace) {
830 %MoveArrayContents(frames, array);
831 formatting_custom_stack_trace = true;
832 var stack_trace = UNDEFINED;
834 stack_trace = GlobalError.prepareStackTrace(obj, array);
836 throw e; // The custom formatting function threw. Rethrow.
838 formatting_custom_stack_trace = false;
843 var lines = new InternalArray();
844 lines.push(FormatErrorString(obj));
845 for (var i = 0; i < frames.length; i++) {
846 var frame = frames[i];
849 line = frame.toString();
852 line = "<error: " + e + ">";
854 // Any code that reaches this point is seriously nasty!
858 lines.push(" at " + line);
860 return %_CallFunction(lines, "\n", ArrayJoin);
864 function GetTypeName(receiver, requireConstructor) {
865 if (IS_NULL_OR_UNDEFINED(receiver)) return null;
866 var constructor = receiver.constructor;
868 return requireConstructor ? null :
869 %_CallFunction(receiver, NoSideEffectsObjectToString);
871 var constructorName = constructor.name;
872 if (!constructorName) {
873 return requireConstructor ? null :
874 %_CallFunction(receiver, NoSideEffectsObjectToString);
876 return constructorName;
880 // Format the stack trace if not yet done, and return it.
881 // Cache the formatted stack trace on the holder.
882 var StackTraceGetter = function() {
883 var formatted_stack_trace = UNDEFINED;
886 var formatted_stack_trace =
887 GET_PRIVATE(holder, formattedStackTraceSymbol);
888 if (IS_UNDEFINED(formatted_stack_trace)) {
889 // No formatted stack trace available.
890 var stack_trace = GET_PRIVATE(holder, stackTraceSymbol);
891 if (IS_UNDEFINED(stack_trace)) {
892 // Neither formatted nor structured stack trace available.
893 // Look further up the prototype chain.
894 holder = %_GetPrototype(holder);
897 formatted_stack_trace = FormatStackTrace(holder, stack_trace);
898 SET_PRIVATE(holder, stackTraceSymbol, UNDEFINED);
899 SET_PRIVATE(holder, formattedStackTraceSymbol, formatted_stack_trace);
901 return formatted_stack_trace;
907 // If the receiver equals the holder, set the formatted stack trace that the
909 var StackTraceSetter = function(v) {
910 if (HAS_PRIVATE(this, stackTraceSymbol)) {
911 SET_PRIVATE(this, stackTraceSymbol, UNDEFINED);
912 SET_PRIVATE(this, formattedStackTraceSymbol, v);
917 // Use a dummy function since we do not actually want to capture a stack trace
918 // when constructing the initial Error prototytpes.
919 var captureStackTrace = function() {};
922 // Define special error type constructors.
923 function DefineError(global, f) {
924 // Store the error function in both the global object
925 // and the runtime object. The function is fetched
926 // from the runtime object when throwing errors from
927 // within the runtime system to avoid strange side
928 // effects when overwriting the error functions from
931 %AddNamedProperty(global, name, f, DONT_ENUM);
932 // Configure the error function.
933 if (name == 'Error') {
934 // The prototype of the Error object must itself be an error.
935 // However, it can't be an instance of the Error object because
936 // it hasn't been properly configured yet. Instead we create a
937 // special not-a-true-error-but-close-enough object.
938 var ErrorPrototype = function() {};
939 %FunctionSetPrototype(ErrorPrototype, GlobalObject.prototype);
940 %FunctionSetInstanceClassName(ErrorPrototype, 'Error');
941 %FunctionSetPrototype(f, new ErrorPrototype());
943 %FunctionSetPrototype(f, new GlobalError());
944 %InternalSetPrototype(f, GlobalError);
946 %FunctionSetInstanceClassName(f, 'Error');
947 %AddNamedProperty(f.prototype, 'constructor', f, DONT_ENUM);
948 %AddNamedProperty(f.prototype, 'name', name, DONT_ENUM);
949 %SetCode(f, function(m) {
950 if (%_IsConstructCall()) {
951 try { captureStackTrace(this, f); } catch (e) { }
952 // Define all the expected properties directly on the error
953 // object. This avoids going through getters and setters defined
954 // on prototype objects.
955 if (!IS_UNDEFINED(m)) {
956 %AddNamedProperty(this, 'message', ToString(m), DONT_ENUM);
966 GlobalError = DefineError(global, function Error() { });
967 GlobalEvalError = DefineError(global, function EvalError() { });
968 GlobalRangeError = DefineError(global, function RangeError() { });
969 GlobalReferenceError = DefineError(global, function ReferenceError() { });
970 GlobalSyntaxError = DefineError(global, function SyntaxError() { });
971 GlobalTypeError = DefineError(global, function TypeError() { });
972 GlobalURIError = DefineError(global, function URIError() { });
974 %AddNamedProperty(GlobalError.prototype, 'message', '', DONT_ENUM);
976 function ErrorToString() {
977 if (!IS_SPEC_OBJECT(this)) {
978 throw MakeTypeError(kCalledOnNonObject, "Error.prototype.toString");
981 return %ErrorToStringRT(this);
984 utils.InstallFunctions(GlobalError.prototype, DONT_ENUM,
985 ['toString', ErrorToString]);
987 $errorToString = ErrorToString;
989 MakeError = function(type, arg0, arg1, arg2) {
990 return MakeGenericError(GlobalError, type, arg0, arg1, arg2);
993 MakeRangeError = function(type, arg0, arg1, arg2) {
994 return MakeGenericError(GlobalRangeError, type, arg0, arg1, arg2);
997 MakeSyntaxError = function(type, arg0, arg1, arg2) {
998 return MakeGenericError(GlobalSyntaxError, type, arg0, arg1, arg2);
1001 MakeTypeError = function(type, arg0, arg1, arg2) {
1002 return MakeGenericError(GlobalTypeError, type, arg0, arg1, arg2);
1005 MakeURIError = function() {
1006 return MakeGenericError(GlobalURIError, kURIMalformed);
1009 // Boilerplate for exceptions for stack overflows. Used from
1010 // Isolate::StackOverflow().
1011 var StackOverflowBoilerplate = MakeRangeError(kStackOverflow);
1012 %DefineAccessorPropertyUnchecked(StackOverflowBoilerplate, 'stack',
1013 StackTraceGetter, StackTraceSetter,
1016 // Define actual captureStackTrace function after everything has been set up.
1017 captureStackTrace = function captureStackTrace(obj, cons_opt) {
1018 // Define accessors first, as this may fail and throw.
1019 ObjectDefineProperty(obj, 'stack', { get: StackTraceGetter,
1020 set: StackTraceSetter,
1021 configurable: true });
1022 %CollectStackTrace(obj, cons_opt ? cons_opt : captureStackTrace);
1025 GlobalError.captureStackTrace = captureStackTrace;
1028 "error_function", GlobalError,
1029 "eval_error_function", GlobalEvalError,
1030 "get_stack_trace_line_fun", GetStackTraceLine,
1031 "make_error_function", MakeGenericError,
1032 "make_range_error", MakeRangeError,
1033 "make_type_error", MakeTypeError,
1034 "message_get_column_number", GetColumnNumber,
1035 "message_get_line_number", GetLineNumber,
1036 "message_get_source_line", GetSourceLine,
1037 "no_side_effect_to_string_fun", NoSideEffectToString,
1038 "range_error_function", GlobalRangeError,
1039 "reference_error_function", GlobalReferenceError,
1040 "stack_overflow_boilerplate", StackOverflowBoilerplate,
1041 "syntax_error_function", GlobalSyntaxError,
1042 "to_detail_string_fun", ToDetailString,
1043 "type_error_function", GlobalTypeError,
1044 "uri_error_function", GlobalURIError,