OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 802 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
813 // See if we can find a unique property on the receiver that holds | 813 // See if we can find a unique property on the receiver that holds |
814 // this function. | 814 // this function. |
815 var ownName = this.fun.name; | 815 var ownName = this.fun.name; |
816 if (ownName && this.receiver && | 816 if (ownName && this.receiver && |
817 (%_CallFunction(this.receiver, | 817 (%_CallFunction(this.receiver, |
818 ownName, | 818 ownName, |
819 ObjectLookupGetter) === this.fun || | 819 ObjectLookupGetter) === this.fun || |
820 %_CallFunction(this.receiver, | 820 %_CallFunction(this.receiver, |
821 ownName, | 821 ownName, |
822 ObjectLookupSetter) === this.fun || | 822 ObjectLookupSetter) === this.fun || |
823 this.receiver[ownName] === this.fun)) { | 823 %GetDataProperty(this.receiver, ownName) === this.fun)) { |
824 // To handle DontEnum properties we guess that the method has | 824 // To handle DontEnum properties we guess that the method has |
825 // the same name as the function. | 825 // the same name as the function. |
826 return ownName; | 826 return ownName; |
827 } | 827 } |
828 var name = null; | 828 var name = null; |
829 for (var prop in this.receiver) { | 829 for (var prop in this.receiver) { |
830 if (%_CallFunction(this.receiver, prop, ObjectLookupGetter) === this.fun || | 830 if (%_CallFunction(this.receiver, prop, ObjectLookupGetter) === this.fun || |
831 %_CallFunction(this.receiver, prop, ObjectLookupSetter) === this.fun || | 831 %_CallFunction(this.receiver, prop, ObjectLookupSetter) === this.fun || |
832 (!%_CallFunction(this.receiver, prop, ObjectLookupGetter) && | 832 %GetDataProperty(this.receiver, prop) === this.fun) { |
833 this.receiver[prop] === this.fun)) { | |
834 // If we find more than one match bail out to avoid confusion. | 833 // If we find more than one match bail out to avoid confusion. |
835 if (name) { | 834 if (name) { |
836 return null; | 835 return null; |
837 } | 836 } |
838 name = prop; | 837 name = prop; |
839 } | 838 } |
840 } | 839 } |
841 if (name) { | 840 if (name) { |
842 return name; | 841 return name; |
843 } | 842 } |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
876 function CallSiteIsNative() { | 875 function CallSiteIsNative() { |
877 var script = %FunctionGetScript(this.fun); | 876 var script = %FunctionGetScript(this.fun); |
878 return script ? (script.type == TYPE_NATIVE) : false; | 877 return script ? (script.type == TYPE_NATIVE) : false; |
879 } | 878 } |
880 | 879 |
881 function CallSiteGetPosition() { | 880 function CallSiteGetPosition() { |
882 return this.pos; | 881 return this.pos; |
883 } | 882 } |
884 | 883 |
885 function CallSiteIsConstructor() { | 884 function CallSiteIsConstructor() { |
886 var constructor = this.receiver ? this.receiver.constructor : null; | 885 var receiver = this.receiver; |
| 886 var constructor = receiver ? %GetDataProperty(receiver, "constructor") : null; |
887 if (!constructor) { | 887 if (!constructor) { |
888 return false; | 888 return false; |
889 } | 889 } |
890 return this.fun === constructor; | 890 return this.fun === constructor; |
891 } | 891 } |
892 | 892 |
893 function CallSiteToString() { | 893 function CallSiteToString() { |
894 var fileName; | 894 var fileName; |
895 var fileLocation = ""; | 895 var fileLocation = ""; |
896 if (this.isNative()) { | 896 if (this.isNative()) { |
(...skipping 29 matching lines...) Expand all Loading... |
926 | 926 |
927 var line = ""; | 927 var line = ""; |
928 var functionName = this.getFunctionName(); | 928 var functionName = this.getFunctionName(); |
929 var addSuffix = true; | 929 var addSuffix = true; |
930 var isConstructor = this.isConstructor(); | 930 var isConstructor = this.isConstructor(); |
931 var isMethodCall = !(this.isToplevel() || isConstructor); | 931 var isMethodCall = !(this.isToplevel() || isConstructor); |
932 if (isMethodCall) { | 932 if (isMethodCall) { |
933 var typeName = GetTypeName(this, true); | 933 var typeName = GetTypeName(this, true); |
934 var methodName = this.getMethodName(); | 934 var methodName = this.getMethodName(); |
935 if (functionName) { | 935 if (functionName) { |
936 if (typeName && functionName.indexOf(typeName) != 0) { | 936 if (typeName && |
| 937 %_CallFunction(functionName, typeName, StringIndexOf) != 0) { |
937 line += typeName + "."; | 938 line += typeName + "."; |
938 } | 939 } |
939 line += functionName; | 940 line += functionName; |
940 if (methodName && functionName.lastIndexOf("." + methodName) != | 941 if (methodName && |
941 functionName.length - methodName.length - 1) { | 942 (%_CallFunction(functionName, "." + methodName, StringIndexOf) != |
| 943 functionName.length - methodName.length - 1)) { |
942 line += " [as " + methodName + "]"; | 944 line += " [as " + methodName + "]"; |
943 } | 945 } |
944 } else { | 946 } else { |
945 line += typeName + "." + (methodName || "<anonymous>"); | 947 line += typeName + "." + (methodName || "<anonymous>"); |
946 } | 948 } |
947 } else if (isConstructor) { | 949 } else if (isConstructor) { |
948 line += "new " + (functionName || "<anonymous>"); | 950 line += "new " + (functionName || "<anonymous>"); |
949 } else if (functionName) { | 951 } else if (functionName) { |
950 line += functionName; | 952 line += functionName; |
951 } else { | 953 } else { |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1009 eval_origin += ")"; | 1011 eval_origin += ")"; |
1010 } else { | 1012 } else { |
1011 eval_origin += " (unknown source)"; | 1013 eval_origin += " (unknown source)"; |
1012 } | 1014 } |
1013 } | 1015 } |
1014 } | 1016 } |
1015 | 1017 |
1016 return eval_origin; | 1018 return eval_origin; |
1017 } | 1019 } |
1018 | 1020 |
1019 function FormatStackTrace(error, frames) { | 1021 |
1020 var lines = []; | 1022 function FormatErrorString(error) { |
1021 try { | 1023 try { |
1022 lines.push(error.toString()); | 1024 return %_CallFunction(error, ErrorToString); |
1023 } catch (e) { | 1025 } catch (e) { |
1024 try { | 1026 try { |
1025 lines.push("<error: " + e + ">"); | 1027 return "<error: " + e + ">"; |
1026 } catch (ee) { | 1028 } catch (ee) { |
1027 lines.push("<error>"); | 1029 return "<error>"; |
1028 } | 1030 } |
1029 } | 1031 } |
| 1032 } |
| 1033 |
| 1034 |
| 1035 function GetStackFrames(raw_stack) { |
| 1036 var frames = new InternalArray(); |
| 1037 for (var i = 0; i < raw_stack.length; i += 4) { |
| 1038 var recv = raw_stack[i]; |
| 1039 var fun = raw_stack[i + 1]; |
| 1040 var code = raw_stack[i + 2]; |
| 1041 var pc = raw_stack[i + 3]; |
| 1042 var pos = %FunctionGetPositionForOffset(code, pc); |
| 1043 frames.push(new CallSite(recv, fun, pos)); |
| 1044 } |
| 1045 return frames; |
| 1046 } |
| 1047 |
| 1048 |
| 1049 function FormatStackTrace(error_string, frames) { |
| 1050 var lines = new InternalArray(); |
| 1051 lines.push(error_string); |
1030 for (var i = 0; i < frames.length; i++) { | 1052 for (var i = 0; i < frames.length; i++) { |
1031 var frame = frames[i]; | 1053 var frame = frames[i]; |
1032 var line; | 1054 var line; |
1033 try { | 1055 try { |
1034 line = frame.toString(); | 1056 line = frame.toString(); |
1035 } catch (e) { | 1057 } catch (e) { |
1036 try { | 1058 try { |
1037 line = "<error: " + e + ">"; | 1059 line = "<error: " + e + ">"; |
1038 } catch (ee) { | 1060 } catch (ee) { |
1039 // Any code that reaches this point is seriously nasty! | 1061 // Any code that reaches this point is seriously nasty! |
1040 line = "<error>"; | 1062 line = "<error>"; |
1041 } | 1063 } |
1042 } | 1064 } |
1043 lines.push(" at " + line); | 1065 lines.push(" at " + line); |
1044 } | 1066 } |
1045 return lines.join("\n"); | 1067 return %_CallFunction(lines, "\n", ArrayJoin); |
1046 } | 1068 } |
1047 | 1069 |
1048 function FormatRawStackTrace(error, raw_stack) { | |
1049 var frames = [ ]; | |
1050 for (var i = 0; i < raw_stack.length; i += 4) { | |
1051 var recv = raw_stack[i]; | |
1052 var fun = raw_stack[i + 1]; | |
1053 var code = raw_stack[i + 2]; | |
1054 var pc = raw_stack[i + 3]; | |
1055 var pos = %FunctionGetPositionForOffset(code, pc); | |
1056 frames.push(new CallSite(recv, fun, pos)); | |
1057 } | |
1058 if (IS_FUNCTION($Error.prepareStackTrace)) { | |
1059 return $Error.prepareStackTrace(error, frames); | |
1060 } else { | |
1061 return FormatStackTrace(error, frames); | |
1062 } | |
1063 } | |
1064 | 1070 |
1065 function GetTypeName(obj, requireConstructor) { | 1071 function GetTypeName(obj, requireConstructor) { |
1066 var constructor = obj.receiver.constructor; | 1072 var constructor = obj.receiver.constructor; |
1067 if (!constructor) { | 1073 if (!constructor) { |
1068 return requireConstructor ? null : | 1074 return requireConstructor ? null : |
1069 %_CallFunction(obj.receiver, ObjectToString); | 1075 %_CallFunction(obj.receiver, ObjectToString); |
1070 } | 1076 } |
1071 var constructorName = constructor.name; | 1077 var constructorName = constructor.name; |
1072 if (!constructorName) { | 1078 if (!constructorName) { |
1073 return requireConstructor ? null : | 1079 return requireConstructor ? null : |
1074 %_CallFunction(obj.receiver, ObjectToString); | 1080 %_CallFunction(obj.receiver, ObjectToString); |
1075 } | 1081 } |
1076 return constructorName; | 1082 return constructorName; |
1077 } | 1083 } |
1078 | 1084 |
| 1085 |
| 1086 // Flag to prevent recursive call of Error.prepareStackTrace. |
| 1087 var formatting_custom_stack_trace = false; |
| 1088 |
| 1089 |
1079 function captureStackTrace(obj, cons_opt) { | 1090 function captureStackTrace(obj, cons_opt) { |
1080 var stackTraceLimit = $Error.stackTraceLimit; | 1091 var stackTraceLimit = $Error.stackTraceLimit; |
1081 if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return; | 1092 if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return; |
1082 if (stackTraceLimit < 0 || stackTraceLimit > 10000) { | 1093 if (stackTraceLimit < 0 || stackTraceLimit > 10000) { |
1083 stackTraceLimit = 10000; | 1094 stackTraceLimit = 10000; |
1084 } | 1095 } |
1085 var raw_stack = %CollectStackTrace(obj, | 1096 var stack = %CollectStackTrace(obj, |
1086 cons_opt ? cons_opt : captureStackTrace, | 1097 cons_opt ? cons_opt : captureStackTrace, |
1087 stackTraceLimit); | 1098 stackTraceLimit); |
| 1099 |
| 1100 // Don't be lazy if the error stack formatting is custom (observable). |
| 1101 if (IS_FUNCTION($Error.prepareStackTrace) && !formatting_custom_stack_trace) { |
| 1102 var array = []; |
| 1103 %MoveArrayContents(GetStackFrames(stack), array); |
| 1104 formatting_custom_stack_trace = true; |
| 1105 try { |
| 1106 obj.stack = $Error.prepareStackTrace(obj, array); |
| 1107 } catch (e) { |
| 1108 throw e; // The custom formatting function threw. Rethrow. |
| 1109 } finally { |
| 1110 formatting_custom_stack_trace = false; |
| 1111 } |
| 1112 return; |
| 1113 } |
| 1114 |
| 1115 var error_string = FormatErrorString(obj); |
1088 // Note that 'obj' and 'this' maybe different when called on objects that | 1116 // Note that 'obj' and 'this' maybe different when called on objects that |
1089 // have the error object on its prototype chain. The getter replaces itself | 1117 // have the error object on its prototype chain. The getter replaces itself |
1090 // with a data property as soon as the stack trace has been formatted. | 1118 // with a data property as soon as the stack trace has been formatted. |
| 1119 // The getter must not change the object layout as it may be called after GC. |
1091 var getter = function() { | 1120 var getter = function() { |
1092 var value = FormatRawStackTrace(obj, raw_stack); | 1121 if (IS_STRING(stack)) return stack; |
1093 %DefineOrRedefineDataProperty(obj, 'stack', value, NONE); | 1122 // Stack is still a raw array awaiting to be formatted. |
1094 return value; | 1123 stack = FormatStackTrace(error_string, GetStackFrames(stack)); |
| 1124 // Release context value. |
| 1125 error_string = void 0; |
| 1126 return stack; |
1095 }; | 1127 }; |
| 1128 %MarkOneShotGetter(getter); |
| 1129 |
1096 // The 'stack' property of the receiver is set as data property. If | 1130 // The 'stack' property of the receiver is set as data property. If |
1097 // the receiver is the same as holder, this accessor pair is replaced. | 1131 // the receiver is the same as holder, this accessor pair is replaced. |
1098 var setter = function(v) { | 1132 var setter = function(v) { |
1099 %DefineOrRedefineDataProperty(this, 'stack', v, NONE); | 1133 %DefineOrRedefineDataProperty(this, 'stack', v, NONE); |
1100 }; | 1134 }; |
1101 | 1135 |
1102 %DefineOrRedefineAccessorProperty(obj, 'stack', getter, setter, DONT_ENUM); | 1136 %DefineOrRedefineAccessorProperty(obj, 'stack', getter, setter, DONT_ENUM); |
1103 } | 1137 } |
1104 | 1138 |
1105 | 1139 |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1232 // Boilerplate for exceptions for stack overflows. Used from | 1266 // Boilerplate for exceptions for stack overflows. Used from |
1233 // Isolate::StackOverflow(). | 1267 // Isolate::StackOverflow(). |
1234 function SetUpStackOverflowBoilerplate() { | 1268 function SetUpStackOverflowBoilerplate() { |
1235 var boilerplate = MakeRangeError('stack_overflow', []); | 1269 var boilerplate = MakeRangeError('stack_overflow', []); |
1236 | 1270 |
1237 // The raw stack trace is stored as hidden property of the copy of this | 1271 // The raw stack trace is stored as hidden property of the copy of this |
1238 // boilerplate error object. Note that the receiver 'this' may not be that | 1272 // boilerplate error object. Note that the receiver 'this' may not be that |
1239 // error object copy, but can be found on the prototype chain of 'this'. | 1273 // error object copy, but can be found on the prototype chain of 'this'. |
1240 // When the stack trace is formatted, this accessor property is replaced by | 1274 // When the stack trace is formatted, this accessor property is replaced by |
1241 // a data property. | 1275 // a data property. |
| 1276 var error_string = boilerplate.name + ": " + boilerplate.message; |
| 1277 |
| 1278 // The getter must not change the object layout as it may be called after GC. |
1242 function getter() { | 1279 function getter() { |
1243 var holder = this; | 1280 var holder = this; |
1244 while (!IS_ERROR(holder)) { | 1281 while (!IS_ERROR(holder)) { |
1245 holder = %GetPrototype(holder); | 1282 holder = %GetPrototype(holder); |
1246 if (holder == null) return MakeSyntaxError('illegal_access', []); | 1283 if (holder == null) return MakeSyntaxError('illegal_access', []); |
1247 } | 1284 } |
1248 var raw_stack = %GetOverflowedRawStackTrace(holder); | 1285 var stack = %GetOverflowedStackTrace(holder); |
1249 var result = IS_ARRAY(raw_stack) ? FormatRawStackTrace(holder, raw_stack) | 1286 if (IS_STRING(stack)) return stack; |
1250 : void 0; | 1287 if (IS_ARRAY(stack)) { |
1251 %DefineOrRedefineDataProperty(holder, 'stack', result, NONE); | 1288 var result = FormatStackTrace(error_string, GetStackFrames(stack)); |
1252 return result; | 1289 %SetOverflowedStackTrace(holder, result); |
| 1290 return result; |
| 1291 } |
| 1292 return void 0; |
1253 } | 1293 } |
| 1294 %MarkOneShotGetter(getter); |
1254 | 1295 |
1255 // The 'stack' property of the receiver is set as data property. If | 1296 // The 'stack' property of the receiver is set as data property. If |
1256 // the receiver is the same as holder, this accessor pair is replaced. | 1297 // the receiver is the same as holder, this accessor pair is replaced. |
1257 function setter(v) { | 1298 function setter(v) { |
1258 %DefineOrRedefineDataProperty(this, 'stack', v, NONE); | 1299 %DefineOrRedefineDataProperty(this, 'stack', v, NONE); |
| 1300 // Release the stack trace that is stored as hidden property, if exists. |
| 1301 %SetOverflowedStackTrace(this, void 0); |
1259 } | 1302 } |
1260 | 1303 |
1261 %DefineOrRedefineAccessorProperty( | 1304 %DefineOrRedefineAccessorProperty( |
1262 boilerplate, 'stack', getter, setter, DONT_ENUM); | 1305 boilerplate, 'stack', getter, setter, DONT_ENUM); |
1263 | 1306 |
1264 return boilerplate; | 1307 return boilerplate; |
1265 } | 1308 } |
1266 | 1309 |
1267 var kStackOverflowBoilerplate = SetUpStackOverflowBoilerplate(); | 1310 var kStackOverflowBoilerplate = SetUpStackOverflowBoilerplate(); |
OLD | NEW |