| Index: src/debug/debug.cc
|
| diff --git a/src/debug/debug.cc b/src/debug/debug.cc
|
| index bbfc43ce11cd8daa4237b5ace9b5f114f4dee6c3..35f9a7350f9091c36e45214878eed7a451cf5ec8 100644
|
| --- a/src/debug/debug.cc
|
| +++ b/src/debug/debug.cc
|
| @@ -40,6 +40,9 @@
|
| : debug_context_(Handle<Context>()),
|
| event_listener_(Handle<Object>()),
|
| event_listener_data_(Handle<Object>()),
|
| + message_handler_(NULL),
|
| + command_received_(0),
|
| + command_queue_(isolate->logger(), kQueueInitialSize),
|
| is_active_(false),
|
| hook_on_function_call_(false),
|
| is_suppressed_(false),
|
| @@ -529,7 +532,7 @@
|
| // Notify the debug event listeners.
|
| Handle<JSArray> jsarr = isolate_->factory()->NewJSArrayWithElements(
|
| break_points_hit.ToHandleChecked());
|
| - OnDebugBreak(jsarr);
|
| + OnDebugBreak(jsarr, false);
|
| return;
|
| }
|
|
|
| @@ -571,7 +574,7 @@
|
|
|
| if (step_break) {
|
| // Notify the debug event listeners.
|
| - OnDebugBreak(isolate_->factory()->undefined_value());
|
| + OnDebugBreak(isolate_->factory()->undefined_value(), false);
|
| } else {
|
| // Re-prepare to continue.
|
| PrepareStep(step_action);
|
| @@ -1783,11 +1786,11 @@
|
| }
|
|
|
| // Process debug event.
|
| - ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data));
|
| + ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data), false);
|
| // Return to continue execution from where the exception was thrown.
|
| }
|
|
|
| -void Debug::OnDebugBreak(Handle<Object> break_points_hit) {
|
| +void Debug::OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue) {
|
| // The caller provided for DebugScope.
|
| AssertDebugContext();
|
| // Bail out if there is no listener for this event
|
| @@ -1822,7 +1825,8 @@
|
| if (!MakeBreakEvent(break_points_hit).ToHandle(&event_data)) return;
|
|
|
| // Process debug event.
|
| - ProcessDebugEvent(v8::Break, Handle<JSObject>::cast(event_data));
|
| + ProcessDebugEvent(v8::Break, Handle<JSObject>::cast(event_data),
|
| + auto_continue);
|
| }
|
|
|
|
|
| @@ -1912,14 +1916,12 @@
|
| return;
|
|
|
| // Process debug event.
|
| - ProcessDebugEvent(v8::AsyncTaskEvent, Handle<JSObject>::cast(event_data));
|
| -}
|
| -
|
| -void Debug::ProcessDebugEvent(v8::DebugEvent event,
|
| - Handle<JSObject> event_data) {
|
| - // Notify registered debug event listener. This can be either a C or
|
| - // a JavaScript function.
|
| - if (event_listener_.is_null()) return;
|
| + ProcessDebugEvent(v8::AsyncTaskEvent, Handle<JSObject>::cast(event_data),
|
| + true);
|
| +}
|
| +
|
| +void Debug::ProcessDebugEvent(v8::DebugEvent event, Handle<JSObject> event_data,
|
| + bool auto_continue) {
|
| HandleScope scope(isolate_);
|
|
|
| // Create the execution state.
|
| @@ -1927,6 +1929,24 @@
|
| // Bail out and don't call debugger if exception.
|
| if (!MakeExecutionState().ToHandle(&exec_state)) return;
|
|
|
| + // First notify the message handler if any.
|
| + if (message_handler_ != NULL) {
|
| + NotifyMessageHandler(event, Handle<JSObject>::cast(exec_state), event_data,
|
| + auto_continue);
|
| + }
|
| + // Notify registered debug event listener. This can be either a C or
|
| + // a JavaScript function. Don't call event listener for v8::Break
|
| + // here, if it's only a debug command -- they will be processed later.
|
| + if ((event != v8::Break || !auto_continue) && !event_listener_.is_null()) {
|
| + CallEventCallback(event, exec_state, event_data, NULL);
|
| + }
|
| +}
|
| +
|
| +
|
| +void Debug::CallEventCallback(v8::DebugEvent event,
|
| + Handle<Object> exec_state,
|
| + Handle<Object> event_data,
|
| + v8::Debug::ClientData* client_data) {
|
| // Prevent other interrupts from triggering, for example API callbacks,
|
| // while dispatching event listners.
|
| PostponeInterruptsScope postpone(isolate_);
|
| @@ -1936,9 +1956,11 @@
|
| // Invoke the C debug event listener.
|
| v8::Debug::EventCallback callback = FUNCTION_CAST<v8::Debug::EventCallback>(
|
| Handle<Foreign>::cast(event_listener_)->foreign_address());
|
| - EventDetailsImpl event_details(event, Handle<JSObject>::cast(exec_state),
|
| + EventDetailsImpl event_details(event,
|
| + Handle<JSObject>::cast(exec_state),
|
| Handle<JSObject>::cast(event_data),
|
| - event_listener_data_);
|
| + event_listener_data_,
|
| + client_data);
|
| callback(event_details);
|
| CHECK(!isolate_->has_scheduled_exception());
|
| } else {
|
| @@ -1964,6 +1986,7 @@
|
| return;
|
| }
|
| SuppressDebug while_processing(this);
|
| + bool in_nested_debug_scope = in_debug_scope();
|
| DebugScope debug_scope(this);
|
| if (debug_scope.failed()) return;
|
|
|
| @@ -1979,8 +2002,20 @@
|
| // Bail out and don't call debugger if exception.
|
| if (!MakeCompileEvent(script, event).ToHandle(&event_data)) return;
|
|
|
| - // Process debug event.
|
| - ProcessDebugEvent(event, Handle<JSObject>::cast(event_data));
|
| + // Don't call NotifyMessageHandler if already in debug scope to avoid running
|
| + // nested command loop.
|
| + if (in_nested_debug_scope) {
|
| + if (event_listener_.is_null()) return;
|
| + // Create the execution state.
|
| + Handle<Object> exec_state;
|
| + // Bail out and don't call debugger if exception.
|
| + if (!MakeExecutionState().ToHandle(&exec_state)) return;
|
| +
|
| + CallEventCallback(event, exec_state, event_data, NULL);
|
| + } else {
|
| + // Process debug event.
|
| + ProcessDebugEvent(event, Handle<JSObject>::cast(event_data), true);
|
| + }
|
| }
|
|
|
|
|
| @@ -1992,6 +2027,136 @@
|
| return handle(*debug_context(), isolate_);
|
| }
|
|
|
| +void Debug::NotifyMessageHandler(v8::DebugEvent event,
|
| + Handle<JSObject> exec_state,
|
| + Handle<JSObject> event_data,
|
| + bool auto_continue) {
|
| + // Prevent other interrupts from triggering, for example API callbacks,
|
| + // while dispatching message handler callbacks.
|
| + PostponeInterruptsScope no_interrupts(isolate_);
|
| + DCHECK(is_active_);
|
| + HandleScope scope(isolate_);
|
| + // Process the individual events.
|
| + bool sendEventMessage = false;
|
| + switch (event) {
|
| + case v8::Break:
|
| + sendEventMessage = !auto_continue;
|
| + break;
|
| + case v8::CompileError:
|
| + case v8::AsyncTaskEvent:
|
| + break;
|
| + case v8::Exception:
|
| + case v8::AfterCompile:
|
| + sendEventMessage = true;
|
| + break;
|
| + }
|
| +
|
| + // The debug command interrupt flag might have been set when the command was
|
| + // added. It should be enough to clear the flag only once while we are in the
|
| + // debugger.
|
| + DCHECK(in_debug_scope());
|
| + isolate_->stack_guard()->ClearDebugCommand();
|
| +
|
| + // Notify the debugger that a debug event has occurred unless auto continue is
|
| + // active in which case no event is send.
|
| + if (sendEventMessage) {
|
| + MessageImpl message = MessageImpl::NewEvent(
|
| + event, auto_continue, Handle<JSObject>::cast(exec_state),
|
| + Handle<JSObject>::cast(event_data));
|
| + InvokeMessageHandler(message);
|
| + }
|
| +
|
| + // If auto continue don't make the event cause a break, but process messages
|
| + // in the queue if any. For script collected events don't even process
|
| + // messages in the queue as the execution state might not be what is expected
|
| + // by the client.
|
| + if (auto_continue && !has_commands()) return;
|
| +
|
| + // DebugCommandProcessor goes here.
|
| + bool running = auto_continue;
|
| +
|
| + Handle<Object> cmd_processor_ctor =
|
| + JSReceiver::GetProperty(isolate_, exec_state, "debugCommandProcessor")
|
| + .ToHandleChecked();
|
| + Handle<Object> ctor_args[] = {isolate_->factory()->ToBoolean(running)};
|
| + Handle<JSReceiver> cmd_processor = Handle<JSReceiver>::cast(
|
| + Execution::Call(isolate_, cmd_processor_ctor, exec_state, 1, ctor_args)
|
| + .ToHandleChecked());
|
| + Handle<JSFunction> process_debug_request = Handle<JSFunction>::cast(
|
| + JSReceiver::GetProperty(isolate_, cmd_processor, "processDebugRequest")
|
| + .ToHandleChecked());
|
| + Handle<Object> is_running =
|
| + JSReceiver::GetProperty(isolate_, cmd_processor, "isRunning")
|
| + .ToHandleChecked();
|
| +
|
| + // Process requests from the debugger.
|
| + do {
|
| + // Wait for new command in the queue.
|
| + command_received_.Wait();
|
| +
|
| + // Get the command from the queue.
|
| + CommandMessage command = command_queue_.Get();
|
| + isolate_->logger()->DebugTag(
|
| + "Got request from command queue, in interactive loop.");
|
| + if (!is_active()) {
|
| + // Delete command text and user data.
|
| + command.Dispose();
|
| + return;
|
| + }
|
| +
|
| + Vector<const uc16> command_text(
|
| + const_cast<const uc16*>(command.text().start()),
|
| + command.text().length());
|
| + Handle<String> request_text = isolate_->factory()
|
| + ->NewStringFromTwoByte(command_text)
|
| + .ToHandleChecked();
|
| + Handle<Object> request_args[] = {request_text};
|
| + Handle<Object> answer_value;
|
| + Handle<String> answer;
|
| + MaybeHandle<Object> maybe_exception;
|
| + MaybeHandle<Object> maybe_result = Execution::TryCall(
|
| + isolate_, process_debug_request, cmd_processor, 1, request_args,
|
| + Execution::MessageHandling::kReport, &maybe_exception);
|
| +
|
| + if (maybe_result.ToHandle(&answer_value)) {
|
| + if (answer_value->IsUndefined(isolate_)) {
|
| + answer = isolate_->factory()->empty_string();
|
| + } else {
|
| + answer = Handle<String>::cast(answer_value);
|
| + }
|
| +
|
| + // Log the JSON request/response.
|
| + if (FLAG_trace_debug_json) {
|
| + PrintF("%s\n", request_text->ToCString().get());
|
| + PrintF("%s\n", answer->ToCString().get());
|
| + }
|
| +
|
| + Handle<Object> is_running_args[] = {answer};
|
| + maybe_result = Execution::Call(isolate_, is_running, cmd_processor, 1,
|
| + is_running_args);
|
| + Handle<Object> result;
|
| + if (!maybe_result.ToHandle(&result)) break;
|
| + running = result->IsTrue(isolate_);
|
| + } else {
|
| + Handle<Object> exception;
|
| + if (!maybe_exception.ToHandle(&exception)) break;
|
| + Handle<Object> result;
|
| + if (!Object::ToString(isolate_, exception).ToHandle(&result)) break;
|
| + answer = Handle<String>::cast(result);
|
| + }
|
| +
|
| + // Return the result.
|
| + MessageImpl message = MessageImpl::NewResponse(
|
| + event, running, exec_state, event_data, answer, command.client_data());
|
| + InvokeMessageHandler(message);
|
| + command.Dispose();
|
| +
|
| + // Return from debug event processing if either the VM is put into the
|
| + // running state (through a continue command) or auto continue is active
|
| + // and there are no more commands queued.
|
| + } while (!running || has_commands());
|
| + command_queue_.Clear();
|
| +}
|
|
|
| void Debug::SetEventListener(Handle<Object> callback,
|
| Handle<Object> data) {
|
| @@ -2013,6 +2178,15 @@
|
| UpdateState();
|
| }
|
|
|
| +void Debug::SetMessageHandler(v8::Debug::MessageHandler handler) {
|
| + message_handler_ = handler;
|
| + UpdateState();
|
| + if (handler == NULL && in_debug_scope()) {
|
| + // Send an empty command to the debugger if in a break to make JavaScript
|
| + // run again if the debugger is closed.
|
| + EnqueueCommandMessage(Vector<const uint16_t>::empty());
|
| + }
|
| +}
|
|
|
| void Debug::SetDebugEventListener(debug::DebugEventListener* listener) {
|
| debug_event_listener_ = listener;
|
| @@ -2020,8 +2194,8 @@
|
| }
|
|
|
| void Debug::UpdateState() {
|
| - bool is_active =
|
| - !event_listener_.is_null() || debug_event_listener_ != nullptr;
|
| + bool is_active = message_handler_ != nullptr || !event_listener_.is_null() ||
|
| + debug_event_listener_ != nullptr;
|
| if (is_active || in_debug_scope()) {
|
| // Note that the debug context could have already been loaded to
|
| // bootstrap test cases.
|
| @@ -2039,6 +2213,31 @@
|
| STATIC_ASSERT(LastStepAction == StepFrame);
|
| hook_on_function_call_ = thread_local_.last_step_action_ >= StepIn ||
|
| isolate_->needs_side_effect_check();
|
| +}
|
| +
|
| +// Calls the registered debug message handler. This callback is part of the
|
| +// public API.
|
| +void Debug::InvokeMessageHandler(MessageImpl message) {
|
| + if (message_handler_ != NULL) message_handler_(message);
|
| +}
|
| +
|
| +// 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.
|
| +void Debug::EnqueueCommandMessage(Vector<const uint16_t> command,
|
| + v8::Debug::ClientData* client_data) {
|
| + // Need to cast away const.
|
| + CommandMessage message = CommandMessage::New(
|
| + Vector<uint16_t>(const_cast<uint16_t*>(command.start()),
|
| + command.length()),
|
| + client_data);
|
| + isolate_->logger()->DebugTag("Put command on command_queue.");
|
| + command_queue_.Put(message);
|
| + command_received_.Signal();
|
| +
|
| + // Set the debug command break flag to have the command processed.
|
| + if (!in_debug_scope()) isolate_->stack_guard()->RequestDebugCommand();
|
| }
|
|
|
| MaybeHandle<Object> Debug::Call(Handle<Object> fun, Handle<Object> data) {
|
| @@ -2087,16 +2286,31 @@
|
| }
|
| }
|
|
|
| + // Collect the break state before clearing the flags.
|
| + bool debug_command_only = isolate_->stack_guard()->CheckDebugCommand() &&
|
| + !isolate_->stack_guard()->CheckDebugBreak();
|
| +
|
| isolate_->stack_guard()->ClearDebugBreak();
|
|
|
| // Clear stepping to avoid duplicate breaks.
|
| ClearStepping();
|
| +
|
| + ProcessDebugMessages(debug_command_only);
|
| +}
|
| +
|
| +void Debug::ProcessDebugMessages(bool debug_command_only) {
|
| + isolate_->stack_guard()->ClearDebugCommand();
|
| +
|
| + StackLimitCheck check(isolate_);
|
| + if (check.HasOverflowed()) return;
|
|
|
| HandleScope scope(isolate_);
|
| DebugScope debug_scope(this);
|
| if (debug_scope.failed()) return;
|
|
|
| - OnDebugBreak(isolate_->factory()->undefined_value());
|
| + // Notify the debug event listeners. Indicate auto continue if the break was
|
| + // a debug command break.
|
| + OnDebugBreak(isolate_->factory()->undefined_value(), debug_command_only);
|
| }
|
|
|
| #ifdef DEBUG
|
| @@ -2179,6 +2393,10 @@
|
| // JavaScript. This can happen if the v8::Debug::Call is used in which
|
| // case the exception should end up in the calling code.
|
| if (!isolate()->has_pending_exception()) debug_->ClearMirrorCache();
|
| +
|
| + // If there are commands in the queue when leaving the debugger request
|
| + // that these commands are processed.
|
| + if (debug_->has_commands()) isolate()->stack_guard()->RequestDebugCommand();
|
| }
|
|
|
| // Leaving this debugger entry.
|
| @@ -2237,14 +2455,107 @@
|
| isolate_->debug()->side_effect_check_failed_ = false;
|
| }
|
|
|
| +MessageImpl MessageImpl::NewEvent(DebugEvent event, bool running,
|
| + Handle<JSObject> exec_state,
|
| + Handle<JSObject> event_data) {
|
| + MessageImpl message(true, event, running, exec_state, event_data,
|
| + Handle<String>(), NULL);
|
| + return message;
|
| +}
|
| +
|
| +MessageImpl MessageImpl::NewResponse(DebugEvent event, bool running,
|
| + Handle<JSObject> exec_state,
|
| + Handle<JSObject> event_data,
|
| + Handle<String> response_json,
|
| + v8::Debug::ClientData* client_data) {
|
| + MessageImpl message(false, event, running, exec_state, event_data,
|
| + response_json, client_data);
|
| + return message;
|
| +}
|
| +
|
| +MessageImpl::MessageImpl(bool is_event, DebugEvent event, bool running,
|
| + Handle<JSObject> exec_state,
|
| + Handle<JSObject> event_data,
|
| + Handle<String> response_json,
|
| + v8::Debug::ClientData* client_data)
|
| + : is_event_(is_event),
|
| + event_(event),
|
| + running_(running),
|
| + exec_state_(exec_state),
|
| + event_data_(event_data),
|
| + response_json_(response_json),
|
| + client_data_(client_data) {}
|
| +
|
| +bool MessageImpl::IsEvent() const { return is_event_; }
|
| +
|
| +bool MessageImpl::IsResponse() const { return !is_event_; }
|
| +
|
| +DebugEvent MessageImpl::GetEvent() const { return event_; }
|
| +
|
| +bool MessageImpl::WillStartRunning() const { return running_; }
|
| +
|
| +v8::Local<v8::Object> MessageImpl::GetExecutionState() const {
|
| + return v8::Utils::ToLocal(exec_state_);
|
| +}
|
| +
|
| +v8::Isolate* MessageImpl::GetIsolate() const {
|
| + return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate());
|
| +}
|
| +
|
| +v8::Local<v8::Object> MessageImpl::GetEventData() const {
|
| + return v8::Utils::ToLocal(event_data_);
|
| +}
|
| +
|
| +v8::Local<v8::String> MessageImpl::GetJSON() const {
|
| + Isolate* isolate = event_data_->GetIsolate();
|
| + v8::EscapableHandleScope scope(reinterpret_cast<v8::Isolate*>(isolate));
|
| +
|
| + if (IsEvent()) {
|
| + // Call toJSONProtocol on the debug event object.
|
| + Handle<Object> fun =
|
| + JSReceiver::GetProperty(isolate, event_data_, "toJSONProtocol")
|
| + .ToHandleChecked();
|
| + if (!fun->IsJSFunction()) {
|
| + return v8::Local<v8::String>();
|
| + }
|
| +
|
| + MaybeHandle<Object> maybe_exception;
|
| + MaybeHandle<Object> maybe_json = Execution::TryCall(
|
| + isolate, fun, event_data_, 0, nullptr,
|
| + Execution::MessageHandling::kReport, &maybe_exception);
|
| + Handle<Object> json;
|
| + if (!maybe_json.ToHandle(&json) || !json->IsString()) {
|
| + return v8::Local<v8::String>();
|
| + }
|
| + return scope.Escape(v8::Utils::ToLocal(Handle<String>::cast(json)));
|
| + } else {
|
| + return v8::Utils::ToLocal(response_json_);
|
| + }
|
| +}
|
| +
|
| +v8::Local<v8::Context> MessageImpl::GetEventContext() const {
|
| + Isolate* isolate = event_data_->GetIsolate();
|
| + v8::Local<v8::Context> context = GetDebugEventContext(isolate);
|
| + // Isolate::context() may be NULL when "script collected" event occurs.
|
| + DCHECK(!context.IsEmpty());
|
| + return context;
|
| +}
|
| +
|
| +v8::Debug::ClientData* MessageImpl::GetClientData() const {
|
| + return client_data_;
|
| +}
|
| +
|
| EventDetailsImpl::EventDetailsImpl(DebugEvent event,
|
| Handle<JSObject> exec_state,
|
| Handle<JSObject> event_data,
|
| - Handle<Object> callback_data)
|
| + Handle<Object> callback_data,
|
| + v8::Debug::ClientData* client_data)
|
| : event_(event),
|
| exec_state_(exec_state),
|
| event_data_(event_data),
|
| - callback_data_(callback_data) {}
|
| + callback_data_(callback_data),
|
| + client_data_(client_data) {}
|
| +
|
|
|
| DebugEvent EventDetailsImpl::GetEvent() const {
|
| return event_;
|
| @@ -2271,9 +2582,95 @@
|
| }
|
|
|
|
|
| +v8::Debug::ClientData* EventDetailsImpl::GetClientData() const {
|
| + return client_data_;
|
| +}
|
| +
|
| v8::Isolate* EventDetailsImpl::GetIsolate() const {
|
| return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate());
|
| }
|
|
|
| +CommandMessage::CommandMessage()
|
| + : text_(Vector<uint16_t>::empty()), client_data_(NULL) {}
|
| +
|
| +CommandMessage::CommandMessage(const Vector<uint16_t>& text,
|
| + v8::Debug::ClientData* data)
|
| + : text_(text), client_data_(data) {}
|
| +
|
| +void CommandMessage::Dispose() {
|
| + text_.Dispose();
|
| + delete client_data_;
|
| + client_data_ = NULL;
|
| +}
|
| +
|
| +CommandMessage CommandMessage::New(const Vector<uint16_t>& command,
|
| + v8::Debug::ClientData* data) {
|
| + return CommandMessage(command.Clone(), data);
|
| +}
|
| +
|
| +CommandMessageQueue::CommandMessageQueue(int size)
|
| + : start_(0), end_(0), size_(size) {
|
| + messages_ = NewArray<CommandMessage>(size);
|
| +}
|
| +
|
| +CommandMessageQueue::~CommandMessageQueue() {
|
| + while (!IsEmpty()) Get().Dispose();
|
| + DeleteArray(messages_);
|
| +}
|
| +
|
| +CommandMessage CommandMessageQueue::Get() {
|
| + DCHECK(!IsEmpty());
|
| + int result = start_;
|
| + start_ = (start_ + 1) % size_;
|
| + return messages_[result];
|
| +}
|
| +
|
| +void CommandMessageQueue::Put(const CommandMessage& message) {
|
| + if ((end_ + 1) % size_ == start_) {
|
| + Expand();
|
| + }
|
| + messages_[end_] = message;
|
| + end_ = (end_ + 1) % size_;
|
| +}
|
| +
|
| +void CommandMessageQueue::Expand() {
|
| + CommandMessageQueue new_queue(size_ * 2);
|
| + while (!IsEmpty()) {
|
| + new_queue.Put(Get());
|
| + }
|
| + CommandMessage* array_to_free = messages_;
|
| + *this = new_queue;
|
| + new_queue.messages_ = array_to_free;
|
| + // Make the new_queue empty so that it doesn't call Dispose on any messages.
|
| + new_queue.start_ = new_queue.end_;
|
| + // Automatic destructor called on new_queue, freeing array_to_free.
|
| +}
|
| +
|
| +LockingCommandMessageQueue::LockingCommandMessageQueue(Logger* logger, int size)
|
| + : logger_(logger), queue_(size) {}
|
| +
|
| +bool LockingCommandMessageQueue::IsEmpty() const {
|
| + base::LockGuard<base::Mutex> lock_guard(&mutex_);
|
| + return queue_.IsEmpty();
|
| +}
|
| +
|
| +CommandMessage LockingCommandMessageQueue::Get() {
|
| + base::LockGuard<base::Mutex> lock_guard(&mutex_);
|
| + CommandMessage result = queue_.Get();
|
| + logger_->DebugEvent("Get", result.text());
|
| + return result;
|
| +}
|
| +
|
| +void LockingCommandMessageQueue::Put(const CommandMessage& message) {
|
| + base::LockGuard<base::Mutex> lock_guard(&mutex_);
|
| + queue_.Put(message);
|
| + logger_->DebugEvent("Put", message.text());
|
| +}
|
| +
|
| +void LockingCommandMessageQueue::Clear() {
|
| + base::LockGuard<base::Mutex> lock_guard(&mutex_);
|
| + queue_.Clear();
|
| +}
|
| +
|
| } // namespace internal
|
| } // namespace v8
|
|
|