| 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 <fstream> // NOLINT(readability/streams) | 7 #include <fstream> // NOLINT(readability/streams) |
| 8 #include <sstream> | 8 #include <sstream> |
| 9 | 9 |
| 10 #include "src/v8.h" | 10 #include "src/v8.h" |
| (...skipping 818 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 829 | 829 |
| 830 Object* Isolate::StackOverflow() { | 830 Object* Isolate::StackOverflow() { |
| 831 HandleScope scope(this); | 831 HandleScope scope(this); |
| 832 // At this point we cannot create an Error object using its javascript | 832 // At this point we cannot create an Error object using its javascript |
| 833 // constructor. Instead, we copy the pre-constructed boilerplate and | 833 // constructor. Instead, we copy the pre-constructed boilerplate and |
| 834 // attach the stack trace as a hidden property. | 834 // attach the stack trace as a hidden property. |
| 835 Handle<String> key = factory()->stack_overflow_string(); | 835 Handle<String> key = factory()->stack_overflow_string(); |
| 836 Handle<JSObject> boilerplate = Handle<JSObject>::cast( | 836 Handle<JSObject> boilerplate = Handle<JSObject>::cast( |
| 837 Object::GetProperty(js_builtins_object(), key).ToHandleChecked()); | 837 Object::GetProperty(js_builtins_object(), key).ToHandleChecked()); |
| 838 Handle<JSObject> exception = factory()->CopyJSObject(boilerplate); | 838 Handle<JSObject> exception = factory()->CopyJSObject(boilerplate); |
| 839 DoThrow(*exception, NULL); | 839 Throw(*exception, nullptr); |
| 840 | 840 |
| 841 CaptureAndSetSimpleStackTrace(exception, factory()->undefined_value()); | 841 CaptureAndSetSimpleStackTrace(exception, factory()->undefined_value()); |
| 842 return heap()->exception(); | 842 return heap()->exception(); |
| 843 } | 843 } |
| 844 | 844 |
| 845 | 845 |
| 846 Object* Isolate::TerminateExecution() { | 846 Object* Isolate::TerminateExecution() { |
| 847 DoThrow(heap_.termination_exception(), NULL); | 847 return Throw(heap_.termination_exception(), nullptr); |
| 848 return heap()->exception(); | |
| 849 } | 848 } |
| 850 | 849 |
| 851 | 850 |
| 852 void Isolate::CancelTerminateExecution() { | 851 void Isolate::CancelTerminateExecution() { |
| 853 if (try_catch_handler()) { | 852 if (try_catch_handler()) { |
| 854 try_catch_handler()->has_terminated_ = false; | 853 try_catch_handler()->has_terminated_ = false; |
| 855 } | 854 } |
| 856 if (has_pending_exception() && | 855 if (has_pending_exception() && |
| 857 pending_exception() == heap_.termination_exception()) { | 856 pending_exception() == heap_.termination_exception()) { |
| 858 thread_local_top()->external_caught_exception_ = false; | 857 thread_local_top()->external_caught_exception_ = false; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 883 entry = api_interrupts_queue_.front(); | 882 entry = api_interrupts_queue_.front(); |
| 884 api_interrupts_queue_.pop(); | 883 api_interrupts_queue_.pop(); |
| 885 } | 884 } |
| 886 VMState<EXTERNAL> state(this); | 885 VMState<EXTERNAL> state(this); |
| 887 HandleScope handle_scope(this); | 886 HandleScope handle_scope(this); |
| 888 entry.first(reinterpret_cast<v8::Isolate*>(this), entry.second); | 887 entry.first(reinterpret_cast<v8::Isolate*>(this), entry.second); |
| 889 } | 888 } |
| 890 } | 889 } |
| 891 | 890 |
| 892 | 891 |
| 892 void ReportBootstrappingException(Handle<Object> exception, |
| 893 MessageLocation* location) { |
| 894 base::OS::PrintError("Exception thrown during bootstrapping\n"); |
| 895 if (location == NULL || location->script().is_null()) return; |
| 896 // We are bootstrapping and caught an error where the location is set |
| 897 // and we have a script for the location. |
| 898 // In this case we could have an extension (or an internal error |
| 899 // somewhere) and we print out the line number at which the error occured |
| 900 // to the console for easier debugging. |
| 901 int line_number = |
| 902 location->script()->GetLineNumber(location->start_pos()) + 1; |
| 903 if (exception->IsString() && location->script()->name()->IsString()) { |
| 904 base::OS::PrintError( |
| 905 "Extension or internal compilation error: %s in %s at line %d.\n", |
| 906 String::cast(*exception)->ToCString().get(), |
| 907 String::cast(location->script()->name())->ToCString().get(), |
| 908 line_number); |
| 909 } else if (location->script()->name()->IsString()) { |
| 910 base::OS::PrintError( |
| 911 "Extension or internal compilation error in %s at line %d.\n", |
| 912 String::cast(location->script()->name())->ToCString().get(), |
| 913 line_number); |
| 914 } else { |
| 915 base::OS::PrintError("Extension or internal compilation error.\n"); |
| 916 } |
| 917 #ifdef OBJECT_PRINT |
| 918 // Since comments and empty lines have been stripped from the source of |
| 919 // builtins, print the actual source here so that line numbers match. |
| 920 if (location->script()->source()->IsString()) { |
| 921 Handle<String> src(String::cast(location->script()->source())); |
| 922 PrintF("Failing script:\n"); |
| 923 int len = src->length(); |
| 924 int line_number = 1; |
| 925 PrintF("%5d: ", line_number); |
| 926 for (int i = 0; i < len; i++) { |
| 927 uint16_t character = src->Get(i); |
| 928 PrintF("%c", character); |
| 929 if (character == '\n' && i < len - 2) { |
| 930 PrintF("%5d: ", ++line_number); |
| 931 } |
| 932 } |
| 933 } |
| 934 #endif |
| 935 } |
| 936 |
| 937 |
| 938 namespace { |
| 939 |
| 940 // Only use by Isolate::Throw for --abort-on-uncaught-exception. |
| 941 int fatal_exception_depth = 0; |
| 942 |
| 943 } // namespace |
| 944 |
| 945 |
| 893 Object* Isolate::Throw(Object* exception, MessageLocation* location) { | 946 Object* Isolate::Throw(Object* exception, MessageLocation* location) { |
| 894 DoThrow(exception, location); | 947 DCHECK(!has_pending_exception()); |
| 948 |
| 949 HandleScope scope(this); |
| 950 Handle<Object> exception_handle(exception, this); |
| 951 |
| 952 // Determine reporting and whether the exception is caught externally. |
| 953 bool catchable_by_javascript = is_catchable_by_javascript(exception); |
| 954 bool can_be_caught_externally = false; |
| 955 bool should_report_exception = |
| 956 ShouldReportException(&can_be_caught_externally, catchable_by_javascript); |
| 957 bool report_exception = catchable_by_javascript && should_report_exception; |
| 958 bool try_catch_needs_message = |
| 959 can_be_caught_externally && try_catch_handler()->capture_message_; |
| 960 bool rethrowing_message = thread_local_top()->rethrowing_message_; |
| 961 |
| 962 thread_local_top()->rethrowing_message_ = false; |
| 963 |
| 964 // Notify debugger of exception. |
| 965 if (catchable_by_javascript) { |
| 966 debug()->OnThrow(exception_handle, report_exception); |
| 967 } |
| 968 |
| 969 // Generate the message if required. |
| 970 if (!rethrowing_message && (report_exception || try_catch_needs_message)) { |
| 971 MessageLocation potential_computed_location; |
| 972 if (location == NULL) { |
| 973 // If no location was specified we use a computed one instead. |
| 974 ComputeLocation(&potential_computed_location); |
| 975 location = &potential_computed_location; |
| 976 } |
| 977 |
| 978 if (bootstrapper()->IsActive()) { |
| 979 // It's not safe to try to make message objects or collect stack traces |
| 980 // while the bootstrapper is active since the infrastructure may not have |
| 981 // been properly initialized. |
| 982 ReportBootstrappingException(exception_handle, location); |
| 983 } else { |
| 984 Handle<Object> message_obj = CreateMessage(exception_handle, location); |
| 985 |
| 986 thread_local_top()->pending_message_obj_ = *message_obj; |
| 987 thread_local_top()->pending_message_script_ = *location->script(); |
| 988 thread_local_top()->pending_message_start_pos_ = location->start_pos(); |
| 989 thread_local_top()->pending_message_end_pos_ = location->end_pos(); |
| 990 |
| 991 // If the abort-on-uncaught-exception flag is specified, abort on any |
| 992 // exception not caught by JavaScript, even when an external handler is |
| 993 // present. This flag is intended for use by JavaScript developers, so |
| 994 // print a user-friendly stack trace (not an internal one). |
| 995 if (fatal_exception_depth == 0 && FLAG_abort_on_uncaught_exception && |
| 996 (report_exception || can_be_caught_externally)) { |
| 997 fatal_exception_depth++; |
| 998 PrintF(stderr, "%s\n\nFROM\n", |
| 999 MessageHandler::GetLocalizedMessage(this, message_obj).get()); |
| 1000 PrintCurrentStackTrace(stderr); |
| 1001 base::OS::Abort(); |
| 1002 } |
| 1003 } |
| 1004 } |
| 1005 |
| 1006 // Save the message for reporting if the the exception remains uncaught. |
| 1007 thread_local_top()->has_pending_message_ = report_exception; |
| 1008 |
| 1009 // Do not forget to clean catcher_ if currently thrown exception cannot |
| 1010 // be caught. If necessary, ReThrow will update the catcher. |
| 1011 thread_local_top()->catcher_ = |
| 1012 can_be_caught_externally ? try_catch_handler() : NULL; |
| 1013 |
| 1014 set_pending_exception(*exception_handle); |
| 895 return heap()->exception(); | 1015 return heap()->exception(); |
| 896 } | 1016 } |
| 897 | 1017 |
| 898 | 1018 |
| 899 Object* Isolate::ReThrow(Object* exception) { | 1019 Object* Isolate::ReThrow(Object* exception) { |
| 900 bool can_be_caught_externally = false; | 1020 bool can_be_caught_externally = false; |
| 901 bool catchable_by_javascript = is_catchable_by_javascript(exception); | 1021 bool catchable_by_javascript = is_catchable_by_javascript(exception); |
| 902 ShouldReportException(&can_be_caught_externally, catchable_by_javascript); | 1022 ShouldReportException(&can_be_caught_externally, catchable_by_javascript); |
| 903 | 1023 |
| 904 thread_local_top()->catcher_ = can_be_caught_externally ? | 1024 thread_local_top()->catcher_ = can_be_caught_externally ? |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1114 !iter.IsAtEnd(); iter.Advance()) { | 1234 !iter.IsAtEnd(); iter.Advance()) { |
| 1115 if (iter.GetCurrent()->IsJSProxy()) return false; | 1235 if (iter.GetCurrent()->IsJSProxy()) return false; |
| 1116 if (JSObject::cast(iter.GetCurrent())->map()->GetConstructor() == | 1236 if (JSObject::cast(iter.GetCurrent())->map()->GetConstructor() == |
| 1117 *error_constructor) { | 1237 *error_constructor) { |
| 1118 return true; | 1238 return true; |
| 1119 } | 1239 } |
| 1120 } | 1240 } |
| 1121 return false; | 1241 return false; |
| 1122 } | 1242 } |
| 1123 | 1243 |
| 1124 static int fatal_exception_depth = 0; | |
| 1125 | |
| 1126 | 1244 |
| 1127 Handle<JSMessageObject> Isolate::CreateMessage(Handle<Object> exception, | 1245 Handle<JSMessageObject> Isolate::CreateMessage(Handle<Object> exception, |
| 1128 MessageLocation* location) { | 1246 MessageLocation* location) { |
| 1129 Handle<JSArray> stack_trace_object; | 1247 Handle<JSArray> stack_trace_object; |
| 1130 MessageLocation potential_computed_location; | 1248 MessageLocation potential_computed_location; |
| 1131 if (capture_stack_trace_for_uncaught_exceptions_) { | 1249 if (capture_stack_trace_for_uncaught_exceptions_) { |
| 1132 if (IsErrorObject(exception)) { | 1250 if (IsErrorObject(exception)) { |
| 1133 // We fetch the stack trace that corresponds to this error object. | 1251 // We fetch the stack trace that corresponds to this error object. |
| 1134 // If the lookup fails, the exception is probably not a valid Error | 1252 // If the lookup fails, the exception is probably not a valid Error |
| 1135 // object. In that case, we fall through and capture the stack trace | 1253 // object. In that case, we fall through and capture the stack trace |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1165 exception = | 1283 exception = |
| 1166 factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("exception")); | 1284 factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("exception")); |
| 1167 } | 1285 } |
| 1168 } | 1286 } |
| 1169 return MessageHandler::MakeMessageObject(this, "uncaught_exception", location, | 1287 return MessageHandler::MakeMessageObject(this, "uncaught_exception", location, |
| 1170 HandleVector<Object>(&exception, 1), | 1288 HandleVector<Object>(&exception, 1), |
| 1171 stack_trace_object); | 1289 stack_trace_object); |
| 1172 } | 1290 } |
| 1173 | 1291 |
| 1174 | 1292 |
| 1175 void ReportBootstrappingException(Handle<Object> exception, | |
| 1176 MessageLocation* location) { | |
| 1177 base::OS::PrintError("Exception thrown during bootstrapping\n"); | |
| 1178 if (location == NULL || location->script().is_null()) return; | |
| 1179 // We are bootstrapping and caught an error where the location is set | |
| 1180 // and we have a script for the location. | |
| 1181 // In this case we could have an extension (or an internal error | |
| 1182 // somewhere) and we print out the line number at which the error occured | |
| 1183 // to the console for easier debugging. | |
| 1184 int line_number = | |
| 1185 location->script()->GetLineNumber(location->start_pos()) + 1; | |
| 1186 if (exception->IsString() && location->script()->name()->IsString()) { | |
| 1187 base::OS::PrintError( | |
| 1188 "Extension or internal compilation error: %s in %s at line %d.\n", | |
| 1189 String::cast(*exception)->ToCString().get(), | |
| 1190 String::cast(location->script()->name())->ToCString().get(), | |
| 1191 line_number); | |
| 1192 } else if (location->script()->name()->IsString()) { | |
| 1193 base::OS::PrintError( | |
| 1194 "Extension or internal compilation error in %s at line %d.\n", | |
| 1195 String::cast(location->script()->name())->ToCString().get(), | |
| 1196 line_number); | |
| 1197 } else { | |
| 1198 base::OS::PrintError("Extension or internal compilation error.\n"); | |
| 1199 } | |
| 1200 #ifdef OBJECT_PRINT | |
| 1201 // Since comments and empty lines have been stripped from the source of | |
| 1202 // builtins, print the actual source here so that line numbers match. | |
| 1203 if (location->script()->source()->IsString()) { | |
| 1204 Handle<String> src(String::cast(location->script()->source())); | |
| 1205 PrintF("Failing script:\n"); | |
| 1206 int len = src->length(); | |
| 1207 int line_number = 1; | |
| 1208 PrintF("%5d: ", line_number); | |
| 1209 for (int i = 0; i < len; i++) { | |
| 1210 uint16_t character = src->Get(i); | |
| 1211 PrintF("%c", character); | |
| 1212 if (character == '\n' && i < len - 2) { | |
| 1213 PrintF("%5d: ", ++line_number); | |
| 1214 } | |
| 1215 } | |
| 1216 } | |
| 1217 #endif | |
| 1218 } | |
| 1219 | |
| 1220 | |
| 1221 void Isolate::DoThrow(Object* exception, MessageLocation* location) { | |
| 1222 DCHECK(!has_pending_exception()); | |
| 1223 | |
| 1224 HandleScope scope(this); | |
| 1225 Handle<Object> exception_handle(exception, this); | |
| 1226 | |
| 1227 // Determine reporting and whether the exception is caught externally. | |
| 1228 bool catchable_by_javascript = is_catchable_by_javascript(exception); | |
| 1229 bool can_be_caught_externally = false; | |
| 1230 bool should_report_exception = | |
| 1231 ShouldReportException(&can_be_caught_externally, catchable_by_javascript); | |
| 1232 bool report_exception = catchable_by_javascript && should_report_exception; | |
| 1233 bool try_catch_needs_message = | |
| 1234 can_be_caught_externally && try_catch_handler()->capture_message_; | |
| 1235 bool rethrowing_message = thread_local_top()->rethrowing_message_; | |
| 1236 | |
| 1237 thread_local_top()->rethrowing_message_ = false; | |
| 1238 | |
| 1239 // Notify debugger of exception. | |
| 1240 if (catchable_by_javascript) { | |
| 1241 debug()->OnThrow(exception_handle, report_exception); | |
| 1242 } | |
| 1243 | |
| 1244 // Generate the message if required. | |
| 1245 if (!rethrowing_message && (report_exception || try_catch_needs_message)) { | |
| 1246 MessageLocation potential_computed_location; | |
| 1247 if (location == NULL) { | |
| 1248 // If no location was specified we use a computed one instead. | |
| 1249 ComputeLocation(&potential_computed_location); | |
| 1250 location = &potential_computed_location; | |
| 1251 } | |
| 1252 | |
| 1253 if (bootstrapper()->IsActive()) { | |
| 1254 // It's not safe to try to make message objects or collect stack traces | |
| 1255 // while the bootstrapper is active since the infrastructure may not have | |
| 1256 // been properly initialized. | |
| 1257 ReportBootstrappingException(exception_handle, location); | |
| 1258 } else { | |
| 1259 Handle<Object> message_obj = CreateMessage(exception_handle, location); | |
| 1260 | |
| 1261 thread_local_top()->pending_message_obj_ = *message_obj; | |
| 1262 thread_local_top()->pending_message_script_ = *location->script(); | |
| 1263 thread_local_top()->pending_message_start_pos_ = location->start_pos(); | |
| 1264 thread_local_top()->pending_message_end_pos_ = location->end_pos(); | |
| 1265 | |
| 1266 // If the abort-on-uncaught-exception flag is specified, abort on any | |
| 1267 // exception not caught by JavaScript, even when an external handler is | |
| 1268 // present. This flag is intended for use by JavaScript developers, so | |
| 1269 // print a user-friendly stack trace (not an internal one). | |
| 1270 if (fatal_exception_depth == 0 && FLAG_abort_on_uncaught_exception && | |
| 1271 (report_exception || can_be_caught_externally)) { | |
| 1272 fatal_exception_depth++; | |
| 1273 PrintF(stderr, "%s\n\nFROM\n", | |
| 1274 MessageHandler::GetLocalizedMessage(this, message_obj).get()); | |
| 1275 PrintCurrentStackTrace(stderr); | |
| 1276 base::OS::Abort(); | |
| 1277 } | |
| 1278 } | |
| 1279 } | |
| 1280 | |
| 1281 // Save the message for reporting if the the exception remains uncaught. | |
| 1282 thread_local_top()->has_pending_message_ = report_exception; | |
| 1283 | |
| 1284 // Do not forget to clean catcher_ if currently thrown exception cannot | |
| 1285 // be caught. If necessary, ReThrow will update the catcher. | |
| 1286 thread_local_top()->catcher_ = can_be_caught_externally ? | |
| 1287 try_catch_handler() : NULL; | |
| 1288 | |
| 1289 set_pending_exception(*exception_handle); | |
| 1290 } | |
| 1291 | |
| 1292 | |
| 1293 bool Isolate::HasExternalTryCatch() { | 1293 bool Isolate::HasExternalTryCatch() { |
| 1294 DCHECK(has_pending_exception()); | 1294 DCHECK(has_pending_exception()); |
| 1295 | 1295 |
| 1296 return (thread_local_top()->catcher_ != NULL) && | 1296 return (thread_local_top()->catcher_ != NULL) && |
| 1297 (try_catch_handler() == thread_local_top()->catcher_); | 1297 (try_catch_handler() == thread_local_top()->catcher_); |
| 1298 } | 1298 } |
| 1299 | 1299 |
| 1300 | 1300 |
| 1301 bool Isolate::IsFinallyOnTop() { | 1301 bool Isolate::IsFinallyOnTop() { |
| 1302 // Get the address of the external handler so we can compare the address to | 1302 // Get the address of the external handler so we can compare the address to |
| (...skipping 1248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2551 if (prev_ && prev_->Intercept(flag)) return true; | 2551 if (prev_ && prev_->Intercept(flag)) return true; |
| 2552 // Then check whether this scope intercepts. | 2552 // Then check whether this scope intercepts. |
| 2553 if ((flag & intercept_mask_)) { | 2553 if ((flag & intercept_mask_)) { |
| 2554 intercepted_flags_ |= flag; | 2554 intercepted_flags_ |= flag; |
| 2555 return true; | 2555 return true; |
| 2556 } | 2556 } |
| 2557 return false; | 2557 return false; |
| 2558 } | 2558 } |
| 2559 | 2559 |
| 2560 } } // namespace v8::internal | 2560 } } // namespace v8::internal |
| OLD | NEW |