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 960 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
971 if (*can_be_caught_externally) { | 971 if (*can_be_caught_externally) { |
972 // Only report the exception if the external handler is verbose. | 972 // Only report the exception if the external handler is verbose. |
973 return try_catch_handler()->is_verbose_; | 973 return try_catch_handler()->is_verbose_; |
974 } else { | 974 } else { |
975 // Report the exception if it isn't caught by JavaScript code. | 975 // Report the exception if it isn't caught by JavaScript code. |
976 return handler == NULL; | 976 return handler == NULL; |
977 } | 977 } |
978 } | 978 } |
979 | 979 |
980 | 980 |
| 981 // Traverse prototype chain to find out whether the object is derived from |
| 982 // the Error object. |
981 bool Isolate::IsErrorObject(Handle<Object> obj) { | 983 bool Isolate::IsErrorObject(Handle<Object> obj) { |
982 if (!obj->IsJSObject()) return false; | 984 if (!obj->IsJSObject()) return false; |
983 | 985 |
984 Handle<String> error_key = | 986 Handle<String> error_key = |
985 factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("$Error")); | 987 factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("$Error")); |
986 Handle<Object> error_constructor = Object::GetProperty( | 988 Handle<Object> error_constructor = Object::GetProperty( |
987 js_builtins_object(), error_key).ToHandleChecked(); | 989 js_builtins_object(), error_key).ToHandleChecked(); |
988 | 990 |
989 DisallowHeapAllocation no_gc; | 991 DisallowHeapAllocation no_gc; |
990 for (PrototypeIterator iter(this, *obj, PrototypeIterator::START_AT_RECEIVER); | 992 for (PrototypeIterator iter(this, *obj, PrototypeIterator::START_AT_RECEIVER); |
991 !iter.IsAtEnd(); iter.Advance()) { | 993 !iter.IsAtEnd(); iter.Advance()) { |
992 if (iter.GetCurrent()->IsJSProxy()) return false; | 994 if (iter.GetCurrent()->IsJSProxy()) return false; |
993 if (JSObject::cast(iter.GetCurrent())->map()->constructor() == | 995 if (JSObject::cast(iter.GetCurrent())->map()->constructor() == |
994 *error_constructor) { | 996 *error_constructor) { |
995 return true; | 997 return true; |
996 } | 998 } |
997 } | 999 } |
998 return false; | 1000 return false; |
999 } | 1001 } |
1000 | 1002 |
1001 static int fatal_exception_depth = 0; | 1003 static int fatal_exception_depth = 0; |
1002 | 1004 |
| 1005 |
| 1006 Handle<JSMessageObject> Isolate::CreateMessage(Handle<Object> exception, |
| 1007 MessageLocation* location) { |
| 1008 Handle<JSArray> stack_trace_object; |
| 1009 if (capture_stack_trace_for_uncaught_exceptions_) { |
| 1010 if (IsErrorObject(exception)) { |
| 1011 // We fetch the stack trace that corresponds to this error object. |
| 1012 Handle<Name> key = factory()->detailed_stack_trace_symbol(); |
| 1013 // Look up as own property. If the lookup fails, the exception is |
| 1014 // probably not a valid Error object. In that case, we fall through |
| 1015 // and capture the stack trace at this throw site. |
| 1016 LookupIterator lookup(exception, key, |
| 1017 LookupIterator::OWN_SKIP_INTERCEPTOR); |
| 1018 Handle<Object> stack_trace_property; |
| 1019 if (Object::GetProperty(&lookup).ToHandle(&stack_trace_property) && |
| 1020 stack_trace_property->IsJSArray()) { |
| 1021 stack_trace_object = Handle<JSArray>::cast(stack_trace_property); |
| 1022 } |
| 1023 } |
| 1024 if (stack_trace_object.is_null()) { |
| 1025 // Not an error object, we capture at throw site. |
| 1026 stack_trace_object = CaptureCurrentStackTrace( |
| 1027 stack_trace_for_uncaught_exceptions_frame_limit_, |
| 1028 stack_trace_for_uncaught_exceptions_options_); |
| 1029 } |
| 1030 } |
| 1031 |
| 1032 // If the exception argument is a custom object, turn it into a string |
| 1033 // before throwing as uncaught exception. Note that the pending |
| 1034 // exception object to be set later must not be turned into a string. |
| 1035 if (exception->IsJSObject() && !IsErrorObject(exception)) { |
| 1036 MaybeHandle<Object> maybe_exception = |
| 1037 Execution::ToDetailString(this, exception); |
| 1038 if (!maybe_exception.ToHandle(&exception)) { |
| 1039 exception = |
| 1040 factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("exception")); |
| 1041 } |
| 1042 } |
| 1043 return MessageHandler::MakeMessageObject(this, "uncaught_exception", location, |
| 1044 HandleVector<Object>(&exception, 1), |
| 1045 stack_trace_object); |
| 1046 } |
| 1047 |
| 1048 |
| 1049 void ReportBootstrappingException(Handle<Object> exception, |
| 1050 MessageLocation* location) { |
| 1051 base::OS::PrintError("Exception thrown during bootstrapping\n"); |
| 1052 if (location == NULL || location->script().is_null()) return; |
| 1053 // We are bootstrapping and caught an error where the location is set |
| 1054 // and we have a script for the location. |
| 1055 // In this case we could have an extension (or an internal error |
| 1056 // somewhere) and we print out the line number at which the error occured |
| 1057 // to the console for easier debugging. |
| 1058 int line_number = |
| 1059 location->script()->GetLineNumber(location->start_pos()) + 1; |
| 1060 if (exception->IsString() && location->script()->name()->IsString()) { |
| 1061 base::OS::PrintError( |
| 1062 "Extension or internal compilation error: %s in %s at line %d.\n", |
| 1063 String::cast(*exception)->ToCString().get(), |
| 1064 String::cast(location->script()->name())->ToCString().get(), |
| 1065 line_number); |
| 1066 } else if (location->script()->name()->IsString()) { |
| 1067 base::OS::PrintError( |
| 1068 "Extension or internal compilation error in %s at line %d.\n", |
| 1069 String::cast(location->script()->name())->ToCString().get(), |
| 1070 line_number); |
| 1071 } else { |
| 1072 base::OS::PrintError("Extension or internal compilation error.\n"); |
| 1073 } |
| 1074 #ifdef OBJECT_PRINT |
| 1075 // Since comments and empty lines have been stripped from the source of |
| 1076 // builtins, print the actual source here so that line numbers match. |
| 1077 if (location->script()->source()->IsString()) { |
| 1078 Handle<String> src(String::cast(location->script()->source())); |
| 1079 PrintF("Failing script:\n"); |
| 1080 int len = src->length(); |
| 1081 int line_number = 1; |
| 1082 PrintF("%5d: ", line_number); |
| 1083 for (int i = 0; i < len; i++) { |
| 1084 uint16_t character = src->Get(i); |
| 1085 PrintF("%c", character); |
| 1086 if (character == '\n' && i < len - 2) { |
| 1087 PrintF("%5d: ", ++line_number); |
| 1088 } |
| 1089 } |
| 1090 } |
| 1091 #endif |
| 1092 } |
| 1093 |
| 1094 |
1003 void Isolate::DoThrow(Object* exception, MessageLocation* location) { | 1095 void Isolate::DoThrow(Object* exception, MessageLocation* location) { |
1004 DCHECK(!has_pending_exception()); | 1096 DCHECK(!has_pending_exception()); |
1005 | 1097 |
1006 HandleScope scope(this); | 1098 HandleScope scope(this); |
1007 Handle<Object> exception_handle(exception, this); | 1099 Handle<Object> exception_handle(exception, this); |
1008 | 1100 |
1009 // Determine reporting and whether the exception is caught externally. | 1101 // Determine reporting and whether the exception is caught externally. |
1010 bool catchable_by_javascript = is_catchable_by_javascript(exception); | 1102 bool catchable_by_javascript = is_catchable_by_javascript(exception); |
1011 bool can_be_caught_externally = false; | 1103 bool can_be_caught_externally = false; |
1012 bool should_report_exception = | 1104 bool should_report_exception = |
1013 ShouldReportException(&can_be_caught_externally, catchable_by_javascript); | 1105 ShouldReportException(&can_be_caught_externally, catchable_by_javascript); |
1014 bool report_exception = catchable_by_javascript && should_report_exception; | 1106 bool report_exception = catchable_by_javascript && should_report_exception; |
1015 bool try_catch_needs_message = | 1107 bool try_catch_needs_message = |
1016 can_be_caught_externally && try_catch_handler()->capture_message_; | 1108 can_be_caught_externally && try_catch_handler()->capture_message_; |
1017 bool bootstrapping = bootstrapper()->IsActive(); | |
1018 bool rethrowing_message = thread_local_top()->rethrowing_message_; | 1109 bool rethrowing_message = thread_local_top()->rethrowing_message_; |
1019 | 1110 |
1020 thread_local_top()->rethrowing_message_ = false; | 1111 thread_local_top()->rethrowing_message_ = false; |
1021 | 1112 |
1022 // Notify debugger of exception. | 1113 // Notify debugger of exception. |
1023 if (catchable_by_javascript) { | 1114 if (catchable_by_javascript) { |
1024 debug()->OnThrow(exception_handle, report_exception); | 1115 debug()->OnThrow(exception_handle, report_exception); |
1025 } | 1116 } |
1026 | 1117 |
1027 // Generate the message if required. | 1118 // Generate the message if required. |
1028 if (!rethrowing_message && (report_exception || try_catch_needs_message)) { | 1119 if (!rethrowing_message && (report_exception || try_catch_needs_message)) { |
1029 MessageLocation potential_computed_location; | 1120 MessageLocation potential_computed_location; |
1030 if (location == NULL) { | 1121 if (location == NULL) { |
1031 // If no location was specified we use a computed one instead. | 1122 // If no location was specified we use a computed one instead. |
1032 ComputeLocation(&potential_computed_location); | 1123 ComputeLocation(&potential_computed_location); |
1033 location = &potential_computed_location; | 1124 location = &potential_computed_location; |
1034 } | 1125 } |
1035 // It's not safe to try to make message objects or collect stack traces | |
1036 // while the bootstrapper is active since the infrastructure may not have | |
1037 // been properly initialized. | |
1038 if (!bootstrapping) { | |
1039 Handle<JSArray> stack_trace_object; | |
1040 if (capture_stack_trace_for_uncaught_exceptions_) { | |
1041 if (IsErrorObject(exception_handle)) { | |
1042 // We fetch the stack trace that corresponds to this error object. | |
1043 Handle<Name> key = factory()->detailed_stack_trace_symbol(); | |
1044 // Look up as own property. If the lookup fails, the exception is | |
1045 // probably not a valid Error object. In that case, we fall through | |
1046 // and capture the stack trace at this throw site. | |
1047 LookupIterator lookup(exception_handle, key, | |
1048 LookupIterator::OWN_SKIP_INTERCEPTOR); | |
1049 Handle<Object> stack_trace_property; | |
1050 if (Object::GetProperty(&lookup).ToHandle(&stack_trace_property) && | |
1051 stack_trace_property->IsJSArray()) { | |
1052 stack_trace_object = Handle<JSArray>::cast(stack_trace_property); | |
1053 } | |
1054 } | |
1055 if (stack_trace_object.is_null()) { | |
1056 // Not an error object, we capture at throw site. | |
1057 stack_trace_object = CaptureCurrentStackTrace( | |
1058 stack_trace_for_uncaught_exceptions_frame_limit_, | |
1059 stack_trace_for_uncaught_exceptions_options_); | |
1060 } | |
1061 } | |
1062 | 1126 |
1063 Handle<Object> exception_arg = exception_handle; | 1127 if (bootstrapper()->IsActive()) { |
1064 // If the exception argument is a custom object, turn it into a string | 1128 // It's not safe to try to make message objects or collect stack traces |
1065 // before throwing as uncaught exception. Note that the pending | 1129 // while the bootstrapper is active since the infrastructure may not have |
1066 // exception object to be set later must not be turned into a string. | 1130 // been properly initialized. |
1067 if (exception_arg->IsJSObject() && !IsErrorObject(exception_arg)) { | 1131 ReportBootstrappingException(exception_handle, location); |
1068 MaybeHandle<Object> maybe_exception = | 1132 } else { |
1069 Execution::ToDetailString(this, exception_arg); | 1133 Handle<Object> message_obj = CreateMessage(exception_handle, location); |
1070 if (!maybe_exception.ToHandle(&exception_arg)) { | 1134 |
1071 exception_arg = factory()->InternalizeOneByteString( | |
1072 STATIC_CHAR_VECTOR("exception")); | |
1073 } | |
1074 } | |
1075 Handle<Object> message_obj = MessageHandler::MakeMessageObject( | |
1076 this, | |
1077 "uncaught_exception", | |
1078 location, | |
1079 HandleVector<Object>(&exception_arg, 1), | |
1080 stack_trace_object); | |
1081 thread_local_top()->pending_message_obj_ = *message_obj; | 1135 thread_local_top()->pending_message_obj_ = *message_obj; |
1082 if (location != NULL) { | 1136 if (location != NULL) { |
1083 thread_local_top()->pending_message_script_ = *location->script(); | 1137 thread_local_top()->pending_message_script_ = *location->script(); |
1084 thread_local_top()->pending_message_start_pos_ = location->start_pos(); | 1138 thread_local_top()->pending_message_start_pos_ = location->start_pos(); |
1085 thread_local_top()->pending_message_end_pos_ = location->end_pos(); | 1139 thread_local_top()->pending_message_end_pos_ = location->end_pos(); |
1086 } | 1140 } |
1087 | 1141 |
1088 // If the abort-on-uncaught-exception flag is specified, abort on any | 1142 // If the abort-on-uncaught-exception flag is specified, abort on any |
1089 // exception not caught by JavaScript, even when an external handler is | 1143 // exception not caught by JavaScript, even when an external handler is |
1090 // present. This flag is intended for use by JavaScript developers, so | 1144 // present. This flag is intended for use by JavaScript developers, so |
1091 // print a user-friendly stack trace (not an internal one). | 1145 // print a user-friendly stack trace (not an internal one). |
1092 if (fatal_exception_depth == 0 && | 1146 if (fatal_exception_depth == 0 && FLAG_abort_on_uncaught_exception && |
1093 FLAG_abort_on_uncaught_exception && | |
1094 (report_exception || can_be_caught_externally)) { | 1147 (report_exception || can_be_caught_externally)) { |
1095 fatal_exception_depth++; | 1148 fatal_exception_depth++; |
1096 PrintF(stderr, | 1149 PrintF(stderr, "%s\n\nFROM\n", |
1097 "%s\n\nFROM\n", | |
1098 MessageHandler::GetLocalizedMessage(this, message_obj).get()); | 1150 MessageHandler::GetLocalizedMessage(this, message_obj).get()); |
1099 PrintCurrentStackTrace(stderr); | 1151 PrintCurrentStackTrace(stderr); |
1100 base::OS::Abort(); | 1152 base::OS::Abort(); |
1101 } | 1153 } |
1102 } else if (location != NULL && !location->script().is_null()) { | |
1103 // We are bootstrapping and caught an error where the location is set | |
1104 // and we have a script for the location. | |
1105 // In this case we could have an extension (or an internal error | |
1106 // somewhere) and we print out the line number at which the error occured | |
1107 // to the console for easier debugging. | |
1108 int line_number = | |
1109 location->script()->GetLineNumber(location->start_pos()) + 1; | |
1110 if (exception->IsString() && location->script()->name()->IsString()) { | |
1111 base::OS::PrintError( | |
1112 "Extension or internal compilation error: %s in %s at line %d.\n", | |
1113 String::cast(exception)->ToCString().get(), | |
1114 String::cast(location->script()->name())->ToCString().get(), | |
1115 line_number); | |
1116 } else if (location->script()->name()->IsString()) { | |
1117 base::OS::PrintError( | |
1118 "Extension or internal compilation error in %s at line %d.\n", | |
1119 String::cast(location->script()->name())->ToCString().get(), | |
1120 line_number); | |
1121 } else { | |
1122 base::OS::PrintError("Extension or internal compilation error.\n"); | |
1123 } | |
1124 #ifdef OBJECT_PRINT | |
1125 // Since comments and empty lines have been stripped from the source of | |
1126 // builtins, print the actual source here so that line numbers match. | |
1127 if (location->script()->source()->IsString()) { | |
1128 Handle<String> src(String::cast(location->script()->source())); | |
1129 PrintF("Failing script:\n"); | |
1130 int len = src->length(); | |
1131 int line_number = 1; | |
1132 PrintF("%5d: ", line_number); | |
1133 for (int i = 0; i < len; i++) { | |
1134 uint16_t character = src->Get(i); | |
1135 PrintF("%c", character); | |
1136 if (character == '\n' && i < len - 2) { | |
1137 PrintF("%5d: ", ++line_number); | |
1138 } | |
1139 } | |
1140 } | |
1141 #endif | |
1142 } | 1154 } |
1143 } | 1155 } |
1144 | 1156 |
1145 // Save the message for reporting if the the exception remains uncaught. | 1157 // Save the message for reporting if the the exception remains uncaught. |
1146 thread_local_top()->has_pending_message_ = report_exception; | 1158 thread_local_top()->has_pending_message_ = report_exception; |
1147 | 1159 |
1148 // Do not forget to clean catcher_ if currently thrown exception cannot | 1160 // Do not forget to clean catcher_ if currently thrown exception cannot |
1149 // be caught. If necessary, ReThrow will update the catcher. | 1161 // be caught. If necessary, ReThrow will update the catcher. |
1150 thread_local_top()->catcher_ = can_be_caught_externally ? | 1162 thread_local_top()->catcher_ = can_be_caught_externally ? |
1151 try_catch_handler() : NULL; | 1163 try_catch_handler() : NULL; |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1307 | 1319 |
1308 Handle<Object> Isolate::GetPromiseOnStackOnThrow() { | 1320 Handle<Object> Isolate::GetPromiseOnStackOnThrow() { |
1309 Handle<Object> undefined = factory()->undefined_value(); | 1321 Handle<Object> undefined = factory()->undefined_value(); |
1310 ThreadLocalTop* tltop = thread_local_top(); | 1322 ThreadLocalTop* tltop = thread_local_top(); |
1311 if (tltop->promise_on_stack_ == NULL) return undefined; | 1323 if (tltop->promise_on_stack_ == NULL) return undefined; |
1312 StackHandler* promise_try = tltop->promise_on_stack_->handler(); | 1324 StackHandler* promise_try = tltop->promise_on_stack_->handler(); |
1313 // Find the top-most try-catch handler. | 1325 // Find the top-most try-catch handler. |
1314 StackHandler* handler = StackHandler::FromAddress(Isolate::handler(tltop)); | 1326 StackHandler* handler = StackHandler::FromAddress(Isolate::handler(tltop)); |
1315 do { | 1327 do { |
1316 if (handler == promise_try) { | 1328 if (handler == promise_try) { |
1317 // Mark the pushed try-catch handler to prevent a later duplicate event | |
1318 // triggered with the following reject. | |
1319 return tltop->promise_on_stack_->promise(); | 1329 return tltop->promise_on_stack_->promise(); |
1320 } | 1330 } |
1321 handler = handler->next(); | 1331 handler = handler->next(); |
1322 // Throwing inside a Promise can be intercepted by an inner try-catch, so | 1332 // Throwing inside a Promise can be intercepted by an inner try-catch, so |
1323 // we stop at the first try-catch handler. | 1333 // we stop at the first try-catch handler. |
1324 } while (handler != NULL && !handler->is_catch()); | 1334 } while (handler != NULL && !handler->is_catch()); |
1325 return undefined; | 1335 return undefined; |
1326 } | 1336 } |
1327 | 1337 |
1328 | 1338 |
(...skipping 942 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2271 if (run_microtasks) RunMicrotasks(); | 2281 if (run_microtasks) RunMicrotasks(); |
2272 // Fire callbacks. Increase call depth to prevent recursive callbacks. | 2282 // Fire callbacks. Increase call depth to prevent recursive callbacks. |
2273 v8::Isolate::SuppressMicrotaskExecutionScope suppress( | 2283 v8::Isolate::SuppressMicrotaskExecutionScope suppress( |
2274 reinterpret_cast<v8::Isolate*>(this)); | 2284 reinterpret_cast<v8::Isolate*>(this)); |
2275 for (int i = 0; i < call_completed_callbacks_.length(); i++) { | 2285 for (int i = 0; i < call_completed_callbacks_.length(); i++) { |
2276 call_completed_callbacks_.at(i)(); | 2286 call_completed_callbacks_.at(i)(); |
2277 } | 2287 } |
2278 } | 2288 } |
2279 | 2289 |
2280 | 2290 |
| 2291 void Isolate::SetPromiseRejectCallback(PromiseRejectCallback callback) { |
| 2292 promise_reject_callback_ = callback; |
| 2293 } |
| 2294 |
| 2295 |
| 2296 void Isolate::ReportPromiseReject(Handle<JSObject> promise, |
| 2297 Handle<Object> value, |
| 2298 v8::PromiseRejectEvent event) { |
| 2299 if (promise_reject_callback_ == NULL) return; |
| 2300 promise_reject_callback_(v8::Utils::PromiseToLocal(promise), |
| 2301 v8::Utils::ToLocal(value), event); |
| 2302 } |
| 2303 |
| 2304 |
2281 void Isolate::EnqueueMicrotask(Handle<Object> microtask) { | 2305 void Isolate::EnqueueMicrotask(Handle<Object> microtask) { |
2282 DCHECK(microtask->IsJSFunction() || microtask->IsCallHandlerInfo()); | 2306 DCHECK(microtask->IsJSFunction() || microtask->IsCallHandlerInfo()); |
2283 Handle<FixedArray> queue(heap()->microtask_queue(), this); | 2307 Handle<FixedArray> queue(heap()->microtask_queue(), this); |
2284 int num_tasks = pending_microtask_count(); | 2308 int num_tasks = pending_microtask_count(); |
2285 DCHECK(num_tasks <= queue->length()); | 2309 DCHECK(num_tasks <= queue->length()); |
2286 if (num_tasks == 0) { | 2310 if (num_tasks == 0) { |
2287 queue = factory()->NewFixedArray(8); | 2311 queue = factory()->NewFixedArray(8); |
2288 heap()->set_microtask_queue(*queue); | 2312 heap()->set_microtask_queue(*queue); |
2289 } else if (num_tasks == queue->length()) { | 2313 } else if (num_tasks == queue->length()) { |
2290 queue = FixedArray::CopySize(queue, num_tasks * 2); | 2314 queue = FixedArray::CopySize(queue, num_tasks * 2); |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2387 if (prev_ && prev_->Intercept(flag)) return true; | 2411 if (prev_ && prev_->Intercept(flag)) return true; |
2388 // Then check whether this scope intercepts. | 2412 // Then check whether this scope intercepts. |
2389 if ((flag & intercept_mask_)) { | 2413 if ((flag & intercept_mask_)) { |
2390 intercepted_flags_ |= flag; | 2414 intercepted_flags_ |= flag; |
2391 return true; | 2415 return true; |
2392 } | 2416 } |
2393 return false; | 2417 return false; |
2394 } | 2418 } |
2395 | 2419 |
2396 } } // namespace v8::internal | 2420 } } // namespace v8::internal |
OLD | NEW |