📄 top.cc.svn-base
字号:
// Copyright 2006-2008 the V8 project authors. All rights reserved.// Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions are// met://// * Redistributions of source code must retain the above copyright// notice, this list of conditions and the following disclaimer.// * Redistributions in binary form must reproduce the above// copyright notice, this list of conditions and the following// disclaimer in the documentation and/or other materials provided// with the distribution.// * Neither the name of Google Inc. nor the names of its// contributors may be used to endorse or promote products derived// from this software without specific prior written permission.//// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.#include "v8.h"#include "api.h"#include "bootstrapper.h"#include "debug.h"#include "execution.h"#include "string-stream.h"#include "platform.h"namespace v8 { namespace internal {ThreadLocalTop Top::thread_local_;Mutex* Top::break_access_ = OS::CreateMutex();StackFrame::Id Top::break_frame_id_;int Top::break_count_;int Top::break_id_;NoAllocationStringAllocator* preallocated_message_space = NULL;Address top_addresses[] = {#define C(name) reinterpret_cast<Address>(Top::name()), TOP_ADDRESS_LIST(C)#undef C 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);}#define VISIT(field) v->VisitPointer(reinterpret_cast<Object**>(&(field)));void Top::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) { VISIT(thread->pending_exception_); VISIT(thread->security_context_); VISIT(thread->context_); VISIT(thread->scheduled_exception_); for (v8::TryCatch* block = thread->try_catch_handler_; block != NULL; block = block->next_) { VISIT(reinterpret_cast<Object*&>(block->exception_)); VISIT(reinterpret_cast<Object*&>(block->message_)); } // Iterate over pointers on native execution stack. for (StackFrameIterator it(thread); !it.done(); it.Advance()) { it.frame()->Iterate(v); }}#undef VISITvoid Top::Iterate(ObjectVisitor* v) { ThreadLocalTop* current_t = &thread_local_; Iterate(v, current_t);}void Top::InitializeThreadLocal() { thread_local_.c_entry_fp_ = 0; thread_local_.handler_ = 0; thread_local_.stack_is_cooked_ = false; thread_local_.try_catch_handler_ = NULL; thread_local_.security_context_ = NULL; thread_local_.context_ = NULL; thread_local_.external_caught_exception_ = false; thread_local_.failed_access_check_callback_ = NULL; clear_pending_exception(); clear_scheduled_exception(); thread_local_.save_context_ = NULL;}// 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); } // When the thread starts running it will allocate a fixed number of bytes // on the stack and publish the location of this memory for others to use. void Run() { EmbeddedVector<char, 16 * 1024> local_buffer; // Initialize the buffer with a known good value. OS::StrNCpy(local_buffer, "Trace data was not generated.\n", local_buffer.length()); // Publish the local buffer and signal its availability. data_ = &local_buffer[0]; length_ = sizeof(local_buffer); data_ready_semaphore_->Signal(); while (keep_running_) { // This thread will wait here until the end of time. wait_for_ever_semaphore_->Wait(); } // Make sure we access the buffer after the wait to remove all possibility // of it being optimized away. OS::StrNCpy(local_buffer, "PreallocatedMemoryThread shutting down.\n", local_buffer.length()); } static char* data() { if (data_ready_semaphore_ != NULL) { // Initial access is guarded until the data has been published. data_ready_semaphore_->Wait(); delete data_ready_semaphore_; data_ready_semaphore_ = NULL; } return data_; } static unsigned length() { if (data_ready_semaphore_ != NULL) { // Initial access is guarded until the data has been published. data_ready_semaphore_->Wait(); delete data_ready_semaphore_; data_ready_semaphore_ = NULL; } 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; wait_for_ever_semaphore_->Signal(); // Wait for the thread to terminate. the_thread_->Join(); if (data_ready_semaphore_ != NULL) { delete data_ready_semaphore_; data_ready_semaphore_ = NULL; } 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 to signal that the data has been initialized. static Semaphore* data_ready_semaphore_; // Location and size of the preallocated memory block. static char* data_; static 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;static bool initialized = false;void Top::Initialize() { CHECK(!initialized); InitializeThreadLocal(); break_frame_id_ = StackFrame::NO_ID; break_count_ = 0; break_id_ = 0; // Only preallocate on the first initialization. if (FLAG_preallocate_message_memory && (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); } initialized = true;}void Top::TearDown() { if (initialized) { // Remove the external reference to the preallocated stack memory. if (preallocated_message_space != NULL) { delete preallocated_message_space; preallocated_message_space = NULL; } PreallocatedMemoryThread::StopThread(); initialized = false; }}void Top::RegisterTryCatchHandler(v8::TryCatch* that) { thread_local_.try_catch_handler_ = that;}void Top::UnregisterTryCatchHandler(v8::TryCatch* that) { ASSERT(thread_local_.try_catch_handler_ == that); thread_local_.try_catch_handler_ = that->next_;}void Top::new_break(StackFrame::Id break_frame_id) { ExecutionAccess access; break_frame_id_ = break_frame_id; break_id_ = ++break_count_;}void Top::set_break(StackFrame::Id break_frame_id, int break_id) { ExecutionAccess access; break_frame_id_ = break_frame_id; break_id_ = break_id;}bool Top::check_break(int break_id) { ExecutionAccess access; return break_id == break_id_;}bool Top::is_break() { ExecutionAccess access; return break_id_ != 0;}StackFrame::Id Top::break_frame_id() { ExecutionAccess access; return break_frame_id_;}int Top::break_id() { ExecutionAccess access; return break_id_;}void Top::MarkCompactPrologue() { MarkCompactPrologue(&thread_local_);}void Top::MarkCompactPrologue(char* data) { MarkCompactPrologue(reinterpret_cast<ThreadLocalTop*>(data));}void Top::MarkCompactPrologue(ThreadLocalTop* thread) { StackFrame::CookFramesForThread(thread);}void Top::MarkCompactEpilogue(char* data) { MarkCompactEpilogue(reinterpret_cast<ThreadLocalTop*>(data));}void Top::MarkCompactEpilogue() { MarkCompactEpilogue(&thread_local_);}void Top::MarkCompactEpilogue(ThreadLocalTop* thread) { StackFrame::UncookFramesForThread(thread);}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++; HeapStringAllocator allocator; StringStream::ClearMentionedObjectCache(); StringStream accumulator(&allocator); incomplete_message = &accumulator; PrintStack(&accumulator); Handle<String> stack_trace = accumulator.ToString(); incomplete_message = NULL; stack_trace_nesting_level = 0; return stack_trace; } else if (stack_trace_nesting_level == 1) { 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(); return Factory::empty_symbol(); } else { OS::Abort(); // Unreachable return Factory::empty_symbol(); }}void Top::PrintStack() { if (stack_trace_nesting_level == 0) { stack_trace_nesting_level++; StringAllocator* allocator; if (preallocated_message_space == NULL) { allocator = new HeapStringAllocator(); } else { allocator = preallocated_message_space; } NativeAllocationChecker allocation_checker( !FLAG_preallocate_message_memory ? NativeAllocationChecker::ALLOW : NativeAllocationChecker::DISALLOW); StringStream::ClearMentionedObjectCache(); StringStream accumulator(allocator); incomplete_message = &accumulator; PrintStack(&accumulator); accumulator.OutputToStdOut(); accumulator.Log(); incomplete_message = NULL; stack_trace_nesting_level = 0; if (preallocated_message_space == NULL) { // Remove the HeapStringAllocator created above. delete allocator; } } else if (stack_trace_nesting_level == 1) { 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(); }}static void PrintFrames(StringStream* accumulator, StackFrame::PrintMode mode) { StackFrameIterator it; for (int i = 0; !it.done(); it.Advance()) { it.frame()->Print(accumulator, mode, i++); }}void Top::PrintStack(StringStream* accumulator) { // The MentionedObjectCache is not GC-proof at the moment. AssertNoAllocation nogc; ASSERT(StringStream::IsMentionedObjectCacheClear()); // Avoid printing anything if there are no frames. if (c_entry_fp(GetCurrentThread()) == 0) return; accumulator->Add( "\n==== Stack trace ============================================\n\n"); PrintFrames(accumulator, StackFrame::OVERVIEW); accumulator->Add( "\n==== Details ================================================\n\n"); PrintFrames(accumulator, StackFrame::DETAILS); accumulator->PrintMentionedObjectCache(); accumulator->Add("=====================\n\n");}void Top::SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback callback) { 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; ASSERT(receiver->IsAccessCheckNeeded()); ASSERT(Top::security_context());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -