From cc2f01d31ffaaf5b615cd033741cb96697b1c2ab Mon Sep 17 00:00:00 2001 From: "yangguo@chromium.org" Date: Mon, 1 Jul 2013 10:54:39 +0000 Subject: [PATCH] Restore message when rethrowing in TryCatch. Based on a patch contributed by Andrew Paprocki . R=jkummerow@chromium.org BUG= TEST=cctest/test-api/TryCatchNestedSyntax Review URL: https://codereview.chromium.org/17694002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15408 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- include/v8.h | 5 ++++- src/api.cc | 25 ++++++++++++++++------ src/isolate.cc | 56 ++++++++++++++++++++++++++++++++++++++----------- src/isolate.h | 8 +++++-- test/cctest/test-api.cc | 41 ++++++++++++++++++++++++++++++++++++ 5 files changed, 114 insertions(+), 21 deletions(-) diff --git a/include/v8.h b/include/v8.h index cf01684..c4b22e3 100644 --- a/include/v8.h +++ b/include/v8.h @@ -4823,7 +4823,10 @@ class V8EXPORT TryCatch { v8::internal::Isolate* isolate_; void* next_; void* exception_; - void* message_; + void* message_obj_; + void* message_script_; + int message_start_pos_; + int message_end_pos_; bool is_verbose_ : 1; bool can_continue_ : 1; bool capture_message_ : 1; diff --git a/src/api.cc b/src/api.cc index edffca1..1bd8c27 100644 --- a/src/api.cc +++ b/src/api.cc @@ -2092,13 +2092,12 @@ void Script::SetData(v8::Handle data) { v8::TryCatch::TryCatch() : isolate_(i::Isolate::Current()), next_(isolate_->try_catch_handler_address()), - exception_(isolate_->heap()->the_hole_value()), - message_(i::Smi::FromInt(0)), is_verbose_(false), can_continue_(true), capture_message_(true), rethrow_(false), has_terminated_(false) { + Reset(); isolate_->RegisterTryCatchHandler(this); } @@ -2108,8 +2107,17 @@ v8::TryCatch::~TryCatch() { if (rethrow_) { v8::HandleScope scope(reinterpret_cast(isolate_)); v8::Local exc = v8::Local::New(Exception()); + if (HasCaught() && capture_message_) { + // If an exception was caught and rethrow_ is indicated, the saved + // message, script, and location need to be restored to Isolate TLS + // for reuse. capture_message_ needs to be disabled so that DoThrow() + // does not create a new message. + isolate_->thread_local_top()->rethrowing_message_ = true; + isolate_->RestorePendingMessageFromTryCatch(this); + } isolate_->UnregisterTryCatchHandler(this); v8::ThrowException(exc); + ASSERT(!isolate_->thread_local_top()->rethrowing_message_); } else { isolate_->UnregisterTryCatchHandler(this); } @@ -2170,8 +2178,9 @@ v8::Local v8::TryCatch::StackTrace() const { v8::Local v8::TryCatch::Message() const { ASSERT(isolate_ == i::Isolate::Current()); - if (HasCaught() && message_ != i::Smi::FromInt(0)) { - i::Object* message = reinterpret_cast(message_); + i::Object* message = reinterpret_cast(message_obj_); + ASSERT(message->IsJSMessageObject() || message->IsTheHole()); + if (HasCaught() && !message->IsTheHole()) { return v8::Utils::MessageToLocal(i::Handle(message, isolate_)); } else { return v8::Local(); @@ -2181,8 +2190,12 @@ v8::Local v8::TryCatch::Message() const { void v8::TryCatch::Reset() { ASSERT(isolate_ == i::Isolate::Current()); - exception_ = isolate_->heap()->the_hole_value(); - message_ = i::Smi::FromInt(0); + i::Object* the_hole = isolate_->heap()->the_hole_value(); + exception_ = the_hole; + message_obj_ = the_hole; + message_script_ = the_hole; + message_start_pos_ = 0; + message_end_pos_ = 0; } diff --git a/src/isolate.cc b/src/isolate.cc index e67eb0c..0f393f7 100644 --- a/src/isolate.cc +++ b/src/isolate.cc @@ -107,6 +107,7 @@ void ThreadLocalTop::InitializeInternal() { // is complete. pending_exception_ = NULL; has_pending_message_ = false; + rethrowing_message_ = false; pending_message_obj_ = NULL; pending_message_script_ = NULL; scheduled_exception_ = NULL; @@ -486,7 +487,8 @@ void Isolate::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) { block != NULL; block = TRY_CATCH_FROM_ADDRESS(block->next_)) { v->VisitPointer(BitCast(&(block->exception_))); - v->VisitPointer(BitCast(&(block->message_))); + v->VisitPointer(BitCast(&(block->message_obj_))); + v->VisitPointer(BitCast(&(block->message_script_))); } // Iterate over pointers on native execution stack. @@ -1162,6 +1164,22 @@ void Isolate::ScheduleThrow(Object* exception) { } +void Isolate::RestorePendingMessageFromTryCatch(v8::TryCatch* handler) { + ASSERT(handler == try_catch_handler()); + ASSERT(handler->HasCaught()); + ASSERT(handler->rethrow_); + ASSERT(handler->capture_message_); + Object* message = reinterpret_cast(handler->message_obj_); + Object* script = reinterpret_cast(handler->message_script_); + ASSERT(message->IsJSMessageObject() || message->IsTheHole()); + ASSERT(script->IsScript() || script->IsTheHole()); + thread_local_top()->pending_message_obj_ = message; + thread_local_top()->pending_message_script_ = script; + thread_local_top()->pending_message_start_pos_ = handler->message_start_pos_; + thread_local_top()->pending_message_end_pos_ = handler->message_end_pos_; +} + + Failure* Isolate::PromoteScheduledException() { MaybeObject* thrown = scheduled_exception(); clear_scheduled_exception(); @@ -1280,9 +1298,12 @@ void Isolate::DoThrow(Object* exception, MessageLocation* location) { ShouldReportException(&can_be_caught_externally, catchable_by_javascript); bool report_exception = catchable_by_javascript && should_report_exception; bool try_catch_needs_message = - can_be_caught_externally && try_catch_handler()->capture_message_; + can_be_caught_externally && try_catch_handler()->capture_message_ && + !thread_local_top()->rethrowing_message_; bool bootstrapping = bootstrapper()->IsActive(); + thread_local_top()->rethrowing_message_ = false; + #ifdef ENABLE_DEBUGGER_SUPPORT // Notify debugger of exception. if (catchable_by_javascript) { @@ -1464,8 +1485,9 @@ void Isolate::ReportPendingMessages() { HandleScope scope(this); Handle message_obj(thread_local_top_.pending_message_obj_, this); - if (thread_local_top_.pending_message_script_ != NULL) { - Handle