📄 debug.cc.svn-base
字号:
// Bail out based on state or if there is no listener for this event if (Debug::InDebugger()) return; if (compiling_natives()) return; if (!Debugger::EventActive(v8::NewFunction)) return; // Enter the debugger. Bail out if the debugger cannot be loaded. if (!Debug::Load()) return; SaveBreakFrame save; EnterDebuggerContext enter; // Create the event object. bool caught_exception = false; Handle<Object> event_data = MakeNewFunctionEvent(function, &caught_exception); // Bail out and don't call debugger if exception. if (caught_exception) { return; } // Process debug event. ProcessDebugEvent(v8::NewFunction, event_data);}void Debugger::ProcessDebugEvent(v8::DebugEvent event, Handle<Object> event_data) { // Create the execution state. bool caught_exception = false; Handle<Object> exec_state = MakeExecutionState(&caught_exception); if (caught_exception) { return; } // First notify the builtin debugger. if (message_thread_ != NULL) { message_thread_->DebugEvent(event, exec_state, event_data); } // Notify registered debug event listeners. The list can contain both C and // JavaScript functions. v8::NeanderArray listeners(Factory::debug_event_listeners()); int length = listeners.length(); for (int i = 0; i < length; i++) { if (listeners.get(i)->IsUndefined()) continue; // Skip deleted ones. v8::NeanderObject listener(JSObject::cast(listeners.get(i))); Handle<Object> callback_data(listener.get(1)); if (listener.get(0)->IsProxy()) { // C debug event listener. Handle<Proxy> callback_obj(Proxy::cast(listener.get(0))); v8::DebugEventCallback callback = FUNCTION_CAST<v8::DebugEventCallback>(callback_obj->proxy()); callback(event, v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)), v8::Utils::ToLocal(Handle<JSObject>::cast(event_data)), v8::Utils::ToLocal(callback_data)); } else { // JavaScript debug event listener. ASSERT(listener.get(0)->IsJSFunction()); Handle<JSFunction> fun(JSFunction::cast(listener.get(0))); // Invoke the JavaScript debug event listener. const int argc = 4; Object** argv[argc] = { Handle<Object>(Smi::FromInt(event)).location(), exec_state.location(), event_data.location(), callback_data.location() }; Handle<Object> result = Execution::TryCall(fun, Top::global(), argc, argv, &caught_exception); if (caught_exception) { // Silently ignore exceptions from debug event listeners. } } }}void Debugger::SetMessageHandler(v8::DebugMessageHandler handler, void* data) { debug_message_handler_ = handler; debug_message_handler_data_ = data; if (!message_thread_) { message_thread_ = new DebugMessageThread(); message_thread_->Start(); } UpdateActiveDebugger();}// Posts an output message from the debugger to the debug_message_handler// callback. This callback is part of the public API. Messages are// kept internally as Vector<uint16_t> strings, which are allocated in various// places and deallocated by the calling function sometime after this call.void Debugger::SendMessage(Vector< uint16_t> message) { if (debug_message_handler_ != NULL) { debug_message_handler_(message.start(), message.length(), debug_message_handler_data_); }}void Debugger::ProcessCommand(Vector<const uint16_t> command) { if (message_thread_ != NULL) { message_thread_->ProcessCommand( Vector<uint16_t>(const_cast<uint16_t *>(command.start()), command.length())); }}void Debugger::UpdateActiveDebugger() { v8::NeanderArray listeners(Factory::debug_event_listeners()); int length = listeners.length(); bool active_listener = false; for (int i = 0; i < length && !active_listener; i++) { active_listener = !listeners.get(i)->IsUndefined(); } set_debugger_active((Debugger::message_thread_ != NULL && Debugger::debug_message_handler_ != NULL) || active_listener); if (!debugger_active() && message_thread_) message_thread_->OnDebuggerInactive();}DebugMessageThread::DebugMessageThread() : host_running_(true), command_queue_(kQueueInitialSize), message_queue_(kQueueInitialSize) { command_received_ = OS::CreateSemaphore(0); message_received_ = OS::CreateSemaphore(0);}// Does not free resources held by DebugMessageThread// because this cannot be done thread-safely.DebugMessageThread::~DebugMessageThread() {}// Puts an event coming from V8 on the queue. Creates// a copy of the JSON formatted event string managed by the V8.// Called by the V8 thread.// The new copy of the event string is destroyed in Run().void DebugMessageThread::SendMessage(Vector<uint16_t> message) { Vector<uint16_t> message_copy = message.Clone(); Logger::DebugTag("Put message on event message_queue."); message_queue_.Put(message_copy); message_received_->Signal();}void DebugMessageThread::SetEventJSONFromEvent(Handle<Object> event_data) { v8::HandleScope scope; // Call toJSONProtocol on the debug event object. v8::Local<v8::Object> api_event_data = v8::Utils::ToLocal(Handle<JSObject>::cast(event_data)); v8::Local<v8::String> fun_name = v8::String::New("toJSONProtocol"); v8::Local<v8::Function> fun = v8::Function::Cast(*api_event_data->Get(fun_name)); v8::TryCatch try_catch; v8::Local<v8::Value> json_event = *fun->Call(api_event_data, 0, NULL); v8::Local<v8::String> json_event_string; if (!try_catch.HasCaught()) { if (!json_event->IsUndefined()) { json_event_string = json_event->ToString(); if (FLAG_trace_debug_json) { PrintLn(json_event_string); } v8::String::Value val(json_event_string); Vector<uint16_t> str(reinterpret_cast<uint16_t*>(*val), json_event_string->Length()); SendMessage(str); } else { SendMessage(Vector<uint16_t>::empty()); } } else { PrintLn(try_catch.Exception()); SendMessage(Vector<uint16_t>::empty()); }}void DebugMessageThread::Run() { // Sends debug events to an installed debugger message callback. while (true) { // Wait and Get are paired so that semaphore count equals queue length. message_received_->Wait(); Logger::DebugTag("Get message from event message_queue."); Vector<uint16_t> message = message_queue_.Get(); if (message.length() > 0) { Debugger::SendMessage(message); } }}// This method is called by the V8 thread whenever a debug event occurs in// the VM.void DebugMessageThread::DebugEvent(v8::DebugEvent event, Handle<Object> exec_state, Handle<Object> event_data) { if (!Debug::Load()) return; // Process the individual events. bool interactive = false; switch (event) { case v8::Break: interactive = true; // Break event is always interactive break; case v8::Exception: interactive = true; // Exception event is always interactive break; case v8::BeforeCompile: break; case v8::AfterCompile: break; case v8::NewFunction: break; default: UNREACHABLE(); } // Done if not interactive. if (!interactive) return; // Get the DebugCommandProcessor. v8::Local<v8::Object> api_exec_state = v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)); v8::Local<v8::String> fun_name = v8::String::New("debugCommandProcessor"); v8::Local<v8::Function> fun = v8::Function::Cast(*api_exec_state->Get(fun_name)); v8::TryCatch try_catch; v8::Local<v8::Object> cmd_processor = v8::Object::Cast(*fun->Call(api_exec_state, 0, NULL)); if (try_catch.HasCaught()) { PrintLn(try_catch.Exception()); return; } // Notify the debugger that a debug event has occurred. host_running_ = false; SetEventJSONFromEvent(event_data); // Wait for commands from the debugger. while (true) { command_received_->Wait(); Logger::DebugTag("Get command from command queue, in interactive loop."); Vector<uint16_t> command = command_queue_.Get(); ASSERT(!host_running_); if (!Debugger::debugger_active()) { host_running_ = true; return; } // Invoke the JavaScript to convert the debug command line to a JSON // request, invoke the JSON request and convert the JSON response to a text // representation. v8::Local<v8::String> fun_name; v8::Local<v8::Function> fun; v8::Local<v8::Value> args[1]; v8::TryCatch try_catch; fun_name = v8::String::New("processDebugCommand"); fun = v8::Function::Cast(*cmd_processor->Get(fun_name)); args[0] = v8::String::New(reinterpret_cast<uint16_t*>(command.start()), command.length()); v8::Local<v8::Value> result_val = fun->Call(cmd_processor, 1, args); // Get the result of the command. v8::Local<v8::String> result_string; bool running = false; if (!try_catch.HasCaught()) { // Get the result as an object. v8::Local<v8::Object> result = v8::Object::Cast(*result_val); // Log the JSON request/response. if (FLAG_trace_debug_json) { PrintLn(result->Get(v8::String::New("request"))); PrintLn(result->Get(v8::String::New("response"))); } // Get the running state. running = result->Get(v8::String::New("running"))->ToBoolean()->Value(); // Get result text. v8::Local<v8::Value> text_result = result->Get(v8::String::New("response")); if (!text_result->IsUndefined()) { result_string = text_result->ToString(); } else { result_string = v8::String::New(""); } } else { // In case of failure the result text is the exception text. result_string = try_catch.Exception()->ToString(); } // Convert text result to C string. v8::String::Value val(result_string); Vector<uint16_t> str(reinterpret_cast<uint16_t*>(*val), result_string->Length()); // Set host_running_ correctly for nested debugger evaluations. host_running_ = running; // Return the result. SendMessage(str); // Return from debug event processing is VM should be running. if (running) { return; } }}// Puts a command coming from the public API on the queue. Creates// a copy of the command string managed by the debugger. Up to this// point, the command data was managed by the API client. Called// by the API client thread. This is where the API client hands off// processing of the command to the DebugMessageThread thread.// The new copy of the command is destroyed in HandleCommand().void DebugMessageThread::ProcessCommand(Vector<uint16_t> command) { Vector<uint16_t> command_copy = command.Clone(); Logger::DebugTag("Put command on command_queue."); command_queue_.Put(command_copy); command_received_->Signal();}void DebugMessageThread::OnDebuggerInactive() { // Send an empty command to the debugger if in a break to make JavaScript run // again if the debugger is closed. if (!host_running_) { ProcessCommand(Vector<uint16_t>::empty()); }}MessageQueue::MessageQueue(int size) : start_(0), end_(0), size_(size) { messages_ = NewArray<Vector<uint16_t> >(size);}MessageQueue::~MessageQueue() { DeleteArray(messages_);}Vector<uint16_t> MessageQueue::Get() { ASSERT(!IsEmpty()); int result = start_; start_ = (start_ + 1) % size_; return messages_[result];}void MessageQueue::Put(const Vector<uint16_t>& message) { if ((end_ + 1) % size_ == start_) { Expand(); } messages_[end_] = message; end_ = (end_ + 1) % size_;}void MessageQueue::Expand() { MessageQueue new_queue(size_ * 2); while (!IsEmpty()) { new_queue.Put(Get()); } Vector<uint16_t>* array_to_free = messages_; *this = new_queue; new_queue.messages_ = array_to_free; // Automatic destructor called on new_queue, freeing array_to_free.}LockingMessageQueue::LockingMessageQueue(int size) : queue_(size) { lock_ = OS::CreateMutex();}LockingMessageQueue::~LockingMessageQueue() { delete lock_;}bool LockingMessageQueue::IsEmpty() const { ScopedLock sl(lock_); return queue_.IsEmpty();}Vector<uint16_t> LockingMess
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -