summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/inspector/agents/InspectorConsoleAgent.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/inspector/agents/InspectorConsoleAgent.cpp')
-rw-r--r--Source/JavaScriptCore/inspector/agents/InspectorConsoleAgent.cpp238
1 files changed, 238 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/inspector/agents/InspectorConsoleAgent.cpp b/Source/JavaScriptCore/inspector/agents/InspectorConsoleAgent.cpp
new file mode 100644
index 000000000..d453dbbd8
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/agents/InspectorConsoleAgent.cpp
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "config.h"
+#include "InspectorConsoleAgent.h"
+
+#include "ConsoleMessage.h"
+#include "InjectedScriptManager.h"
+#include "InspectorFrontendRouter.h"
+#include "InspectorHeapAgent.h"
+#include "ScriptArguments.h"
+#include "ScriptCallFrame.h"
+#include "ScriptCallStack.h"
+#include "ScriptCallStackFactory.h"
+#include "ScriptObject.h"
+#include <wtf/CurrentTime.h>
+#include <wtf/text/WTFString.h>
+
+namespace Inspector {
+
+static const unsigned maximumConsoleMessages = 100;
+static const int expireConsoleMessagesStep = 10;
+
+InspectorConsoleAgent::InspectorConsoleAgent(AgentContext& context, InspectorHeapAgent* heapAgent)
+ : InspectorAgentBase(ASCIILiteral("Console"))
+ , m_injectedScriptManager(context.injectedScriptManager)
+ , m_frontendDispatcher(std::make_unique<ConsoleFrontendDispatcher>(context.frontendRouter))
+ , m_backendDispatcher(ConsoleBackendDispatcher::create(context.backendDispatcher, this))
+ , m_heapAgent(heapAgent)
+{
+}
+
+InspectorConsoleAgent::~InspectorConsoleAgent()
+{
+}
+
+void InspectorConsoleAgent::didCreateFrontendAndBackend(FrontendRouter*, BackendDispatcher*)
+{
+}
+
+void InspectorConsoleAgent::willDestroyFrontendAndBackend(DisconnectReason)
+{
+ String errorString;
+ disable(errorString);
+}
+
+void InspectorConsoleAgent::discardValues()
+{
+ m_consoleMessages.clear();
+}
+
+void InspectorConsoleAgent::enable(ErrorString&)
+{
+ if (m_enabled)
+ return;
+
+ m_enabled = true;
+
+ if (m_expiredConsoleMessageCount) {
+ ConsoleMessage expiredMessage(MessageSource::Other, MessageType::Log, MessageLevel::Warning, String::format("%d console messages are not shown.", m_expiredConsoleMessageCount));
+ expiredMessage.addToFrontend(*m_frontendDispatcher, m_injectedScriptManager, false);
+ }
+
+ size_t messageCount = m_consoleMessages.size();
+ for (size_t i = 0; i < messageCount; ++i)
+ m_consoleMessages[i]->addToFrontend(*m_frontendDispatcher, m_injectedScriptManager, false);
+}
+
+void InspectorConsoleAgent::disable(ErrorString&)
+{
+ if (!m_enabled)
+ return;
+
+ m_enabled = false;
+}
+
+void InspectorConsoleAgent::clearMessages(ErrorString&)
+{
+ m_consoleMessages.clear();
+ m_expiredConsoleMessageCount = 0;
+ m_previousMessage = nullptr;
+
+ m_injectedScriptManager.releaseObjectGroup(ASCIILiteral("console"));
+
+ if (m_enabled)
+ m_frontendDispatcher->messagesCleared();
+}
+
+void InspectorConsoleAgent::reset()
+{
+ ErrorString unused;
+ clearMessages(unused);
+
+ m_times.clear();
+ m_counts.clear();
+}
+
+void InspectorConsoleAgent::addMessageToConsole(std::unique_ptr<ConsoleMessage> message)
+{
+ if (!m_injectedScriptManager.inspectorEnvironment().developerExtrasEnabled())
+ return;
+
+ if (message->type() == MessageType::Clear) {
+ ErrorString unused;
+ clearMessages(unused);
+ }
+
+ addConsoleMessage(WTFMove(message));
+}
+
+void InspectorConsoleAgent::startTiming(const String& title)
+{
+ ASSERT(!title.isNull());
+ if (title.isNull())
+ return;
+
+ auto result = m_times.add(title, monotonicallyIncreasingTime());
+
+ if (!result.isNewEntry) {
+ // FIXME: Send an enum to the frontend for localization?
+ String warning = makeString("Timer \"", title, "\" already exists");
+ addMessageToConsole(std::make_unique<ConsoleMessage>(MessageSource::ConsoleAPI, MessageType::Timing, MessageLevel::Warning, warning));
+ }
+}
+
+void InspectorConsoleAgent::stopTiming(const String& title, Ref<ScriptCallStack>&& callStack)
+{
+ ASSERT(!title.isNull());
+ if (title.isNull())
+ return;
+
+ auto it = m_times.find(title);
+ if (it == m_times.end()) {
+ // FIXME: Send an enum to the frontend for localization?
+ String warning = makeString("Timer \"", title, "\" does not exist");
+ addMessageToConsole(std::make_unique<ConsoleMessage>(MessageSource::ConsoleAPI, MessageType::Timing, MessageLevel::Warning, warning));
+ return;
+ }
+
+ double startTime = it->value;
+ m_times.remove(it);
+
+ double elapsed = monotonicallyIncreasingTime() - startTime;
+ String message = title + String::format(": %.3fms", elapsed * 1000);
+ addMessageToConsole(std::make_unique<ConsoleMessage>(MessageSource::ConsoleAPI, MessageType::Timing, MessageLevel::Debug, message, WTFMove(callStack)));
+}
+
+void InspectorConsoleAgent::takeHeapSnapshot(const String& title)
+{
+ if (!m_injectedScriptManager.inspectorEnvironment().developerExtrasEnabled())
+ return;
+
+ ErrorString ignored;
+ double timestamp;
+ String snapshotData;
+ m_heapAgent->snapshot(ignored, &timestamp, &snapshotData);
+
+ m_frontendDispatcher->heapSnapshot(timestamp, snapshotData, title.isEmpty() ? nullptr : &title);
+}
+
+void InspectorConsoleAgent::count(JSC::ExecState* state, Ref<ScriptArguments>&& arguments)
+{
+ Ref<ScriptCallStack> callStack = createScriptCallStackForConsole(state, ScriptCallStack::maxCallStackSizeToCapture);
+
+ String title;
+ String identifier;
+ if (!arguments->argumentCount()) {
+ // '@' prefix for engine generated labels.
+ title = ASCIILiteral("Global");
+ identifier = makeString('@', title);
+ } else {
+ // '#' prefix for user labels.
+ arguments->getFirstArgumentAsString(title);
+ identifier = makeString('#', title);
+ }
+
+ auto result = m_counts.add(identifier, 1);
+ if (!result.isNewEntry)
+ result.iterator->value += 1;
+
+ // FIXME: Web Inspector should have a better UI for counters, but for now we just log an updated counter value.
+
+ String message = makeString(title, ": ", String::number(result.iterator->value));
+ addMessageToConsole(std::make_unique<ConsoleMessage>(MessageSource::ConsoleAPI, MessageType::Log, MessageLevel::Debug, message, WTFMove(callStack)));
+}
+
+static bool isGroupMessage(MessageType type)
+{
+ return type == MessageType::StartGroup
+ || type == MessageType::StartGroupCollapsed
+ || type == MessageType::EndGroup;
+}
+
+void InspectorConsoleAgent::addConsoleMessage(std::unique_ptr<ConsoleMessage> consoleMessage)
+{
+ ASSERT(m_injectedScriptManager.inspectorEnvironment().developerExtrasEnabled());
+ ASSERT_ARG(consoleMessage, consoleMessage);
+
+ if (m_previousMessage && !isGroupMessage(m_previousMessage->type()) && m_previousMessage->isEqual(consoleMessage.get())) {
+ m_previousMessage->incrementCount();
+ if (m_enabled)
+ m_previousMessage->updateRepeatCountInConsole(*m_frontendDispatcher);
+ } else {
+ m_previousMessage = consoleMessage.get();
+ m_consoleMessages.append(WTFMove(consoleMessage));
+ if (m_enabled)
+ m_previousMessage->addToFrontend(*m_frontendDispatcher, m_injectedScriptManager, true);
+ }
+
+ if (m_consoleMessages.size() >= maximumConsoleMessages) {
+ m_expiredConsoleMessageCount += expireConsoleMessagesStep;
+ m_consoleMessages.remove(0, expireConsoleMessagesStep);
+ }
+}
+
+} // namespace Inspector