OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <stdlib.h> | 5 #include <stdlib.h> |
6 | 6 |
7 #include "src/v8.h" | 7 #include "src/v8.h" |
8 | 8 |
9 #include "src/ast.h" | 9 #include "src/ast.h" |
10 #include "src/base/platform/platform.h" | 10 #include "src/base/platform/platform.h" |
(...skipping 988 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
999 if (JSObject::cast(iter.GetCurrent())->map()->constructor() == | 999 if (JSObject::cast(iter.GetCurrent())->map()->constructor() == |
1000 *error_constructor) { | 1000 *error_constructor) { |
1001 return true; | 1001 return true; |
1002 } | 1002 } |
1003 } | 1003 } |
1004 return false; | 1004 return false; |
1005 } | 1005 } |
1006 | 1006 |
1007 static int fatal_exception_depth = 0; | 1007 static int fatal_exception_depth = 0; |
1008 | 1008 |
| 1009 |
| 1010 Handle<JSMessageObject> Isolate::CreateMessage(Handle<Object> exception, |
| 1011 MessageLocation* location, |
| 1012 Handle<JSObject> promise) { |
| 1013 Handle<JSArray> stack_trace_object; |
| 1014 if (capture_stack_trace_for_uncaught_exceptions_) { |
| 1015 if (IsErrorObject(exception)) { |
| 1016 // We fetch the stack trace that corresponds to this error object. |
| 1017 Handle<Name> key = factory()->detailed_stack_trace_symbol(); |
| 1018 // Look up as own property. If the lookup fails, the exception is |
| 1019 // probably not a valid Error object. In that case, we fall through |
| 1020 // and capture the stack trace at this throw site. |
| 1021 LookupIterator lookup(exception, key, |
| 1022 LookupIterator::OWN_SKIP_INTERCEPTOR); |
| 1023 Handle<Object> stack_trace_property; |
| 1024 if (Object::GetProperty(&lookup).ToHandle(&stack_trace_property) && |
| 1025 stack_trace_property->IsJSArray()) { |
| 1026 stack_trace_object = Handle<JSArray>::cast(stack_trace_property); |
| 1027 } |
| 1028 } |
| 1029 if (stack_trace_object.is_null()) { |
| 1030 // Not an error object, we capture at throw site. |
| 1031 stack_trace_object = CaptureCurrentStackTrace( |
| 1032 stack_trace_for_uncaught_exceptions_frame_limit_, |
| 1033 stack_trace_for_uncaught_exceptions_options_); |
| 1034 } |
| 1035 } |
| 1036 |
| 1037 // If the exception argument is a custom object, turn it into a string |
| 1038 // before throwing as uncaught exception. Note that the pending |
| 1039 // exception object to be set later must not be turned into a string. |
| 1040 if (exception->IsJSObject() && !IsErrorObject(exception)) { |
| 1041 MaybeHandle<Object> maybe_exception = |
| 1042 Execution::ToDetailString(this, exception); |
| 1043 if (!maybe_exception.ToHandle(&exception)) { |
| 1044 exception = |
| 1045 factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("exception")); |
| 1046 } |
| 1047 } |
| 1048 return MessageHandler::MakeMessageObject(this, "uncaught_exception", location, |
| 1049 HandleVector<Object>(&exception, 1), |
| 1050 promise, stack_trace_object); |
| 1051 } |
| 1052 |
| 1053 |
| 1054 void ReportBootstrappingException(Handle<Object> exception, |
| 1055 MessageLocation* location) { |
| 1056 base::OS::PrintError("Exception thrown during bootstrapping\n"); |
| 1057 if (location == NULL || location->script().is_null()) return; |
| 1058 // We are bootstrapping and caught an error where the location is set |
| 1059 // and we have a script for the location. |
| 1060 // In this case we could have an extension (or an internal error |
| 1061 // somewhere) and we print out the line number at which the error occured |
| 1062 // to the console for easier debugging. |
| 1063 int line_number = |
| 1064 location->script()->GetLineNumber(location->start_pos()) + 1; |
| 1065 if (exception->IsString() && location->script()->name()->IsString()) { |
| 1066 base::OS::PrintError( |
| 1067 "Extension or internal compilation error: %s in %s at line %d.\n", |
| 1068 String::cast(*exception)->ToCString().get(), |
| 1069 String::cast(location->script()->name())->ToCString().get(), |
| 1070 line_number); |
| 1071 } else if (location->script()->name()->IsString()) { |
| 1072 base::OS::PrintError( |
| 1073 "Extension or internal compilation error in %s at line %d.\n", |
| 1074 String::cast(location->script()->name())->ToCString().get(), |
| 1075 line_number); |
| 1076 } else { |
| 1077 base::OS::PrintError("Extension or internal compilation error.\n"); |
| 1078 } |
| 1079 #ifdef OBJECT_PRINT |
| 1080 // Since comments and empty lines have been stripped from the source of |
| 1081 // builtins, print the actual source here so that line numbers match. |
| 1082 if (location->script()->source()->IsString()) { |
| 1083 Handle<String> src(String::cast(location->script()->source())); |
| 1084 PrintF("Failing script:\n"); |
| 1085 int len = src->length(); |
| 1086 int line_number = 1; |
| 1087 PrintF("%5d: ", line_number); |
| 1088 for (int i = 0; i < len; i++) { |
| 1089 uint16_t character = src->Get(i); |
| 1090 PrintF("%c", character); |
| 1091 if (character == '\n' && i < len - 2) { |
| 1092 PrintF("%5d: ", ++line_number); |
| 1093 } |
| 1094 } |
| 1095 } |
| 1096 #endif |
| 1097 } |
| 1098 |
| 1099 |
1009 void Isolate::DoThrow(Object* exception, MessageLocation* location) { | 1100 void Isolate::DoThrow(Object* exception, MessageLocation* location) { |
1010 DCHECK(!has_pending_exception()); | 1101 DCHECK(!has_pending_exception()); |
1011 | 1102 |
1012 HandleScope scope(this); | 1103 HandleScope scope(this); |
1013 Handle<Object> exception_handle(exception, this); | 1104 Handle<Object> exception_handle(exception, this); |
1014 | 1105 |
1015 // Determine reporting and whether the exception is caught externally. | 1106 // Determine reporting and whether the exception is caught externally. |
1016 bool catchable_by_javascript = is_catchable_by_javascript(exception); | 1107 bool catchable_by_javascript = is_catchable_by_javascript(exception); |
1017 bool can_be_caught_externally = false; | 1108 bool can_be_caught_externally = false; |
1018 bool should_report_exception = | 1109 bool should_report_exception = |
1019 ShouldReportException(&can_be_caught_externally, catchable_by_javascript); | 1110 ShouldReportException(&can_be_caught_externally, catchable_by_javascript); |
1020 bool report_exception = catchable_by_javascript && should_report_exception; | 1111 bool report_exception = catchable_by_javascript && should_report_exception; |
1021 bool try_catch_needs_message = | 1112 bool try_catch_needs_message = |
1022 can_be_caught_externally && try_catch_handler()->capture_message_; | 1113 can_be_caught_externally && try_catch_handler()->capture_message_; |
1023 bool bootstrapping = bootstrapper()->IsActive(); | |
1024 bool rethrowing_message = thread_local_top()->rethrowing_message_; | 1114 bool rethrowing_message = thread_local_top()->rethrowing_message_; |
1025 | 1115 |
1026 thread_local_top()->rethrowing_message_ = false; | 1116 thread_local_top()->rethrowing_message_ = false; |
1027 | 1117 |
| 1118 Handle<Object> promise = GetPromiseOnStackOnThrow(); |
1028 // Notify debugger of exception. | 1119 // Notify debugger of exception. |
1029 if (catchable_by_javascript) { | 1120 if (catchable_by_javascript) { |
1030 debug()->OnThrow(exception_handle, report_exception); | 1121 debug()->OnThrow(exception_handle, promise, report_exception); |
1031 } | 1122 } |
1032 | 1123 |
1033 // Generate the message if required. | 1124 // Generate the message if required. |
1034 if (!rethrowing_message && (report_exception || try_catch_needs_message)) { | 1125 if (!rethrowing_message && (report_exception || try_catch_needs_message)) { |
1035 MessageLocation potential_computed_location; | 1126 MessageLocation potential_computed_location; |
1036 if (location == NULL) { | 1127 if (location == NULL) { |
1037 // If no location was specified we use a computed one instead. | 1128 // If no location was specified we use a computed one instead. |
1038 ComputeLocation(&potential_computed_location); | 1129 ComputeLocation(&potential_computed_location); |
1039 location = &potential_computed_location; | 1130 location = &potential_computed_location; |
1040 } | 1131 } |
1041 // It's not safe to try to make message objects or collect stack traces | |
1042 // while the bootstrapper is active since the infrastructure may not have | |
1043 // been properly initialized. | |
1044 if (!bootstrapping) { | |
1045 Handle<JSArray> stack_trace_object; | |
1046 if (capture_stack_trace_for_uncaught_exceptions_) { | |
1047 if (IsErrorObject(exception_handle)) { | |
1048 // We fetch the stack trace that corresponds to this error object. | |
1049 Handle<Name> key = factory()->detailed_stack_trace_symbol(); | |
1050 // Look up as own property. If the lookup fails, the exception is | |
1051 // probably not a valid Error object. In that case, we fall through | |
1052 // and capture the stack trace at this throw site. | |
1053 LookupIterator lookup(exception_handle, key, | |
1054 LookupIterator::OWN_SKIP_INTERCEPTOR); | |
1055 Handle<Object> stack_trace_property; | |
1056 if (Object::GetProperty(&lookup).ToHandle(&stack_trace_property) && | |
1057 stack_trace_property->IsJSArray()) { | |
1058 stack_trace_object = Handle<JSArray>::cast(stack_trace_property); | |
1059 } | |
1060 } | |
1061 if (stack_trace_object.is_null()) { | |
1062 // Not an error object, we capture at throw site. | |
1063 stack_trace_object = CaptureCurrentStackTrace( | |
1064 stack_trace_for_uncaught_exceptions_frame_limit_, | |
1065 stack_trace_for_uncaught_exceptions_options_); | |
1066 } | |
1067 } | |
1068 | 1132 |
1069 Handle<Object> exception_arg = exception_handle; | 1133 if (bootstrapper()->IsActive()) { |
1070 // If the exception argument is a custom object, turn it into a string | 1134 // It's not safe to try to make message objects or collect stack traces |
1071 // before throwing as uncaught exception. Note that the pending | 1135 // while the bootstrapper is active since the infrastructure may not have |
1072 // exception object to be set later must not be turned into a string. | 1136 // been properly initialized. |
1073 if (exception_arg->IsJSObject() && !IsErrorObject(exception_arg)) { | 1137 ReportBootstrappingException(exception_handle, location); |
1074 MaybeHandle<Object> maybe_exception = | 1138 } else { |
1075 Execution::ToDetailString(this, exception_arg); | 1139 Handle<Object> message_obj = CreateMessage(exception_handle, location); |
1076 if (!maybe_exception.ToHandle(&exception_arg)) { | 1140 |
1077 exception_arg = factory()->InternalizeOneByteString( | |
1078 STATIC_CHAR_VECTOR("exception")); | |
1079 } | |
1080 } | |
1081 Handle<Object> message_obj = MessageHandler::MakeMessageObject( | |
1082 this, | |
1083 "uncaught_exception", | |
1084 location, | |
1085 HandleVector<Object>(&exception_arg, 1), | |
1086 stack_trace_object); | |
1087 thread_local_top()->pending_message_obj_ = *message_obj; | 1141 thread_local_top()->pending_message_obj_ = *message_obj; |
1088 if (location != NULL) { | 1142 if (location != NULL) { |
1089 thread_local_top()->pending_message_script_ = *location->script(); | 1143 thread_local_top()->pending_message_script_ = *location->script(); |
1090 thread_local_top()->pending_message_start_pos_ = location->start_pos(); | 1144 thread_local_top()->pending_message_start_pos_ = location->start_pos(); |
1091 thread_local_top()->pending_message_end_pos_ = location->end_pos(); | 1145 thread_local_top()->pending_message_end_pos_ = location->end_pos(); |
1092 } | 1146 } |
1093 | 1147 |
1094 // If the abort-on-uncaught-exception flag is specified, abort on any | 1148 // If the abort-on-uncaught-exception flag is specified, abort on any |
1095 // exception not caught by JavaScript, even when an external handler is | 1149 // exception not caught by JavaScript, even when an external handler is |
1096 // present. This flag is intended for use by JavaScript developers, so | 1150 // present. This flag is intended for use by JavaScript developers, so |
1097 // print a user-friendly stack trace (not an internal one). | 1151 // print a user-friendly stack trace (not an internal one). |
1098 if (fatal_exception_depth == 0 && | 1152 if (fatal_exception_depth == 0 && FLAG_abort_on_uncaught_exception && |
1099 FLAG_abort_on_uncaught_exception && | |
1100 (report_exception || can_be_caught_externally)) { | 1153 (report_exception || can_be_caught_externally)) { |
1101 fatal_exception_depth++; | 1154 fatal_exception_depth++; |
1102 PrintF(stderr, | 1155 PrintF(stderr, "%s\n\nFROM\n", |
1103 "%s\n\nFROM\n", | |
1104 MessageHandler::GetLocalizedMessage(this, message_obj).get()); | 1156 MessageHandler::GetLocalizedMessage(this, message_obj).get()); |
1105 PrintCurrentStackTrace(stderr); | 1157 PrintCurrentStackTrace(stderr); |
1106 base::OS::Abort(); | 1158 base::OS::Abort(); |
1107 } | 1159 } |
1108 } else if (location != NULL && !location->script().is_null()) { | 1160 } |
1109 // We are bootstrapping and caught an error where the location is set | 1161 } else if (!can_be_caught_externally) { |
1110 // and we have a script for the location. | 1162 // Only if not intercepted externally by a TryCatch this exception may |
1111 // In this case we could have an extension (or an internal error | 1163 // reject a promise. |
1112 // somewhere) and we print out the line number at which the error occured | 1164 if (!promise->IsUndefined()) { |
1113 // to the console for easier debugging. | 1165 Handle<JSObject> jspromise = Handle<JSObject>::cast(promise); |
1114 int line_number = | 1166 ReportPromiseReject(jspromise, exception_handle, location); |
1115 location->script()->GetLineNumber(location->start_pos()) + 1; | 1167 // Mark the promise as already having triggered a message. |
1116 if (exception->IsString() && location->script()->name()->IsString()) { | 1168 Handle<Symbol> key = factory()->promise_debug_symbol(); |
1117 base::OS::PrintError( | 1169 Handle<Object> value = factory()->true_value(); |
1118 "Extension or internal compilation error: %s in %s at line %d.\n", | 1170 JSObject::SetProperty(jspromise, key, value, STRICT); |
1119 String::cast(exception)->ToCString().get(), | |
1120 String::cast(location->script()->name())->ToCString().get(), | |
1121 line_number); | |
1122 } else if (location->script()->name()->IsString()) { | |
1123 base::OS::PrintError( | |
1124 "Extension or internal compilation error in %s at line %d.\n", | |
1125 String::cast(location->script()->name())->ToCString().get(), | |
1126 line_number); | |
1127 } else { | |
1128 base::OS::PrintError("Extension or internal compilation error.\n"); | |
1129 } | |
1130 #ifdef OBJECT_PRINT | |
1131 // Since comments and empty lines have been stripped from the source of | |
1132 // builtins, print the actual source here so that line numbers match. | |
1133 if (location->script()->source()->IsString()) { | |
1134 Handle<String> src(String::cast(location->script()->source())); | |
1135 PrintF("Failing script:\n"); | |
1136 int len = src->length(); | |
1137 int line_number = 1; | |
1138 PrintF("%5d: ", line_number); | |
1139 for (int i = 0; i < len; i++) { | |
1140 uint16_t character = src->Get(i); | |
1141 PrintF("%c", character); | |
1142 if (character == '\n' && i < len - 2) { | |
1143 PrintF("%5d: ", ++line_number); | |
1144 } | |
1145 } | |
1146 } | |
1147 #endif | |
1148 } | 1171 } |
1149 } | 1172 } |
1150 | 1173 |
| 1174 set_pending_exception(*exception_handle); |
| 1175 |
1151 // Save the message for reporting if the the exception remains uncaught. | 1176 // Save the message for reporting if the the exception remains uncaught. |
1152 thread_local_top()->has_pending_message_ = report_exception; | 1177 thread_local_top()->has_pending_message_ = report_exception; |
1153 | 1178 |
1154 // Do not forget to clean catcher_ if currently thrown exception cannot | 1179 // Do not forget to clean catcher_ if currently thrown exception cannot |
1155 // be caught. If necessary, ReThrow will update the catcher. | 1180 // be caught. If necessary, ReThrow will update the catcher. |
1156 thread_local_top()->catcher_ = can_be_caught_externally ? | 1181 thread_local_top()->catcher_ = |
1157 try_catch_handler() : NULL; | 1182 can_be_caught_externally ? try_catch_handler() : NULL; |
1158 | |
1159 set_pending_exception(*exception_handle); | |
1160 } | 1183 } |
1161 | 1184 |
1162 | 1185 |
| 1186 void Isolate::ReportPromiseReject(Handle<JSObject> promise, |
| 1187 Handle<Object> exception, |
| 1188 MessageLocation* location) { |
| 1189 if (!FLAG_report_promise_reject) return; |
| 1190 Handle<Object> uncaught; |
| 1191 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
| 1192 this, uncaught, i::Execution::PromiseHasRejectHandler(this, promise), |
| 1193 /* void */); |
| 1194 if (uncaught->IsTrue()) return; // Promise has reject handler. |
| 1195 |
| 1196 MessageLocation potential_computed_location; |
| 1197 if (location == NULL) { |
| 1198 // If no location was specified we use a computed one instead. |
| 1199 ComputeLocation(&potential_computed_location); |
| 1200 location = &potential_computed_location; |
| 1201 } |
| 1202 Handle<JSMessageObject> message = CreateMessage(exception, location, promise); |
| 1203 set_pending_exception(*exception); |
| 1204 MessageHandler::ReportMessage(this, location, message); |
| 1205 clear_pending_exception(); |
| 1206 } |
| 1207 |
| 1208 |
1163 bool Isolate::HasExternalTryCatch() { | 1209 bool Isolate::HasExternalTryCatch() { |
1164 DCHECK(has_pending_exception()); | 1210 DCHECK(has_pending_exception()); |
1165 | 1211 |
1166 return (thread_local_top()->catcher_ != NULL) && | 1212 return (thread_local_top()->catcher_ != NULL) && |
1167 (try_catch_handler() == thread_local_top()->catcher_); | 1213 (try_catch_handler() == thread_local_top()->catcher_); |
1168 } | 1214 } |
1169 | 1215 |
1170 | 1216 |
1171 bool Isolate::IsFinallyOnTop() { | 1217 bool Isolate::IsFinallyOnTop() { |
1172 // Get the address of the external handler so we can compare the address to | 1218 // Get the address of the external handler so we can compare the address to |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1313 | 1359 |
1314 Handle<Object> Isolate::GetPromiseOnStackOnThrow() { | 1360 Handle<Object> Isolate::GetPromiseOnStackOnThrow() { |
1315 Handle<Object> undefined = factory()->undefined_value(); | 1361 Handle<Object> undefined = factory()->undefined_value(); |
1316 ThreadLocalTop* tltop = thread_local_top(); | 1362 ThreadLocalTop* tltop = thread_local_top(); |
1317 if (tltop->promise_on_stack_ == NULL) return undefined; | 1363 if (tltop->promise_on_stack_ == NULL) return undefined; |
1318 StackHandler* promise_try = tltop->promise_on_stack_->handler(); | 1364 StackHandler* promise_try = tltop->promise_on_stack_->handler(); |
1319 // Find the top-most try-catch handler. | 1365 // Find the top-most try-catch handler. |
1320 StackHandler* handler = StackHandler::FromAddress(Isolate::handler(tltop)); | 1366 StackHandler* handler = StackHandler::FromAddress(Isolate::handler(tltop)); |
1321 do { | 1367 do { |
1322 if (handler == promise_try) { | 1368 if (handler == promise_try) { |
1323 // Mark the pushed try-catch handler to prevent a later duplicate event | |
1324 // triggered with the following reject. | |
1325 return tltop->promise_on_stack_->promise(); | 1369 return tltop->promise_on_stack_->promise(); |
1326 } | 1370 } |
1327 handler = handler->next(); | 1371 handler = handler->next(); |
1328 // Throwing inside a Promise can be intercepted by an inner try-catch, so | 1372 // Throwing inside a Promise can be intercepted by an inner try-catch, so |
1329 // we stop at the first try-catch handler. | 1373 // we stop at the first try-catch handler. |
1330 } while (handler != NULL && !handler->is_catch()); | 1374 } while (handler != NULL && !handler->is_catch()); |
1331 return undefined; | 1375 return undefined; |
1332 } | 1376 } |
1333 | 1377 |
1334 | 1378 |
(...skipping 1045 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2380 if (prev_ && prev_->Intercept(flag)) return true; | 2424 if (prev_ && prev_->Intercept(flag)) return true; |
2381 // Then check whether this scope intercepts. | 2425 // Then check whether this scope intercepts. |
2382 if ((flag & intercept_mask_)) { | 2426 if ((flag & intercept_mask_)) { |
2383 intercepted_flags_ |= flag; | 2427 intercepted_flags_ |= flag; |
2384 return true; | 2428 return true; |
2385 } | 2429 } |
2386 return false; | 2430 return false; |
2387 } | 2431 } |
2388 | 2432 |
2389 } } // namespace v8::internal | 2433 } } // namespace v8::internal |
OLD | NEW |