Index: src/top.cc |
diff --git a/src/top.cc b/src/top.cc |
index 3364c0d511c92b1b2c50fba0c9873a8ea571c3a3..83d7de3afee6a43904ed7182cb7d75b8883bdad7 100644 |
--- a/src/top.cc |
+++ b/src/top.cc |
@@ -333,7 +333,7 @@ void Top::RegisterTryCatchHandler(v8::TryCatch* that) { |
void Top::UnregisterTryCatchHandler(v8::TryCatch* that) { |
- ASSERT(thread_local_.TryCatchHandler() == that); |
+ ASSERT(try_catch_handler() == that); |
thread_local_.set_try_catch_handler_address( |
reinterpret_cast<Address>(that->next_)); |
thread_local_.catcher_ = NULL; |
@@ -732,6 +732,13 @@ Failure* Top::Throw(Object* exception, MessageLocation* location) { |
Failure* Top::ReThrow(MaybeObject* exception, MessageLocation* location) { |
+ bool can_be_caught_externally = false; |
+ ShouldReportException(&can_be_caught_externally, |
+ is_catchable_by_javascript(exception)); |
+ if (can_be_caught_externally) { |
+ thread_local_.catcher_ = try_catch_handler(); |
+ } |
+ |
// Set the exception being re-thrown. |
set_pending_exception(exception); |
return Failure::Exception(); |
@@ -807,7 +814,7 @@ void Top::ComputeLocation(MessageLocation* target) { |
} |
-bool Top::ShouldReportException(bool* is_caught_externally, |
+bool Top::ShouldReportException(bool* can_be_caught_externally, |
bool catchable_by_javascript) { |
// Find the top-most try-catch handler. |
StackHandler* handler = |
@@ -823,13 +830,13 @@ bool Top::ShouldReportException(bool* is_caught_externally, |
// The exception has been externally caught if and only if there is |
// an external handler which is on top of the top-most try-catch |
// handler. |
- *is_caught_externally = external_handler_address != NULL && |
+ *can_be_caught_externally = external_handler_address != NULL && |
(handler == NULL || handler->address() > external_handler_address || |
!catchable_by_javascript); |
- if (*is_caught_externally) { |
+ if (*can_be_caught_externally) { |
// Only report the exception if the external handler is verbose. |
- return thread_local_.TryCatchHandler()->is_verbose_; |
+ return try_catch_handler()->is_verbose_; |
} else { |
// Report the exception if it isn't caught by JavaScript code. |
return handler == NULL; |
@@ -848,14 +855,12 @@ void Top::DoThrow(MaybeObject* exception, |
Handle<Object> exception_handle(exception_object); |
// Determine reporting and whether the exception is caught externally. |
- bool is_out_of_memory = exception == Failure::OutOfMemoryException(); |
- bool is_termination_exception = exception == Heap::termination_exception(); |
- bool catchable_by_javascript = !is_termination_exception && !is_out_of_memory; |
+ bool catchable_by_javascript = is_catchable_by_javascript(exception); |
// Only real objects can be caught by JS. |
ASSERT(!catchable_by_javascript || is_object); |
- bool is_caught_externally = false; |
+ bool can_be_caught_externally = false; |
bool should_report_exception = |
- ShouldReportException(&is_caught_externally, catchable_by_javascript); |
+ ShouldReportException(&can_be_caught_externally, catchable_by_javascript); |
bool report_exception = catchable_by_javascript && should_report_exception; |
#ifdef ENABLE_DEBUGGER_SUPPORT |
@@ -869,8 +874,8 @@ void Top::DoThrow(MaybeObject* exception, |
Handle<Object> message_obj; |
MessageLocation potential_computed_location; |
bool try_catch_needs_message = |
- is_caught_externally && |
- thread_local_.TryCatchHandler()->capture_message_; |
+ can_be_caught_externally && |
+ try_catch_handler()->capture_message_; |
if (report_exception || try_catch_needs_message) { |
if (location == NULL) { |
// If no location was specified we use a computed one instead |
@@ -908,8 +913,8 @@ void Top::DoThrow(MaybeObject* exception, |
} |
} |
- if (is_caught_externally) { |
- thread_local_.catcher_ = thread_local_.TryCatchHandler(); |
+ if (can_be_caught_externally) { |
+ thread_local_.catcher_ = try_catch_handler(); |
} |
// NOTE: Notifying the debugger or generating the message |
@@ -925,22 +930,63 @@ void Top::DoThrow(MaybeObject* exception, |
} |
+bool Top::IsExternallyCaught() { |
+ ASSERT(has_pending_exception()); |
+ |
+ if ((thread_local_.catcher_ == NULL) || |
+ (try_catch_handler() != thread_local_.catcher_)) { |
+ // When throwing the exception, we found no v8::TryCatch |
+ // which should care about this exception. |
+ return false; |
+ } |
+ |
+ if (!is_catchable_by_javascript(pending_exception())) { |
+ return true; |
+ } |
+ |
+ // Get the address of the external handler so we can compare the address to |
+ // determine which one is closer to the top of the stack. |
+ Address external_handler_address = thread_local_.try_catch_handler_address(); |
+ ASSERT(external_handler_address != NULL); |
+ |
+ // The exception has been externally caught if and only if there is |
+ // an external handler which is on top of the top-most try-finally |
+ // handler. |
+ // There should be no try-catch blocks as they would prohibit us from |
+ // finding external catcher in the first place (see catcher_ check above). |
+ // |
+ // Note, that finally clause would rethrow an exception unless it's |
+ // aborted by jumps in control flow like return, break, etc. and we'll |
+ // have another chances to set proper v8::TryCatch. |
+ StackHandler* handler = |
+ StackHandler::FromAddress(Top::handler(Top::GetCurrentThread())); |
+ while (handler != NULL && handler->address() < external_handler_address) { |
+ ASSERT(!handler->is_try_catch()); |
+ if (handler->is_try_finally()) return false; |
+ |
+ handler = handler->next(); |
+ } |
+ |
+ return true; |
+} |
+ |
+ |
void Top::ReportPendingMessages() { |
ASSERT(has_pending_exception()); |
- setup_external_caught(); |
// If the pending exception is OutOfMemoryException set out_of_memory in |
// the global context. Note: We have to mark the global context here |
// since the GenerateThrowOutOfMemory stub cannot make a RuntimeCall to |
// set it. |
- bool external_caught = thread_local_.external_caught_exception_; |
+ bool external_caught = IsExternallyCaught(); |
+ thread_local_.external_caught_exception_ = external_caught; |
HandleScope scope; |
if (thread_local_.pending_exception_ == Failure::OutOfMemoryException()) { |
context()->mark_out_of_memory(); |
} else if (thread_local_.pending_exception_ == |
Heap::termination_exception()) { |
if (external_caught) { |
- thread_local_.TryCatchHandler()->can_continue_ = false; |
- thread_local_.TryCatchHandler()->exception_ = Heap::null_value(); |
+ try_catch_handler()->can_continue_ = false; |
+ try_catch_handler()->exception_ = Heap::null_value(); |
} |
} else { |
// At this point all non-object (failure) exceptions have |
@@ -949,9 +995,8 @@ void Top::ReportPendingMessages() { |
Handle<Object> exception(pending_exception_object); |
thread_local_.external_caught_exception_ = false; |
if (external_caught) { |
- thread_local_.TryCatchHandler()->can_continue_ = true; |
- thread_local_.TryCatchHandler()->exception_ = |
- thread_local_.pending_exception_; |
+ try_catch_handler()->can_continue_ = true; |
+ try_catch_handler()->exception_ = thread_local_.pending_exception_; |
if (!thread_local_.pending_message_obj_->IsTheHole()) { |
try_catch_handler()->message_ = thread_local_.pending_message_obj_; |
} |