| Index: src/top.cc
|
| ===================================================================
|
| --- src/top.cc (revision 3427)
|
| +++ src/top.cc (working copy)
|
| @@ -38,99 +38,15 @@
|
| namespace v8 {
|
| namespace internal {
|
|
|
| -ThreadLocalTop Top::thread_local_;
|
| -Mutex* Top::break_access_ = OS::CreateMutex();
|
| -
|
| -NoAllocationStringAllocator* preallocated_message_space = NULL;
|
| -
|
| -Address top_addresses[] = {
|
| -#define C(name) reinterpret_cast<Address>(Top::name()),
|
| - TOP_ADDRESS_LIST(C)
|
| - TOP_ADDRESS_LIST_PROF(C)
|
| -#undef C
|
| - NULL
|
| -};
|
| -
|
| -
|
| -v8::TryCatch* ThreadLocalTop::TryCatchHandler() {
|
| - return TRY_CATCH_FROM_ADDRESS(try_catch_handler_address());
|
| -}
|
| -
|
| -
|
| -void ThreadLocalTop::Initialize() {
|
| - c_entry_fp_ = 0;
|
| - handler_ = 0;
|
| -#ifdef ENABLE_LOGGING_AND_PROFILING
|
| - js_entry_sp_ = 0;
|
| -#endif
|
| - stack_is_cooked_ = false;
|
| - try_catch_handler_address_ = NULL;
|
| - context_ = NULL;
|
| - int id = ThreadManager::CurrentId();
|
| - thread_id_ = (id == 0) ? ThreadManager::kInvalidId : id;
|
| - external_caught_exception_ = false;
|
| - failed_access_check_callback_ = NULL;
|
| - save_context_ = NULL;
|
| - catcher_ = NULL;
|
| -}
|
| -
|
| -
|
| -Address Top::get_address_from_id(Top::AddressId id) {
|
| - return top_addresses[id];
|
| -}
|
| -
|
| -
|
| -char* Top::Iterate(ObjectVisitor* v, char* thread_storage) {
|
| - ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(thread_storage);
|
| - Iterate(v, thread);
|
| - return thread_storage + sizeof(ThreadLocalTop);
|
| -}
|
| -
|
| -
|
| -void Top::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) {
|
| - v->VisitPointer(&(thread->pending_exception_));
|
| - v->VisitPointer(&(thread->pending_message_obj_));
|
| - v->VisitPointer(
|
| - bit_cast<Object**, Script**>(&(thread->pending_message_script_)));
|
| - v->VisitPointer(bit_cast<Object**, Context**>(&(thread->context_)));
|
| - v->VisitPointer(&(thread->scheduled_exception_));
|
| -
|
| - for (v8::TryCatch* block = thread->TryCatchHandler();
|
| - block != NULL;
|
| - block = TRY_CATCH_FROM_ADDRESS(block->next_)) {
|
| - v->VisitPointer(bit_cast<Object**, void**>(&(block->exception_)));
|
| - v->VisitPointer(bit_cast<Object**, void**>(&(block->message_)));
|
| - }
|
| -
|
| - // Iterate over pointers on native execution stack.
|
| - for (StackFrameIterator it(thread); !it.done(); it.Advance()) {
|
| - it.frame()->Iterate(v);
|
| - }
|
| -}
|
| -
|
| -
|
| -void Top::Iterate(ObjectVisitor* v) {
|
| - ThreadLocalTop* current_t = &thread_local_;
|
| - Iterate(v, current_t);
|
| -}
|
| -
|
| -
|
| -void Top::InitializeThreadLocal() {
|
| - thread_local_.Initialize();
|
| - clear_pending_exception();
|
| - clear_pending_message();
|
| - clear_scheduled_exception();
|
| -}
|
| -
|
| -
|
| // Create a dummy thread that will wait forever on a semaphore. The only
|
| // purpose for this thread is to have some stack area to save essential data
|
| // into for use by a stacks only core dump (aka minidump).
|
| class PreallocatedMemoryThread: public Thread {
|
| public:
|
| - PreallocatedMemoryThread() : keep_running_(true) {
|
| - wait_for_ever_semaphore_ = OS::CreateSemaphore(0);
|
| - data_ready_semaphore_ = OS::CreateSemaphore(0);
|
| + PreallocatedMemoryThread() : keep_running_(true),
|
| + wait_for_ever_semaphore_(OS::CreateSemaphore(0)),
|
| + data_ready_semaphore_(OS::CreateSemaphore(0)),
|
| + data_(NULL), length_(0) {
|
| }
|
|
|
| // When the thread starts running it will allocate a fixed number of bytes
|
| @@ -158,7 +74,7 @@
|
| local_buffer.length());
|
| }
|
|
|
| - static char* data() {
|
| + char* data() {
|
| if (data_ready_semaphore_ != NULL) {
|
| // Initial access is guarded until the data has been published.
|
| data_ready_semaphore_->Wait();
|
| @@ -168,7 +84,7 @@
|
| return data_;
|
| }
|
|
|
| - static unsigned length() {
|
| + unsigned length() {
|
| if (data_ready_semaphore_ != NULL) {
|
| // Initial access is guarded until the data has been published.
|
| data_ready_semaphore_->Wait();
|
| @@ -178,22 +94,13 @@
|
| return length_;
|
| }
|
|
|
| - static void StartThread() {
|
| - if (the_thread_ != NULL) return;
|
| -
|
| - the_thread_ = new PreallocatedMemoryThread();
|
| - the_thread_->Start();
|
| - }
|
| -
|
| // Stop the PreallocatedMemoryThread and release its resources.
|
| - static void StopThread() {
|
| - if (the_thread_ == NULL) return;
|
| -
|
| - the_thread_->keep_running_ = false;
|
| + void RequestEnd() {
|
| + keep_running_ = false;
|
| wait_for_ever_semaphore_->Signal();
|
|
|
| // Wait for the thread to terminate.
|
| - the_thread_->Join();
|
| + Join();
|
|
|
| if (data_ready_semaphore_ != NULL) {
|
| delete data_ready_semaphore_;
|
| @@ -202,66 +109,209 @@
|
|
|
| delete wait_for_ever_semaphore_;
|
| wait_for_ever_semaphore_ = NULL;
|
| -
|
| - // Done with the thread entirely.
|
| - delete the_thread_;
|
| - the_thread_ = NULL;
|
| }
|
|
|
| private:
|
| // Used to make sure that the thread keeps looping even for spurious wakeups.
|
| bool keep_running_;
|
|
|
| - // The preallocated memory thread singleton.
|
| - static PreallocatedMemoryThread* the_thread_;
|
| // This semaphore is used by the PreallocatedMemoryThread to wait for ever.
|
| - static Semaphore* wait_for_ever_semaphore_;
|
| + Semaphore* wait_for_ever_semaphore_;
|
| // Semaphore to signal that the data has been initialized.
|
| - static Semaphore* data_ready_semaphore_;
|
| + Semaphore* data_ready_semaphore_;
|
|
|
| // Location and size of the preallocated memory block.
|
| - static char* data_;
|
| - static unsigned length_;
|
| + char* data_;
|
| + unsigned length_;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(PreallocatedMemoryThread);
|
| };
|
|
|
| -PreallocatedMemoryThread* PreallocatedMemoryThread::the_thread_ = NULL;
|
| -Semaphore* PreallocatedMemoryThread::wait_for_ever_semaphore_ = NULL;
|
| -Semaphore* PreallocatedMemoryThread::data_ready_semaphore_ = NULL;
|
| -char* PreallocatedMemoryThread::data_ = NULL;
|
| -unsigned PreallocatedMemoryThread::length_ = 0;
|
| +class TopPrivateData {
|
| + public:
|
| + NoAllocationStringAllocator* preallocated_message_space;
|
| + Address top_addresses[Top::k_top_address_count];
|
|
|
| -static bool initialized = false;
|
| + // The preallocated memory thread singleton.
|
| + PreallocatedMemoryThread* the_thread_;
|
| + int stack_trace_nesting_level;
|
| + StringStream* incomplete_message;
|
| + bool initialized;
|
|
|
| + TopPrivateData()
|
| + :initialized(false), preallocated_message_space(NULL),
|
| + incomplete_message(NULL), stack_trace_nesting_level(NULL),
|
| + the_thread_(NULL) {
|
| + Address _top_addresses[] = {
|
| + #define C(name) reinterpret_cast<Address>(Top::name()),
|
| + TOP_ADDRESS_LIST(C)
|
| + TOP_ADDRESS_LIST_PROF(C)
|
| + #undef C
|
| + NULL
|
| + };
|
| + for (int i = 0; i < Top::k_top_address_count; ++i)
|
| + top_addresses[i] = _top_addresses[i];
|
| + }
|
| +
|
| + void StartThread() {
|
| + if (the_thread_ != NULL) return;
|
| +
|
| + the_thread_ = new PreallocatedMemoryThread();
|
| + the_thread_->Start();
|
| + }
|
| +
|
| + // Stop the PreallocatedMemoryThread and release its resources.
|
| + void StopThread() {
|
| + if (the_thread_ == NULL) return;
|
| + the_thread_->RequestEnd();
|
| +
|
| + // Done with the thread entirely.
|
| + delete the_thread_;
|
| + the_thread_ = NULL;
|
| + }
|
| +};
|
| +
|
| +TopData::TopData()
|
| + :break_access_(OS::CreateMutex()),
|
| + thread_local_(),
|
| + top_private_data_(NULL) {
|
| +}
|
| +
|
| +void Top::PostConstruct() {
|
| + v8_context()->top_data_.top_private_data_ = new TopPrivateData();
|
| +}
|
| +
|
| +void Top::PreDestroy() {
|
| + delete v8_context()->top_data_.top_private_data_;
|
| +}
|
| +
|
| +ThreadLocalTop::ThreadLocalTop()
|
| + :context_(NULL),
|
| + has_pending_message_(false),
|
| + external_caught_exception_(false),
|
| + formal_count_(0),
|
| + stack_is_cooked_(false),
|
| + #ifdef ENABLE_LOGGING_AND_PROFILING
|
| + js_entry_sp_(NULL),
|
| + #endif
|
| + handler_(NULL),
|
| + c_entry_fp_(NULL),
|
| + catcher_(NULL),
|
| + save_context_(NULL),
|
| + scheduled_exception_(NULL),
|
| + pending_message_end_pos_(0),
|
| + pending_message_start_pos_(0),
|
| + pending_message_script_(0),
|
| + pending_message_obj_(NULL),
|
| + pending_message_(NULL),
|
| + pending_exception_(false),
|
| + thread_id_(0),
|
| + failed_access_check_callback_(NULL),
|
| + try_catch_handler_address_(NULL) {
|
| +}
|
| +
|
| +v8::TryCatch* ThreadLocalTop::TryCatchHandler() {
|
| + return TRY_CATCH_FROM_ADDRESS(try_catch_handler_address());
|
| +}
|
| +
|
| +
|
| +void ThreadLocalTop::Initialize() {
|
| + c_entry_fp_ = 0;
|
| + handler_ = 0;
|
| +#ifdef ENABLE_LOGGING_AND_PROFILING
|
| + js_entry_sp_ = 0;
|
| +#endif
|
| + stack_is_cooked_ = false;
|
| + try_catch_handler_address_ = NULL;
|
| + context_ = NULL;
|
| + int id = ThreadManager::CurrentId();
|
| + thread_id_ = (id == 0) ? ThreadManager::kInvalidId : id;
|
| + external_caught_exception_ = false;
|
| + failed_access_check_callback_ = NULL;
|
| + save_context_ = NULL;
|
| + catcher_ = NULL;
|
| +}
|
| +
|
| +
|
| +Address Top::get_address_from_id(Top::AddressId id) {
|
| + return v8_context()->top_data_.top_private_data_->top_addresses[id];
|
| +}
|
| +
|
| +
|
| +char* Top::Iterate(ObjectVisitor* v, char* thread_storage) {
|
| + ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(thread_storage);
|
| + Iterate(v, thread);
|
| + return thread_storage + sizeof(ThreadLocalTop);
|
| +}
|
| +
|
| +
|
| +void Top::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) {
|
| + v->VisitPointer(&(thread->pending_exception_));
|
| + v->VisitPointer(&(thread->pending_message_obj_));
|
| + v->VisitPointer(
|
| + bit_cast<Object**, Script**>(&(thread->pending_message_script_)));
|
| + v->VisitPointer(bit_cast<Object**, Context**>(&(thread->context_)));
|
| + v->VisitPointer(&(thread->scheduled_exception_));
|
| +
|
| + for (v8::TryCatch* block = thread->TryCatchHandler();
|
| + block != NULL;
|
| + block = TRY_CATCH_FROM_ADDRESS(block->next_)) {
|
| + v->VisitPointer(bit_cast<Object**, void**>(&(block->exception_)));
|
| + v->VisitPointer(bit_cast<Object**, void**>(&(block->message_)));
|
| + }
|
| +
|
| + // Iterate over pointers on native execution stack.
|
| + for (StackFrameIterator it(thread); !it.done(); it.Advance()) {
|
| + it.frame()->Iterate(v);
|
| + }
|
| +}
|
| +
|
| +
|
| +void Top::Iterate(ObjectVisitor* v) {
|
| + ThreadLocalTop* current_t = &v8_context()->top_data_.thread_local_;
|
| + Iterate(v, current_t);
|
| +}
|
| +
|
| +
|
| +void Top::InitializeThreadLocal() {
|
| + v8_context()->top_data_.thread_local_.Initialize();
|
| + clear_pending_exception();
|
| + clear_pending_message();
|
| + clear_scheduled_exception();
|
| +}
|
| +
|
| void Top::Initialize() {
|
| - CHECK(!initialized);
|
| + TopPrivateData* top_private_data = v8_context()->top_data_.top_private_data_;
|
| + CHECK(!top_private_data->initialized);
|
|
|
| InitializeThreadLocal();
|
|
|
| // Only preallocate on the first initialization.
|
| - if (FLAG_preallocate_message_memory && (preallocated_message_space == NULL)) {
|
| + if (FLAG_preallocate_message_memory &&
|
| + (top_private_data->preallocated_message_space == NULL)) {
|
| // Start the thread which will set aside some memory.
|
| - PreallocatedMemoryThread::StartThread();
|
| - preallocated_message_space =
|
| - new NoAllocationStringAllocator(PreallocatedMemoryThread::data(),
|
| - PreallocatedMemoryThread::length());
|
| - PreallocatedStorage::Init(PreallocatedMemoryThread::length() / 4);
|
| + top_private_data->StartThread();
|
| + top_private_data->preallocated_message_space =
|
| + new NoAllocationStringAllocator(
|
| + top_private_data->the_thread_->data(),
|
| + top_private_data->the_thread_->length());
|
| + PreallocatedStorage::Init(top_private_data->the_thread_->length() / 4);
|
| }
|
| - initialized = true;
|
| + top_private_data->initialized = true;
|
| }
|
|
|
|
|
| void Top::TearDown() {
|
| - if (initialized) {
|
| + TopPrivateData* top_private_data = v8_context()->top_data_.top_private_data_;
|
| + if (top_private_data->initialized) {
|
| // Remove the external reference to the preallocated stack memory.
|
| - if (preallocated_message_space != NULL) {
|
| - delete preallocated_message_space;
|
| - preallocated_message_space = NULL;
|
| + if (top_private_data->preallocated_message_space != NULL) {
|
| + delete top_private_data->preallocated_message_space;
|
| + top_private_data->preallocated_message_space = NULL;
|
| }
|
|
|
| - PreallocatedMemoryThread::StopThread();
|
| - initialized = false;
|
| + top_private_data->StopThread();
|
| + top_private_data->initialized = false;
|
| }
|
| }
|
|
|
| @@ -274,21 +324,22 @@
|
| // returned will be the address of the C++ try catch handler itself.
|
| Address address = reinterpret_cast<Address>(
|
| SimulatorStack::RegisterCTryCatch(reinterpret_cast<uintptr_t>(that)));
|
| - thread_local_.set_try_catch_handler_address(address);
|
| + v8_context()->top_data_.thread_local_.set_try_catch_handler_address(address);
|
| }
|
|
|
|
|
| void Top::UnregisterTryCatchHandler(v8::TryCatch* that) {
|
| - ASSERT(thread_local_.TryCatchHandler() == that);
|
| - thread_local_.set_try_catch_handler_address(
|
| + ThreadLocalTop& thread_local = v8_context()->top_data_.thread_local_;
|
| + ASSERT(thread_local.TryCatchHandler() == that);
|
| + thread_local.set_try_catch_handler_address(
|
| reinterpret_cast<Address>(that->next_));
|
| - thread_local_.catcher_ = NULL;
|
| + thread_local.catcher_ = NULL;
|
| SimulatorStack::UnregisterCTryCatch();
|
| }
|
|
|
|
|
| void Top::MarkCompactPrologue(bool is_compacting) {
|
| - MarkCompactPrologue(is_compacting, &thread_local_);
|
| + MarkCompactPrologue(is_compacting, &v8_context()->top_data_.thread_local_);
|
| }
|
|
|
|
|
| @@ -310,7 +361,7 @@
|
|
|
|
|
| void Top::MarkCompactEpilogue(bool is_compacting) {
|
| - MarkCompactEpilogue(is_compacting, &thread_local_);
|
| + MarkCompactEpilogue(is_compacting, &v8_context()->top_data_.thread_local_);
|
| }
|
|
|
|
|
| @@ -320,30 +371,27 @@
|
| }
|
| }
|
|
|
| -
|
| -static int stack_trace_nesting_level = 0;
|
| -static StringStream* incomplete_message = NULL;
|
| -
|
| -
|
| Handle<String> Top::StackTrace() {
|
| - if (stack_trace_nesting_level == 0) {
|
| - stack_trace_nesting_level++;
|
| + TopPrivateData* top_private_data = v8_context()->top_data_.top_private_data_;
|
| + if (top_private_data->stack_trace_nesting_level == 0) {
|
| + top_private_data->stack_trace_nesting_level++;
|
| HeapStringAllocator allocator;
|
| StringStream::ClearMentionedObjectCache();
|
| StringStream accumulator(&allocator);
|
| - incomplete_message = &accumulator;
|
| + top_private_data->incomplete_message = &accumulator;
|
| +
|
| PrintStack(&accumulator);
|
| Handle<String> stack_trace = accumulator.ToString();
|
| - incomplete_message = NULL;
|
| - stack_trace_nesting_level = 0;
|
| + top_private_data->incomplete_message = NULL;
|
| + top_private_data->stack_trace_nesting_level = 0;
|
| return stack_trace;
|
| - } else if (stack_trace_nesting_level == 1) {
|
| - stack_trace_nesting_level++;
|
| + } else if (top_private_data->stack_trace_nesting_level == 1) {
|
| + top_private_data->stack_trace_nesting_level++;
|
| OS::PrintError(
|
| "\n\nAttempt to print stack while printing stack (double fault)\n");
|
| OS::PrintError(
|
| "If you are lucky you may find a partial stack dump on stdout.\n\n");
|
| - incomplete_message->OutputToStdOut();
|
| + top_private_data->incomplete_message->OutputToStdOut();
|
| return Factory::empty_symbol();
|
| } else {
|
| OS::Abort();
|
| @@ -354,14 +402,15 @@
|
|
|
|
|
| void Top::PrintStack() {
|
| - if (stack_trace_nesting_level == 0) {
|
| - stack_trace_nesting_level++;
|
| + TopPrivateData* top_private_data = v8_context()->top_data_.top_private_data_;
|
| + if (top_private_data->stack_trace_nesting_level == 0) {
|
| + top_private_data->stack_trace_nesting_level++;
|
|
|
| StringAllocator* allocator;
|
| - if (preallocated_message_space == NULL) {
|
| + if (top_private_data->preallocated_message_space == NULL) {
|
| allocator = new HeapStringAllocator();
|
| } else {
|
| - allocator = preallocated_message_space;
|
| + allocator = top_private_data->preallocated_message_space;
|
| }
|
|
|
| NativeAllocationChecker allocation_checker(
|
| @@ -371,23 +420,23 @@
|
|
|
| StringStream::ClearMentionedObjectCache();
|
| StringStream accumulator(allocator);
|
| - incomplete_message = &accumulator;
|
| + top_private_data->incomplete_message = &accumulator;
|
| PrintStack(&accumulator);
|
| accumulator.OutputToStdOut();
|
| accumulator.Log();
|
| - incomplete_message = NULL;
|
| - stack_trace_nesting_level = 0;
|
| - if (preallocated_message_space == NULL) {
|
| + top_private_data->incomplete_message = NULL;
|
| + top_private_data->stack_trace_nesting_level = 0;
|
| + if (top_private_data->preallocated_message_space == NULL) {
|
| // Remove the HeapStringAllocator created above.
|
| delete allocator;
|
| }
|
| - } else if (stack_trace_nesting_level == 1) {
|
| - stack_trace_nesting_level++;
|
| + } else if (top_private_data->stack_trace_nesting_level == 1) {
|
| + top_private_data->stack_trace_nesting_level++;
|
| OS::PrintError(
|
| "\n\nAttempt to print stack while printing stack (double fault)\n");
|
| OS::PrintError(
|
| "If you are lucky you may find a partial stack dump on stdout.\n\n");
|
| - incomplete_message->OutputToStdOut();
|
| + top_private_data->incomplete_message->OutputToStdOut();
|
| }
|
| }
|
|
|
| @@ -423,13 +472,15 @@
|
|
|
|
|
| void Top::SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback callback) {
|
| - ASSERT(thread_local_.failed_access_check_callback_ == NULL);
|
| - thread_local_.failed_access_check_callback_ = callback;
|
| + ThreadLocalTop& thread_local = v8_context()->top_data_.thread_local_;
|
| + ASSERT(thread_local.failed_access_check_callback_ == NULL);
|
| + thread_local.failed_access_check_callback_ = callback;
|
| }
|
|
|
|
|
| void Top::ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type) {
|
| - if (!thread_local_.failed_access_check_callback_) return;
|
| + ThreadLocalTop& thread_local = v8_context()->top_data_.thread_local_;
|
| + if (!thread_local.failed_access_check_callback_) return;
|
|
|
| ASSERT(receiver->IsAccessCheckNeeded());
|
| ASSERT(Top::context());
|
| @@ -447,7 +498,7 @@
|
| HandleScope scope;
|
| Handle<JSObject> receiver_handle(receiver);
|
| Handle<Object> data(AccessCheckInfo::cast(data_obj)->data());
|
| - thread_local_.failed_access_check_callback_(
|
| + thread_local.failed_access_check_callback_(
|
| v8::Utils::ToLocal(receiver_handle),
|
| type,
|
| v8::Utils::ToLocal(data));
|
| @@ -625,8 +676,9 @@
|
| // When scheduling a throw we first throw the exception to get the
|
| // error reporting if it is uncaught before rescheduling it.
|
| Throw(exception);
|
| - thread_local_.scheduled_exception_ = pending_exception();
|
| - thread_local_.external_caught_exception_ = false;
|
| + ThreadLocalTop& thread_local = v8_context()->top_data_.thread_local_;
|
| + thread_local.scheduled_exception_ = pending_exception();
|
| + thread_local.external_caught_exception_ = false;
|
| clear_pending_exception();
|
| }
|
|
|
| @@ -713,9 +765,10 @@
|
| handler = handler->next();
|
| }
|
|
|
| + ThreadLocalTop& thread_local = v8_context()->top_data_.thread_local_;
|
| // 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();
|
| + Address external_handler_address = thread_local.try_catch_handler_address();
|
|
|
| // 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
|
| @@ -726,7 +779,7 @@
|
|
|
| if (*is_caught_externally) {
|
| // Only report the exception if the external handler is verbose.
|
| - return thread_local_.TryCatchHandler()->is_verbose_;
|
| + return thread_local.TryCatchHandler()->is_verbose_;
|
| } else {
|
| // Report the exception if it isn't caught by JavaScript code.
|
| return handler == NULL;
|
| @@ -741,6 +794,7 @@
|
|
|
| HandleScope scope;
|
| Handle<Object> exception_handle(exception);
|
| + ThreadLocalTop& thread_local = v8_context()->top_data_.thread_local_;
|
|
|
| // Determine reporting and whether the exception is caught externally.
|
| bool is_caught_externally = false;
|
| @@ -763,7 +817,7 @@
|
| MessageLocation potential_computed_location;
|
| bool try_catch_needs_message =
|
| is_caught_externally &&
|
| - thread_local_.TryCatchHandler()->capture_message_;
|
| + thread_local.TryCatchHandler()->capture_message_;
|
| if (report_exception || try_catch_needs_message) {
|
| if (location == NULL) {
|
| // If no location was specified we use a computed one instead
|
| @@ -782,19 +836,19 @@
|
| }
|
|
|
| // Save the message for reporting if the the exception remains uncaught.
|
| - thread_local_.has_pending_message_ = report_exception;
|
| - thread_local_.pending_message_ = message;
|
| + thread_local.has_pending_message_ = report_exception;
|
| + thread_local.pending_message_ = message;
|
| if (!message_obj.is_null()) {
|
| - thread_local_.pending_message_obj_ = *message_obj;
|
| + thread_local.pending_message_obj_ = *message_obj;
|
| if (location != NULL) {
|
| - thread_local_.pending_message_script_ = *location->script();
|
| - thread_local_.pending_message_start_pos_ = location->start_pos();
|
| - thread_local_.pending_message_end_pos_ = location->end_pos();
|
| + thread_local.pending_message_script_ = *location->script();
|
| + thread_local.pending_message_start_pos_ = location->start_pos();
|
| + thread_local.pending_message_end_pos_ = location->end_pos();
|
| }
|
| }
|
|
|
| if (is_caught_externally) {
|
| - thread_local_.catcher_ = thread_local_.TryCatchHandler();
|
| + thread_local.catcher_ = thread_local.TryCatchHandler();
|
| }
|
|
|
| // NOTE: Notifying the debugger or generating the message
|
| @@ -807,41 +861,42 @@
|
| void Top::ReportPendingMessages() {
|
| ASSERT(has_pending_exception());
|
| setup_external_caught();
|
| + ThreadLocalTop& thread_local = v8_context()->top_data_.thread_local_;
|
| // 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 = thread_local.external_caught_exception_;
|
| HandleScope scope;
|
| - if (thread_local_.pending_exception_ == Failure::OutOfMemoryException()) {
|
| + if (thread_local.pending_exception_ == Failure::OutOfMemoryException()) {
|
| context()->mark_out_of_memory();
|
| - } else if (thread_local_.pending_exception_ ==
|
| + } 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();
|
| + thread_local.TryCatchHandler()->can_continue_ = false;
|
| + thread_local.TryCatchHandler()->exception_ = Heap::null_value();
|
| }
|
| } else {
|
| Handle<Object> exception(pending_exception());
|
| - thread_local_.external_caught_exception_ = false;
|
| + thread_local.external_caught_exception_ = false;
|
| if (external_caught) {
|
| - thread_local_.TryCatchHandler()->can_continue_ = true;
|
| - thread_local_.TryCatchHandler()->exception_ =
|
| - thread_local_.pending_exception_;
|
| - if (!thread_local_.pending_message_obj_->IsTheHole()) {
|
| - try_catch_handler()->message_ = thread_local_.pending_message_obj_;
|
| + thread_local.TryCatchHandler()->can_continue_ = true;
|
| + thread_local.TryCatchHandler()->exception_ =
|
| + thread_local.pending_exception_;
|
| + if (!thread_local.pending_message_obj_->IsTheHole()) {
|
| + try_catch_handler()->message_ = thread_local.pending_message_obj_;
|
| }
|
| }
|
| - if (thread_local_.has_pending_message_) {
|
| - thread_local_.has_pending_message_ = false;
|
| - if (thread_local_.pending_message_ != NULL) {
|
| - MessageHandler::ReportMessage(thread_local_.pending_message_);
|
| - } else if (!thread_local_.pending_message_obj_->IsTheHole()) {
|
| - Handle<Object> message_obj(thread_local_.pending_message_obj_);
|
| - if (thread_local_.pending_message_script_ != NULL) {
|
| - Handle<Script> script(thread_local_.pending_message_script_);
|
| - int start_pos = thread_local_.pending_message_start_pos_;
|
| - int end_pos = thread_local_.pending_message_end_pos_;
|
| + if (thread_local.has_pending_message_) {
|
| + thread_local.has_pending_message_ = false;
|
| + if (thread_local.pending_message_ != NULL) {
|
| + MessageHandler::ReportMessage(thread_local.pending_message_);
|
| + } else if (!thread_local.pending_message_obj_->IsTheHole()) {
|
| + Handle<Object> message_obj(thread_local.pending_message_obj_);
|
| + if (thread_local.pending_message_script_ != NULL) {
|
| + Handle<Script> script(thread_local.pending_message_script_);
|
| + int start_pos = thread_local.pending_message_start_pos_;
|
| + int end_pos = thread_local.pending_message_end_pos_;
|
| MessageLocation location(script, start_pos, end_pos);
|
| MessageHandler::ReportMessage(&location, message_obj);
|
| } else {
|
| @@ -849,7 +904,7 @@
|
| }
|
| }
|
| }
|
| - thread_local_.external_caught_exception_ = external_caught;
|
| + thread_local.external_caught_exception_ = external_caught;
|
| set_pending_exception(*exception);
|
| }
|
| clear_pending_message();
|
| @@ -862,6 +917,7 @@
|
|
|
|
|
| bool Top::OptionalRescheduleException(bool is_bottom_call) {
|
| + ThreadLocalTop& thread_local = v8_context()->top_data_.thread_local_;
|
| // Allways reschedule out of memory exceptions.
|
| if (!is_out_of_memory()) {
|
| bool is_termination_exception =
|
| @@ -872,17 +928,17 @@
|
|
|
| if (is_termination_exception) {
|
| if (is_bottom_call) {
|
| - thread_local_.external_caught_exception_ = false;
|
| + thread_local.external_caught_exception_ = false;
|
| clear_pending_exception();
|
| return false;
|
| }
|
| - } else if (thread_local_.external_caught_exception_) {
|
| + } else if (thread_local.external_caught_exception_) {
|
| // If the exception is externally caught, clear it if there are no
|
| // JavaScript frames on the way to the C++ frame that has the
|
| // external handler.
|
| - ASSERT(thread_local_.try_catch_handler_address() != NULL);
|
| + ASSERT(thread_local.try_catch_handler_address() != NULL);
|
| Address external_handler_address =
|
| - thread_local_.try_catch_handler_address();
|
| + thread_local.try_catch_handler_address();
|
| JavaScriptFrameIterator it;
|
| if (it.done() || (it.frame()->sp() > external_handler_address)) {
|
| clear_exception = true;
|
| @@ -891,14 +947,14 @@
|
|
|
| // Clear the exception if needed.
|
| if (clear_exception) {
|
| - thread_local_.external_caught_exception_ = false;
|
| + thread_local.external_caught_exception_ = false;
|
| clear_pending_exception();
|
| return false;
|
| }
|
| }
|
|
|
| // Reschedule the exception.
|
| - thread_local_.scheduled_exception_ = pending_exception();
|
| + thread_local.scheduled_exception_ = pending_exception();
|
| clear_pending_exception();
|
| return true;
|
| }
|
| @@ -922,7 +978,8 @@
|
|
|
|
|
| Handle<Context> Top::global_context() {
|
| - GlobalObject* global = thread_local_.context_->global();
|
| + GlobalObject* global = v8_context()->top_data_.thread_local_.context_->
|
| + global();
|
| return Handle<Context>(global->global_context());
|
| }
|
|
|
| @@ -966,25 +1023,31 @@
|
|
|
|
|
| char* Top::ArchiveThread(char* to) {
|
| - memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(thread_local_));
|
| + memcpy(
|
| + to,
|
| + reinterpret_cast<char*>(&v8_context()->top_data_.thread_local_),
|
| + sizeof(ThreadLocalTop));
|
| InitializeThreadLocal();
|
| - return to + sizeof(thread_local_);
|
| + return to + sizeof(ThreadLocalTop);
|
| }
|
|
|
|
|
| char* Top::RestoreThread(char* from) {
|
| - memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(thread_local_));
|
| - return from + sizeof(thread_local_);
|
| + memcpy(
|
| + reinterpret_cast<char*>(&v8_context()->top_data_.thread_local_),
|
| + from,
|
| + sizeof(ThreadLocalTop));
|
| + return from + sizeof(ThreadLocalTop);
|
| }
|
|
|
|
|
| ExecutionAccess::ExecutionAccess() {
|
| - Top::break_access_->Lock();
|
| + v8_context()->top_data_.break_access_->Lock();
|
| }
|
|
|
|
|
| ExecutionAccess::~ExecutionAccess() {
|
| - Top::break_access_->Unlock();
|
| + v8_context()->top_data_.break_access_->Unlock();
|
| }
|
|
|
|
|
|
|