summaryrefslogtreecommitdiffstats
path: root/Source/JavaScriptCore/profiler
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-06 11:45:16 +0100
committerSteve Block <steveblock@google.com>2011-05-12 13:44:10 +0100
commitcad810f21b803229eb11403f9209855525a25d57 (patch)
tree29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/JavaScriptCore/profiler
parent121b0cf4517156d0ac5111caf9830c51b69bae8f (diff)
downloadexternal_webkit-cad810f21b803229eb11403f9209855525a25d57.zip
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/JavaScriptCore/profiler')
-rw-r--r--Source/JavaScriptCore/profiler/CallIdentifier.h100
-rw-r--r--Source/JavaScriptCore/profiler/Profile.cpp136
-rw-r--r--Source/JavaScriptCore/profiler/Profile.h72
-rw-r--r--Source/JavaScriptCore/profiler/ProfileGenerator.cpp181
-rw-r--r--Source/JavaScriptCore/profiler/ProfileGenerator.h79
-rw-r--r--Source/JavaScriptCore/profiler/ProfileNode.cpp351
-rw-r--r--Source/JavaScriptCore/profiler/ProfileNode.h172
-rw-r--r--Source/JavaScriptCore/profiler/Profiler.cpp172
-rw-r--r--Source/JavaScriptCore/profiler/Profiler.h77
-rw-r--r--Source/JavaScriptCore/profiler/ProfilerServer.h35
-rw-r--r--Source/JavaScriptCore/profiler/ProfilerServer.mm115
11 files changed, 1490 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/profiler/CallIdentifier.h b/Source/JavaScriptCore/profiler/CallIdentifier.h
new file mode 100644
index 0000000..76c1470
--- /dev/null
+++ b/Source/JavaScriptCore/profiler/CallIdentifier.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2008 Apple 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. ``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
+ * 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.
+ */
+
+
+#ifndef CallIdentifier_h
+#define CallIdentifier_h
+
+#include <runtime/UString.h>
+#include "FastAllocBase.h"
+#include <wtf/text/CString.h>
+#include <wtf/text/StringHash.h>
+
+namespace JSC {
+
+ struct CallIdentifier : public FastAllocBase {
+ UString m_name;
+ UString m_url;
+ unsigned m_lineNumber;
+
+ CallIdentifier()
+ : m_lineNumber(0)
+ {
+ }
+
+ CallIdentifier(const UString& name, const UString& url, int lineNumber)
+ : m_name(name)
+ , m_url(!url.isNull() ? url : "")
+ , m_lineNumber(lineNumber)
+ {
+ }
+
+ inline bool operator==(const CallIdentifier& ci) const { return ci.m_lineNumber == m_lineNumber && ci.m_name == m_name && ci.m_url == m_url; }
+ inline bool operator!=(const CallIdentifier& ci) const { return !(*this == ci); }
+
+ struct Hash {
+ static unsigned hash(const CallIdentifier& key)
+ {
+ unsigned hashCodes[3] = {
+ key.m_name.impl()->hash(),
+ key.m_url.impl()->hash(),
+ key.m_lineNumber
+ };
+ return WTF::StringHasher::createBlobHash<sizeof(hashCodes)>(hashCodes);
+ }
+
+ static bool equal(const CallIdentifier& a, const CallIdentifier& b) { return a == b; }
+ static const bool safeToCompareToEmptyOrDeleted = true;
+ };
+
+ unsigned hash() const { return Hash::hash(*this); }
+
+#ifndef NDEBUG
+ operator const char*() const { return c_str(); }
+ const char* c_str() const { return m_name.utf8().data(); }
+#endif
+ };
+
+} // namespace JSC
+
+namespace WTF {
+
+ template<> struct DefaultHash<JSC::CallIdentifier> { typedef JSC::CallIdentifier::Hash Hash; };
+
+ template<> struct HashTraits<JSC::CallIdentifier> : GenericHashTraits<JSC::CallIdentifier> {
+ static void constructDeletedValue(JSC::CallIdentifier& slot)
+ {
+ new (&slot) JSC::CallIdentifier(JSC::UString(), JSC::UString(), std::numeric_limits<unsigned>::max());
+ }
+ static bool isDeletedValue(const JSC::CallIdentifier& value)
+ {
+ return value.m_name.isNull() && value.m_url.isNull() && value.m_lineNumber == std::numeric_limits<unsigned>::max();
+ }
+ };
+
+} // namespace WTF
+
+#endif // CallIdentifier_h
+
diff --git a/Source/JavaScriptCore/profiler/Profile.cpp b/Source/JavaScriptCore/profiler/Profile.cpp
new file mode 100644
index 0000000..1a84518
--- /dev/null
+++ b/Source/JavaScriptCore/profiler/Profile.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2008 Apple 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. ``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
+ * 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 "Profile.h"
+
+#include "ProfileNode.h"
+#include <stdio.h>
+
+namespace JSC {
+
+PassRefPtr<Profile> Profile::create(const UString& title, unsigned uid)
+{
+ return adoptRef(new Profile(title, uid));
+}
+
+Profile::Profile(const UString& title, unsigned uid)
+ : m_title(title)
+ , m_uid(uid)
+{
+ // FIXME: When multi-threading is supported this will be a vector and calls
+ // into the profiler will need to know which thread it is executing on.
+ m_head = ProfileNode::create(0, CallIdentifier("Thread_1", UString(), 0), 0, 0);
+}
+
+Profile::~Profile()
+{
+}
+
+void Profile::forEach(void (ProfileNode::*function)())
+{
+ ProfileNode* currentNode = m_head->firstChild();
+ for (ProfileNode* nextNode = currentNode; nextNode; nextNode = nextNode->firstChild())
+ currentNode = nextNode;
+
+ if (!currentNode)
+ currentNode = m_head.get();
+
+ ProfileNode* endNode = m_head->traverseNextNodePostOrder();
+ while (currentNode && currentNode != endNode) {
+ (currentNode->*function)();
+ currentNode = currentNode->traverseNextNodePostOrder();
+ }
+}
+
+void Profile::focus(const ProfileNode* profileNode)
+{
+ if (!profileNode || !m_head)
+ return;
+
+ bool processChildren;
+ const CallIdentifier& callIdentifier = profileNode->callIdentifier();
+ for (ProfileNode* currentNode = m_head.get(); currentNode; currentNode = currentNode->traverseNextNodePreOrder(processChildren))
+ processChildren = currentNode->focus(callIdentifier);
+
+ // Set the visible time of all nodes so that the %s display correctly.
+ forEach(&ProfileNode::calculateVisibleTotalTime);
+}
+
+void Profile::exclude(const ProfileNode* profileNode)
+{
+ if (!profileNode || !m_head)
+ return;
+
+ const CallIdentifier& callIdentifier = profileNode->callIdentifier();
+
+ for (ProfileNode* currentNode = m_head.get(); currentNode; currentNode = currentNode->traverseNextNodePreOrder())
+ currentNode->exclude(callIdentifier);
+
+ // Set the visible time of the head so the %s display correctly.
+ m_head->setVisibleTotalTime(m_head->totalTime() - m_head->selfTime());
+ m_head->setVisibleSelfTime(0.0);
+}
+
+void Profile::restoreAll()
+{
+ forEach(&ProfileNode::restore);
+}
+
+#ifndef NDEBUG
+void Profile::debugPrintData() const
+{
+ printf("Call graph:\n");
+ m_head->debugPrintData(0);
+}
+
+typedef pair<StringImpl*, unsigned> NameCountPair;
+
+static inline bool functionNameCountPairComparator(const NameCountPair& a, const NameCountPair& b)
+{
+ return a.second > b.second;
+}
+
+void Profile::debugPrintDataSampleStyle() const
+{
+ typedef Vector<NameCountPair> NameCountPairVector;
+
+ FunctionCallHashCount countedFunctions;
+ printf("Call graph:\n");
+ m_head->debugPrintDataSampleStyle(0, countedFunctions);
+
+ printf("\nTotal number in stack:\n");
+ NameCountPairVector sortedFunctions(countedFunctions.size());
+ copyToVector(countedFunctions, sortedFunctions);
+
+ std::sort(sortedFunctions.begin(), sortedFunctions.end(), functionNameCountPairComparator);
+ for (NameCountPairVector::iterator it = sortedFunctions.begin(); it != sortedFunctions.end(); ++it)
+ printf(" %-12d%s\n", (*it).second, UString((*it).first).utf8().data());
+
+ printf("\nSort by top of stack, same collapsed (when >= 5):\n");
+}
+#endif
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/profiler/Profile.h b/Source/JavaScriptCore/profiler/Profile.h
new file mode 100644
index 0000000..6bf29f7
--- /dev/null
+++ b/Source/JavaScriptCore/profiler/Profile.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2008 Apple 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. ``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
+ * 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.
+ */
+
+#ifndef Profile_h
+#define Profile_h
+
+#include "ProfileNode.h"
+#include <runtime/UString.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace JSC {
+
+ class Profile : public RefCounted<Profile> {
+ public:
+ static PassRefPtr<Profile> create(const UString& title, unsigned uid);
+ virtual ~Profile();
+
+ const UString& title() const { return m_title; }
+ ProfileNode* head() const { return m_head.get(); }
+ void setHead(PassRefPtr<ProfileNode> head) { m_head = head; }
+ double totalTime() const { return m_head->totalTime(); }
+ unsigned int uid() const { return m_uid; }
+
+ void forEach(void (ProfileNode::*)());
+
+ void focus(const ProfileNode*);
+ void exclude(const ProfileNode*);
+ void restoreAll();
+
+#ifndef NDEBUG
+ void debugPrintData() const;
+ void debugPrintDataSampleStyle() const;
+#endif
+
+ protected:
+ Profile(const UString& title, unsigned uid);
+
+ private:
+ void removeProfileStart();
+ void removeProfileEnd();
+
+ UString m_title;
+ RefPtr<ProfileNode> m_head;
+ unsigned int m_uid;
+ };
+
+} // namespace JSC
+
+#endif // Profile_h
diff --git a/Source/JavaScriptCore/profiler/ProfileGenerator.cpp b/Source/JavaScriptCore/profiler/ProfileGenerator.cpp
new file mode 100644
index 0000000..68d1733
--- /dev/null
+++ b/Source/JavaScriptCore/profiler/ProfileGenerator.cpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2008 Apple 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. ``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
+ * 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 "ProfileGenerator.h"
+
+#include "CallFrame.h"
+#include "CodeBlock.h"
+#include "JSGlobalObject.h"
+#include "JSStringRef.h"
+#include "JSFunction.h"
+#include "Interpreter.h"
+#include "Profile.h"
+#include "Profiler.h"
+#include "Tracing.h"
+
+namespace JSC {
+
+static const char* NonJSExecution = "(idle)";
+
+PassRefPtr<ProfileGenerator> ProfileGenerator::create(const UString& title, ExecState* originatingExec, unsigned uid)
+{
+ return adoptRef(new ProfileGenerator(title, originatingExec, uid));
+}
+
+ProfileGenerator::ProfileGenerator(const UString& title, ExecState* originatingExec, unsigned uid)
+ : m_originatingGlobalExec(originatingExec ? originatingExec->lexicalGlobalObject()->globalExec() : 0)
+ , m_profileGroup(originatingExec ? originatingExec->lexicalGlobalObject()->profileGroup() : 0)
+{
+ m_profile = Profile::create(title, uid);
+ m_currentNode = m_head = m_profile->head();
+ if (originatingExec)
+ addParentForConsoleStart(originatingExec);
+}
+
+void ProfileGenerator::addParentForConsoleStart(ExecState* exec)
+{
+ int lineNumber;
+ intptr_t sourceID;
+ UString sourceURL;
+ JSValue function;
+
+ exec->interpreter()->retrieveLastCaller(exec, lineNumber, sourceID, sourceURL, function);
+ m_currentNode = ProfileNode::create(exec, Profiler::createCallIdentifier(exec, function ? function.toThisObject(exec) : 0, sourceURL, lineNumber), m_head.get(), m_head.get());
+ m_head->insertNode(m_currentNode.get());
+}
+
+const UString& ProfileGenerator::title() const
+{
+ return m_profile->title();
+}
+
+void ProfileGenerator::willExecute(ExecState* callerCallFrame, const CallIdentifier& callIdentifier)
+{
+ if (JAVASCRIPTCORE_PROFILE_WILL_EXECUTE_ENABLED()) {
+ CString name = callIdentifier.m_name.utf8();
+ CString url = callIdentifier.m_url.utf8();
+ JAVASCRIPTCORE_PROFILE_WILL_EXECUTE(m_profileGroup, const_cast<char*>(name.data()), const_cast<char*>(url.data()), callIdentifier.m_lineNumber);
+ }
+
+ if (!m_originatingGlobalExec)
+ return;
+
+ ASSERT(m_currentNode);
+ m_currentNode = m_currentNode->willExecute(callerCallFrame, callIdentifier);
+}
+
+void ProfileGenerator::didExecute(ExecState* callerCallFrame, const CallIdentifier& callIdentifier)
+{
+ if (JAVASCRIPTCORE_PROFILE_DID_EXECUTE_ENABLED()) {
+ CString name = callIdentifier.m_name.utf8();
+ CString url = callIdentifier.m_url.utf8();
+ JAVASCRIPTCORE_PROFILE_DID_EXECUTE(m_profileGroup, const_cast<char*>(name.data()), const_cast<char*>(url.data()), callIdentifier.m_lineNumber);
+ }
+
+ if (!m_originatingGlobalExec)
+ return;
+
+ ASSERT(m_currentNode);
+ if (m_currentNode->callIdentifier() != callIdentifier) {
+ RefPtr<ProfileNode> returningNode = ProfileNode::create(callerCallFrame, callIdentifier, m_head.get(), m_currentNode.get());
+ returningNode->setStartTime(m_currentNode->startTime());
+ returningNode->didExecute();
+ m_currentNode->insertNode(returningNode.release());
+ return;
+ }
+
+ m_currentNode = m_currentNode->didExecute();
+}
+
+void ProfileGenerator::exceptionUnwind(ExecState* handlerCallFrame, const CallIdentifier&)
+{
+ // If the current node was called by the handler (==) or any
+ // more nested function (>) the we have exited early from it.
+ ASSERT(m_currentNode);
+ while (m_currentNode->callerCallFrame() >= handlerCallFrame) {
+ didExecute(m_currentNode->callerCallFrame(), m_currentNode->callIdentifier());
+ ASSERT(m_currentNode);
+ }
+}
+
+void ProfileGenerator::stopProfiling()
+{
+ m_profile->forEach(&ProfileNode::stopProfiling);
+
+ removeProfileStart();
+ removeProfileEnd();
+
+ ASSERT(m_currentNode);
+
+ // Set the current node to the parent, because we are in a call that
+ // will not get didExecute call.
+ m_currentNode = m_currentNode->parent();
+
+ if (double headSelfTime = m_head->selfTime()) {
+ RefPtr<ProfileNode> idleNode = ProfileNode::create(0, CallIdentifier(NonJSExecution, UString(), 0), m_head.get(), m_head.get());
+
+ idleNode->setTotalTime(headSelfTime);
+ idleNode->setSelfTime(headSelfTime);
+ idleNode->setVisible(true);
+
+ m_head->setSelfTime(0.0);
+ m_head->addChild(idleNode.release());
+ }
+}
+
+// The console.ProfileGenerator that started this ProfileGenerator will be the first child.
+void ProfileGenerator::removeProfileStart()
+{
+ ProfileNode* currentNode = 0;
+ for (ProfileNode* next = m_head.get(); next; next = next->firstChild())
+ currentNode = next;
+
+ if (currentNode->callIdentifier().m_name != "profile")
+ return;
+
+ // Attribute the time of the node aobut to be removed to the self time of its parent
+ currentNode->parent()->setSelfTime(currentNode->parent()->selfTime() + currentNode->totalTime());
+ currentNode->parent()->removeChild(currentNode);
+}
+
+// The console.ProfileGeneratorEnd that stopped this ProfileGenerator will be the last child.
+void ProfileGenerator::removeProfileEnd()
+{
+ ProfileNode* currentNode = 0;
+ for (ProfileNode* next = m_head.get(); next; next = next->lastChild())
+ currentNode = next;
+
+ if (currentNode->callIdentifier().m_name != "profileEnd")
+ return;
+
+ // Attribute the time of the node aobut to be removed to the self time of its parent
+ currentNode->parent()->setSelfTime(currentNode->parent()->selfTime() + currentNode->totalTime());
+
+ ASSERT(currentNode->callIdentifier() == (currentNode->parent()->children()[currentNode->parent()->children().size() - 1])->callIdentifier());
+ currentNode->parent()->removeChild(currentNode);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/profiler/ProfileGenerator.h b/Source/JavaScriptCore/profiler/ProfileGenerator.h
new file mode 100644
index 0000000..cbed73b
--- /dev/null
+++ b/Source/JavaScriptCore/profiler/ProfileGenerator.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2008 Apple 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. ``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
+ * 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.
+ */
+
+#ifndef ProfileGenerator_h
+#define ProfileGenerator_h
+
+#include "Profile.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace JSC {
+
+ class ExecState;
+ class Profile;
+ class ProfileNode;
+ class UString;
+ struct CallIdentifier;
+
+ class ProfileGenerator : public RefCounted<ProfileGenerator> {
+ public:
+ static PassRefPtr<ProfileGenerator> create(const UString& title, ExecState* originatingExec, unsigned uid);
+
+ // Members
+ const UString& title() const;
+ PassRefPtr<Profile> profile() const { return m_profile; }
+ ExecState* originatingGlobalExec() const { return m_originatingGlobalExec; }
+ unsigned profileGroup() const { return m_profileGroup; }
+
+ // Collecting
+ void willExecute(ExecState* callerCallFrame, const CallIdentifier&);
+ void didExecute(ExecState* callerCallFrame, const CallIdentifier&);
+
+ void exceptionUnwind(ExecState* handlerCallFrame, const CallIdentifier&);
+
+ // Stopping Profiling
+ void stopProfiling();
+
+ typedef void (ProfileGenerator::*ProfileFunction)(ExecState* callerOrHandlerCallFrame, const CallIdentifier& callIdentifier);
+
+ private:
+ ProfileGenerator(const UString& title, ExecState* originatingExec, unsigned uid);
+ void addParentForConsoleStart(ExecState*);
+
+ void removeProfileStart();
+ void removeProfileEnd();
+
+ RefPtr<Profile> m_profile;
+ ExecState* m_originatingGlobalExec;
+ unsigned m_profileGroup;
+ RefPtr<ProfileNode> m_head;
+ RefPtr<ProfileNode> m_currentNode;
+ };
+
+} // namespace JSC
+
+#endif // ProfileGenerator_h
diff --git a/Source/JavaScriptCore/profiler/ProfileNode.cpp b/Source/JavaScriptCore/profiler/ProfileNode.cpp
new file mode 100644
index 0000000..8f20bbe
--- /dev/null
+++ b/Source/JavaScriptCore/profiler/ProfileNode.cpp
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2008 Apple 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE 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 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 "ProfileNode.h"
+
+#include "Profiler.h"
+#include <stdio.h>
+#include <wtf/DateMath.h>
+#include <wtf/text/StringHash.h>
+
+#if OS(WINDOWS)
+#include <windows.h>
+#endif
+
+using namespace WTF;
+
+namespace JSC {
+
+static double getCount()
+{
+#if OS(WINDOWS)
+ static LARGE_INTEGER frequency;
+ if (!frequency.QuadPart)
+ QueryPerformanceFrequency(&frequency);
+ LARGE_INTEGER counter;
+ QueryPerformanceCounter(&counter);
+ return static_cast<double>(counter.QuadPart) / frequency.QuadPart;
+#else
+ return currentTimeMS();
+#endif
+}
+
+ProfileNode::ProfileNode(ExecState* callerCallFrame, const CallIdentifier& callIdentifier, ProfileNode* headNode, ProfileNode* parentNode)
+ : m_callerCallFrame(callerCallFrame)
+ , m_callIdentifier(callIdentifier)
+ , m_head(headNode)
+ , m_parent(parentNode)
+ , m_nextSibling(0)
+ , m_startTime(0.0)
+ , m_actualTotalTime(0.0)
+ , m_visibleTotalTime(0.0)
+ , m_actualSelfTime(0.0)
+ , m_visibleSelfTime(0.0)
+ , m_numberOfCalls(0)
+ , m_visible(true)
+{
+ startTimer();
+}
+
+ProfileNode::ProfileNode(ExecState* callerCallFrame, ProfileNode* headNode, ProfileNode* nodeToCopy)
+ : m_callerCallFrame(callerCallFrame)
+ , m_callIdentifier(nodeToCopy->callIdentifier())
+ , m_head(headNode)
+ , m_parent(nodeToCopy->parent())
+ , m_nextSibling(0)
+ , m_startTime(0.0)
+ , m_actualTotalTime(nodeToCopy->actualTotalTime())
+ , m_visibleTotalTime(nodeToCopy->totalTime())
+ , m_actualSelfTime(nodeToCopy->actualSelfTime())
+ , m_visibleSelfTime(nodeToCopy->selfTime())
+ , m_numberOfCalls(nodeToCopy->numberOfCalls())
+ , m_visible(nodeToCopy->visible())
+{
+}
+
+ProfileNode* ProfileNode::willExecute(ExecState* callerCallFrame, const CallIdentifier& callIdentifier)
+{
+ for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild) {
+ if ((*currentChild)->callIdentifier() == callIdentifier) {
+ (*currentChild)->startTimer();
+ return (*currentChild).get();
+ }
+ }
+
+ RefPtr<ProfileNode> newChild = ProfileNode::create(callerCallFrame, callIdentifier, m_head ? m_head : this, this); // If this ProfileNode has no head it is the head.
+ if (m_children.size())
+ m_children.last()->setNextSibling(newChild.get());
+ m_children.append(newChild.release());
+ return m_children.last().get();
+}
+
+ProfileNode* ProfileNode::didExecute()
+{
+ endAndRecordCall();
+ return m_parent;
+}
+
+void ProfileNode::addChild(PassRefPtr<ProfileNode> prpChild)
+{
+ RefPtr<ProfileNode> child = prpChild;
+ child->setParent(this);
+ if (m_children.size())
+ m_children.last()->setNextSibling(child.get());
+ m_children.append(child.release());
+}
+
+ProfileNode* ProfileNode::findChild(ProfileNode* node) const
+{
+ if (!node)
+ return 0;
+
+ for (size_t i = 0; i < m_children.size(); ++i) {
+ if (*node == m_children[i].get())
+ return m_children[i].get();
+ }
+
+ return 0;
+}
+
+void ProfileNode::removeChild(ProfileNode* node)
+{
+ if (!node)
+ return;
+
+ for (size_t i = 0; i < m_children.size(); ++i) {
+ if (*node == m_children[i].get()) {
+ m_children.remove(i);
+ break;
+ }
+ }
+
+ resetChildrensSiblings();
+}
+
+void ProfileNode::insertNode(PassRefPtr<ProfileNode> prpNode)
+{
+ RefPtr<ProfileNode> node = prpNode;
+
+ for (unsigned i = 0; i < m_children.size(); ++i)
+ node->addChild(m_children[i].release());
+
+ m_children.clear();
+ m_children.append(node.release());
+}
+
+void ProfileNode::stopProfiling()
+{
+ if (m_startTime)
+ endAndRecordCall();
+
+ m_visibleTotalTime = m_actualTotalTime;
+
+ ASSERT(m_actualSelfTime == 0.0 && m_startTime == 0.0);
+
+ // Because we iterate in post order all of our children have been stopped before us.
+ for (unsigned i = 0; i < m_children.size(); ++i)
+ m_actualSelfTime += m_children[i]->totalTime();
+
+ ASSERT(m_actualSelfTime <= m_actualTotalTime);
+ m_actualSelfTime = m_actualTotalTime - m_actualSelfTime;
+ m_visibleSelfTime = m_actualSelfTime;
+}
+
+ProfileNode* ProfileNode::traverseNextNodePostOrder() const
+{
+ ProfileNode* next = m_nextSibling;
+ if (!next)
+ return m_parent;
+ while (ProfileNode* firstChild = next->firstChild())
+ next = firstChild;
+ return next;
+}
+
+ProfileNode* ProfileNode::traverseNextNodePreOrder(bool processChildren) const
+{
+ if (processChildren && m_children.size())
+ return m_children[0].get();
+
+ if (m_nextSibling)
+ return m_nextSibling;
+
+ ProfileNode* nextParent = m_parent;
+ if (!nextParent)
+ return 0;
+
+ ProfileNode* next;
+ for (next = m_parent->nextSibling(); !next; next = nextParent->nextSibling()) {
+ nextParent = nextParent->parent();
+ if (!nextParent)
+ return 0;
+ }
+
+ return next;
+}
+
+void ProfileNode::setTreeVisible(ProfileNode* node, bool visible)
+{
+ ProfileNode* nodeParent = node->parent();
+ ProfileNode* nodeSibling = node->nextSibling();
+ node->setParent(0);
+ node->setNextSibling(0);
+
+ for (ProfileNode* currentNode = node; currentNode; currentNode = currentNode->traverseNextNodePreOrder())
+ currentNode->setVisible(visible);
+
+ node->setParent(nodeParent);
+ node->setNextSibling(nodeSibling);
+}
+
+void ProfileNode::calculateVisibleTotalTime()
+{
+ double sumOfVisibleChildrensTime = 0.0;
+
+ for (unsigned i = 0; i < m_children.size(); ++i) {
+ if (m_children[i]->visible())
+ sumOfVisibleChildrensTime += m_children[i]->totalTime();
+ }
+
+ m_visibleTotalTime = m_visibleSelfTime + sumOfVisibleChildrensTime;
+}
+
+bool ProfileNode::focus(const CallIdentifier& callIdentifier)
+{
+ if (!m_visible)
+ return false;
+
+ if (m_callIdentifier != callIdentifier) {
+ m_visible = false;
+ return true;
+ }
+
+ for (ProfileNode* currentParent = m_parent; currentParent; currentParent = currentParent->parent())
+ currentParent->setVisible(true);
+
+ return false;
+}
+
+void ProfileNode::exclude(const CallIdentifier& callIdentifier)
+{
+ if (m_visible && m_callIdentifier == callIdentifier) {
+ setTreeVisible(this, false);
+
+ m_parent->setVisibleSelfTime(m_parent->selfTime() + m_visibleTotalTime);
+ }
+}
+
+void ProfileNode::restore()
+{
+ m_visibleTotalTime = m_actualTotalTime;
+ m_visibleSelfTime = m_actualSelfTime;
+ m_visible = true;
+}
+
+void ProfileNode::endAndRecordCall()
+{
+ m_actualTotalTime += m_startTime ? getCount() - m_startTime : 0.0;
+ m_startTime = 0.0;
+
+ ++m_numberOfCalls;
+}
+
+void ProfileNode::startTimer()
+{
+ if (!m_startTime)
+ m_startTime = getCount();
+}
+
+void ProfileNode::resetChildrensSiblings()
+{
+ unsigned size = m_children.size();
+ for (unsigned i = 0; i < size; ++i)
+ m_children[i]->setNextSibling(i + 1 == size ? 0 : m_children[i + 1].get());
+}
+
+#ifndef NDEBUG
+void ProfileNode::debugPrintData(int indentLevel) const
+{
+ // Print function names
+ for (int i = 0; i < indentLevel; ++i)
+ printf(" ");
+
+ printf("Function Name %s %d SelfTime %.3fms/%.3f%% TotalTime %.3fms/%.3f%% VSelf %.3fms VTotal %.3fms Visible %s Next Sibling %s\n",
+ functionName().utf8().data(),
+ m_numberOfCalls, m_actualSelfTime, selfPercent(), m_actualTotalTime, totalPercent(),
+ m_visibleSelfTime, m_visibleTotalTime,
+ (m_visible ? "True" : "False"),
+ m_nextSibling ? m_nextSibling->functionName().utf8().data() : "");
+
+ ++indentLevel;
+
+ // Print children's names and information
+ for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild)
+ (*currentChild)->debugPrintData(indentLevel);
+}
+
+// print the profiled data in a format that matches the tool sample's output.
+double ProfileNode::debugPrintDataSampleStyle(int indentLevel, FunctionCallHashCount& countedFunctions) const
+{
+ printf(" ");
+
+ // Print function names
+ const char* name = functionName().utf8().data();
+ double sampleCount = m_actualTotalTime * 1000;
+ if (indentLevel) {
+ for (int i = 0; i < indentLevel; ++i)
+ printf(" ");
+
+ countedFunctions.add(functionName().impl());
+
+ printf("%.0f %s\n", sampleCount ? sampleCount : 1, name);
+ } else
+ printf("%s\n", name);
+
+ ++indentLevel;
+
+ // Print children's names and information
+ double sumOfChildrensCount = 0.0;
+ for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild)
+ sumOfChildrensCount += (*currentChild)->debugPrintDataSampleStyle(indentLevel, countedFunctions);
+
+ sumOfChildrensCount *= 1000; //
+ // Print remainder of samples to match sample's output
+ if (sumOfChildrensCount < sampleCount) {
+ printf(" ");
+ while (indentLevel--)
+ printf(" ");
+
+ printf("%.0f %s\n", sampleCount - sumOfChildrensCount, functionName().utf8().data());
+ }
+
+ return m_actualTotalTime;
+}
+#endif
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/profiler/ProfileNode.h b/Source/JavaScriptCore/profiler/ProfileNode.h
new file mode 100644
index 0000000..ffe7b6f
--- /dev/null
+++ b/Source/JavaScriptCore/profiler/ProfileNode.h
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2008 Apple 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE 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 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.
+ */
+
+#ifndef ProfileNode_h
+#define ProfileNode_h
+
+#include "CallIdentifier.h"
+#include <wtf/HashCountedSet.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+namespace JSC {
+
+ class ExecState;
+ class ProfileNode;
+
+ typedef Vector<RefPtr<ProfileNode> >::const_iterator StackIterator;
+ typedef HashCountedSet<StringImpl*> FunctionCallHashCount;
+
+ class ProfileNode : public RefCounted<ProfileNode> {
+ public:
+ static PassRefPtr<ProfileNode> create(ExecState* callerCallFrame, const CallIdentifier& callIdentifier, ProfileNode* headNode, ProfileNode* parentNode)
+ {
+ return adoptRef(new ProfileNode(callerCallFrame, callIdentifier, headNode, parentNode));
+ }
+ static PassRefPtr<ProfileNode> create(ExecState* callerCallFrame, ProfileNode* headNode, ProfileNode* node)
+ {
+ return adoptRef(new ProfileNode(callerCallFrame, headNode, node));
+ }
+
+ bool operator==(ProfileNode* node) { return m_callIdentifier == node->callIdentifier(); }
+
+ ProfileNode* willExecute(ExecState* callerCallFrame, const CallIdentifier&);
+ ProfileNode* didExecute();
+
+ void stopProfiling();
+
+ // CallIdentifier members
+ ExecState* callerCallFrame() const { return m_callerCallFrame; }
+ const CallIdentifier& callIdentifier() const { return m_callIdentifier; }
+ const UString& functionName() const { return m_callIdentifier.m_name; }
+ const UString& url() const { return m_callIdentifier.m_url; }
+ unsigned lineNumber() const { return m_callIdentifier.m_lineNumber; }
+
+ // Relationships
+ ProfileNode* head() const { return m_head; }
+ void setHead(ProfileNode* head) { m_head = head; }
+ ProfileNode* parent() const { return m_parent; }
+ void setParent(ProfileNode* parent) { m_parent = parent; }
+ ProfileNode* nextSibling() const { return m_nextSibling; }
+ void setNextSibling(ProfileNode* nextSibling) { m_nextSibling = nextSibling; }
+
+ // Time members
+ double startTime() const { return m_startTime; }
+ void setStartTime(double startTime) { m_startTime = startTime; }
+ double totalTime() const { return m_visibleTotalTime; }
+ double actualTotalTime() const { return m_actualTotalTime; }
+ void setTotalTime(double time) { m_actualTotalTime = time; m_visibleTotalTime = time; }
+ void setActualTotalTime(double time) { m_actualTotalTime = time; }
+ void setVisibleTotalTime(double time) { m_visibleTotalTime = time; }
+ double selfTime() const { return m_visibleSelfTime; }
+ double actualSelfTime() const { return m_actualSelfTime; }
+ void setSelfTime(double time) {m_actualSelfTime = time; m_visibleSelfTime = time; }
+ void setActualSelfTime(double time) { m_actualSelfTime = time; }
+ void setVisibleSelfTime(double time) { m_visibleSelfTime = time; }
+
+ double totalPercent() const { return (m_visibleTotalTime / (m_head ? m_head->totalTime() : totalTime())) * 100.0; }
+ double selfPercent() const { return (m_visibleSelfTime / (m_head ? m_head->totalTime() : totalTime())) * 100.0; }
+
+ unsigned numberOfCalls() const { return m_numberOfCalls; }
+ void setNumberOfCalls(unsigned number) { m_numberOfCalls = number; }
+
+ // Children members
+ const Vector<RefPtr<ProfileNode> >& children() const { return m_children; }
+ ProfileNode* firstChild() const { return m_children.size() ? m_children.first().get() : 0; }
+ ProfileNode* lastChild() const { return m_children.size() ? m_children.last().get() : 0; }
+ ProfileNode* findChild(ProfileNode*) const;
+ void removeChild(ProfileNode*);
+ void addChild(PassRefPtr<ProfileNode> prpChild);
+ void insertNode(PassRefPtr<ProfileNode> prpNode);
+
+ // Visiblity
+ bool visible() const { return m_visible; }
+ void setVisible(bool visible) { m_visible = visible; }
+
+ static void setTreeVisible(ProfileNode*, bool visible);
+
+ // Sorting
+ ProfileNode* traverseNextNodePostOrder() const;
+ ProfileNode* traverseNextNodePreOrder(bool processChildren = true) const;
+
+ // Views
+ void calculateVisibleTotalTime();
+ bool focus(const CallIdentifier&);
+ void exclude(const CallIdentifier&);
+ void restore();
+
+ void endAndRecordCall();
+
+#ifndef NDEBUG
+ const char* c_str() const { return m_callIdentifier; }
+ void debugPrintData(int indentLevel) const;
+ double debugPrintDataSampleStyle(int indentLevel, FunctionCallHashCount&) const;
+#endif
+
+ private:
+ ProfileNode(ExecState* callerCallFrame, const CallIdentifier&, ProfileNode* headNode, ProfileNode* parentNode);
+ ProfileNode(ExecState* callerCallFrame, ProfileNode* headNode, ProfileNode* nodeToCopy);
+
+ void startTimer();
+ void resetChildrensSiblings();
+
+ RefPtr<ProfileNode>* childrenBegin() { return m_children.begin(); }
+ RefPtr<ProfileNode>* childrenEnd() { return m_children.end(); }
+
+ // Sorting comparators
+ static inline bool totalTimeDescendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b) { return a->totalTime() > b->totalTime(); }
+ static inline bool totalTimeAscendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b) { return a->totalTime() < b->totalTime(); }
+ static inline bool selfTimeDescendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b) { return a->selfTime() > b->selfTime(); }
+ static inline bool selfTimeAscendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b) { return a->selfTime() < b->selfTime(); }
+ static inline bool callsDescendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b) { return a->numberOfCalls() > b->numberOfCalls(); }
+ static inline bool callsAscendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b) { return a->numberOfCalls() < b->numberOfCalls(); }
+ static inline bool functionNameDescendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b) { return a->functionName() > b->functionName(); }
+ static inline bool functionNameAscendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b) { return a->functionName() < b->functionName(); }
+
+ ExecState* m_callerCallFrame;
+ CallIdentifier m_callIdentifier;
+ ProfileNode* m_head;
+ ProfileNode* m_parent;
+ ProfileNode* m_nextSibling;
+
+ double m_startTime;
+ double m_actualTotalTime;
+ double m_visibleTotalTime;
+ double m_actualSelfTime;
+ double m_visibleSelfTime;
+ unsigned m_numberOfCalls;
+
+ bool m_visible;
+
+ Vector<RefPtr<ProfileNode> > m_children;
+ };
+
+} // namespace JSC
+
+#endif // ProfileNode_h
diff --git a/Source/JavaScriptCore/profiler/Profiler.cpp b/Source/JavaScriptCore/profiler/Profiler.cpp
new file mode 100644
index 0000000..9ac73fd
--- /dev/null
+++ b/Source/JavaScriptCore/profiler/Profiler.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2008 Apple 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE 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 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 "Profiler.h"
+
+#include "CommonIdentifiers.h"
+#include "CallFrame.h"
+#include "CodeBlock.h"
+#include "InternalFunction.h"
+#include "JSFunction.h"
+#include "JSGlobalObject.h"
+#include "Nodes.h"
+#include "Profile.h"
+#include "ProfileGenerator.h"
+#include "ProfileNode.h"
+#include "UStringConcatenate.h"
+#include <stdio.h>
+
+namespace JSC {
+
+static const char* GlobalCodeExecution = "(program)";
+static const char* AnonymousFunction = "(anonymous function)";
+static unsigned ProfilesUID = 0;
+
+static CallIdentifier createCallIdentifierFromFunctionImp(ExecState*, JSFunction*);
+
+Profiler* Profiler::s_sharedProfiler = 0;
+Profiler* Profiler::s_sharedEnabledProfilerReference = 0;
+
+Profiler* Profiler::profiler()
+{
+ if (!s_sharedProfiler)
+ s_sharedProfiler = new Profiler();
+ return s_sharedProfiler;
+}
+
+void Profiler::startProfiling(ExecState* exec, const UString& title)
+{
+ ASSERT_ARG(title, !title.isNull());
+
+ // Check if we currently have a Profile for this global ExecState and title.
+ // If so return early and don't create a new Profile.
+ ExecState* globalExec = exec ? exec->lexicalGlobalObject()->globalExec() : 0;
+
+ for (size_t i = 0; i < m_currentProfiles.size(); ++i) {
+ ProfileGenerator* profileGenerator = m_currentProfiles[i].get();
+ if (profileGenerator->originatingGlobalExec() == globalExec && profileGenerator->title() == title)
+ return;
+ }
+
+ s_sharedEnabledProfilerReference = this;
+ RefPtr<ProfileGenerator> profileGenerator = ProfileGenerator::create(title, exec, ++ProfilesUID);
+ m_currentProfiles.append(profileGenerator);
+}
+
+PassRefPtr<Profile> Profiler::stopProfiling(ExecState* exec, const UString& title)
+{
+ ExecState* globalExec = exec ? exec->lexicalGlobalObject()->globalExec() : 0;
+ for (ptrdiff_t i = m_currentProfiles.size() - 1; i >= 0; --i) {
+ ProfileGenerator* profileGenerator = m_currentProfiles[i].get();
+ if (profileGenerator->originatingGlobalExec() == globalExec && (title.isNull() || profileGenerator->title() == title)) {
+ profileGenerator->stopProfiling();
+ RefPtr<Profile> returnProfile = profileGenerator->profile();
+
+ m_currentProfiles.remove(i);
+ if (!m_currentProfiles.size())
+ s_sharedEnabledProfilerReference = 0;
+
+ return returnProfile;
+ }
+ }
+
+ return 0;
+}
+
+static inline void dispatchFunctionToProfiles(ExecState* callerOrHandlerCallFrame, const Vector<RefPtr<ProfileGenerator> >& profiles, ProfileGenerator::ProfileFunction function, const CallIdentifier& callIdentifier, unsigned currentProfileTargetGroup)
+{
+ for (size_t i = 0; i < profiles.size(); ++i) {
+ if (profiles[i]->profileGroup() == currentProfileTargetGroup || !profiles[i]->originatingGlobalExec())
+ (profiles[i].get()->*function)(callerOrHandlerCallFrame, callIdentifier);
+ }
+}
+
+void Profiler::willExecute(ExecState* callerCallFrame, JSValue function)
+{
+ ASSERT(!m_currentProfiles.isEmpty());
+
+ dispatchFunctionToProfiles(callerCallFrame, m_currentProfiles, &ProfileGenerator::willExecute, createCallIdentifier(callerCallFrame, function, "", 0), callerCallFrame->lexicalGlobalObject()->profileGroup());
+}
+
+void Profiler::willExecute(ExecState* callerCallFrame, const UString& sourceURL, int startingLineNumber)
+{
+ ASSERT(!m_currentProfiles.isEmpty());
+
+ CallIdentifier callIdentifier = createCallIdentifier(callerCallFrame, JSValue(), sourceURL, startingLineNumber);
+
+ dispatchFunctionToProfiles(callerCallFrame, m_currentProfiles, &ProfileGenerator::willExecute, callIdentifier, callerCallFrame->lexicalGlobalObject()->profileGroup());
+}
+
+void Profiler::didExecute(ExecState* callerCallFrame, JSValue function)
+{
+ ASSERT(!m_currentProfiles.isEmpty());
+
+ dispatchFunctionToProfiles(callerCallFrame, m_currentProfiles, &ProfileGenerator::didExecute, createCallIdentifier(callerCallFrame, function, "", 0), callerCallFrame->lexicalGlobalObject()->profileGroup());
+}
+
+void Profiler::didExecute(ExecState* callerCallFrame, const UString& sourceURL, int startingLineNumber)
+{
+ ASSERT(!m_currentProfiles.isEmpty());
+
+ dispatchFunctionToProfiles(callerCallFrame, m_currentProfiles, &ProfileGenerator::didExecute, createCallIdentifier(callerCallFrame, JSValue(), sourceURL, startingLineNumber), callerCallFrame->lexicalGlobalObject()->profileGroup());
+}
+
+void Profiler::exceptionUnwind(ExecState* handlerCallFrame)
+{
+ ASSERT(!m_currentProfiles.isEmpty());
+
+ dispatchFunctionToProfiles(handlerCallFrame, m_currentProfiles, &ProfileGenerator::exceptionUnwind, createCallIdentifier(handlerCallFrame, JSValue(), "", 0), handlerCallFrame->lexicalGlobalObject()->profileGroup());
+}
+
+CallIdentifier Profiler::createCallIdentifier(ExecState* exec, JSValue functionValue, const UString& defaultSourceURL, int defaultLineNumber)
+{
+ if (!functionValue)
+ return CallIdentifier(GlobalCodeExecution, defaultSourceURL, defaultLineNumber);
+ if (!functionValue.isObject())
+ return CallIdentifier("(unknown)", defaultSourceURL, defaultLineNumber);
+ if (asObject(functionValue)->inherits(&JSFunction::info)) {
+ JSFunction* function = asFunction(functionValue);
+ if (!function->executable()->isHostFunction())
+ return createCallIdentifierFromFunctionImp(exec, function);
+ }
+ if (asObject(functionValue)->inherits(&JSFunction::info))
+ return CallIdentifier(static_cast<JSFunction*>(asObject(functionValue))->name(exec), defaultSourceURL, defaultLineNumber);
+ if (asObject(functionValue)->inherits(&InternalFunction::info))
+ return CallIdentifier(static_cast<InternalFunction*>(asObject(functionValue))->name(exec), defaultSourceURL, defaultLineNumber);
+ return CallIdentifier(makeUString("(", asObject(functionValue)->className(), " object)"), defaultSourceURL, defaultLineNumber);
+}
+
+CallIdentifier createCallIdentifierFromFunctionImp(ExecState* exec, JSFunction* function)
+{
+ ASSERT(!function->isHostFunction());
+ const UString& name = function->calculatedDisplayName(exec);
+ return CallIdentifier(name.isEmpty() ? AnonymousFunction : name, function->jsExecutable()->sourceURL(), function->jsExecutable()->lineNo());
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/profiler/Profiler.h b/Source/JavaScriptCore/profiler/Profiler.h
new file mode 100644
index 0000000..f9c2ccb
--- /dev/null
+++ b/Source/JavaScriptCore/profiler/Profiler.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2008 Apple 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE 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 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.
+ */
+
+#ifndef Profiler_h
+#define Profiler_h
+
+#include "Profile.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+namespace JSC {
+
+ class ExecState;
+ class JSGlobalData;
+ class JSObject;
+ class JSValue;
+ class ProfileGenerator;
+ class UString;
+ struct CallIdentifier;
+
+ class Profiler : public FastAllocBase {
+ public:
+ static Profiler** enabledProfilerReference()
+ {
+ return &s_sharedEnabledProfilerReference;
+ }
+
+ static Profiler* profiler();
+ static CallIdentifier createCallIdentifier(ExecState* exec, JSValue, const UString& sourceURL, int lineNumber);
+
+ void startProfiling(ExecState*, const UString& title);
+ PassRefPtr<Profile> stopProfiling(ExecState*, const UString& title);
+
+ void willExecute(ExecState* callerCallFrame, JSValue function);
+ void willExecute(ExecState* callerCallFrame, const UString& sourceURL, int startingLineNumber);
+ void didExecute(ExecState* callerCallFrame, JSValue function);
+ void didExecute(ExecState* callerCallFrame, const UString& sourceURL, int startingLineNumber);
+
+ void exceptionUnwind(ExecState* handlerCallFrame);
+
+ const Vector<RefPtr<ProfileGenerator> >& currentProfiles() { return m_currentProfiles; };
+
+ private:
+ Vector<RefPtr<ProfileGenerator> > m_currentProfiles;
+ static Profiler* s_sharedProfiler;
+ static Profiler* s_sharedEnabledProfilerReference;
+ };
+
+} // namespace JSC
+
+#endif // Profiler_h
diff --git a/Source/JavaScriptCore/profiler/ProfilerServer.h b/Source/JavaScriptCore/profiler/ProfilerServer.h
new file mode 100644
index 0000000..5b7cc46
--- /dev/null
+++ b/Source/JavaScriptCore/profiler/ProfilerServer.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2008 Apple 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. ``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
+ * 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.
+ */
+
+#ifndef ProfileServer_h
+#define ProfileServer_h
+
+namespace JSC {
+
+void startProfilerServerIfNeeded();
+
+} // namespace JSC
+
+#endif // ProfileServer_h
diff --git a/Source/JavaScriptCore/profiler/ProfilerServer.mm b/Source/JavaScriptCore/profiler/ProfilerServer.mm
new file mode 100644
index 0000000..7d87f96
--- /dev/null
+++ b/Source/JavaScriptCore/profiler/ProfilerServer.mm
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2008 Apple 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. ``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
+ * 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.
+ */
+
+#import "config.h"
+#import "ProfilerServer.h"
+
+#import "JSProfilerPrivate.h"
+#import "JSRetainPtr.h"
+#import <Foundation/Foundation.h>
+
+#if PLATFORM(IOS_SIMULATOR)
+#import <Foundation/NSDistributedNotificationCenter.h>
+#endif
+
+@interface ProfilerServer : NSObject {
+@private
+ NSString *_serverName;
+ unsigned _listenerCount;
+}
++ (ProfilerServer *)sharedProfileServer;
+- (void)startProfiling;
+- (void)stopProfiling;
+@end
+
+@implementation ProfilerServer
+
++ (ProfilerServer *)sharedProfileServer
+{
+ static ProfilerServer *sharedServer;
+ if (!sharedServer)
+ sharedServer = [[ProfilerServer alloc] init];
+ return sharedServer;
+}
+
+- (id)init
+{
+ if (!(self = [super init]))
+ return nil;
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+ if ([defaults boolForKey:@"EnableJSProfiling"])
+ [self startProfiling];
+
+#if !PLATFORM(IOS) || PLATFORM(IOS_SIMULATOR)
+ // FIXME: <rdar://problem/6546135>
+ // The catch-all notifications
+ [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(startProfiling) name:@"ProfilerServerStartNotification" object:nil];
+ [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(stopProfiling) name:@"ProfilerServerStopNotification" object:nil];
+#endif
+
+ // The specific notifications
+ NSProcessInfo *processInfo = [NSProcessInfo processInfo];
+ _serverName = [[NSString alloc] initWithFormat:@"ProfilerServer-%d", [processInfo processIdentifier]];
+
+#if !PLATFORM(IOS) || PLATFORM(IOS_SIMULATOR)
+ // FIXME: <rdar://problem/6546135>
+ [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(startProfiling) name:[_serverName stringByAppendingString:@"-Start"] object:nil];
+ [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(stopProfiling) name:[_serverName stringByAppendingString:@"-Stop"] object:nil];
+#endif
+
+ [pool drain];
+
+ return self;
+}
+
+- (void)startProfiling
+{
+ if (++_listenerCount > 1)
+ return;
+ JSRetainPtr<JSStringRef> profileName(Adopt, JSStringCreateWithUTF8CString([_serverName UTF8String]));
+ JSStartProfiling(0, profileName.get());
+}
+
+- (void)stopProfiling
+{
+ if (!_listenerCount || --_listenerCount > 0)
+ return;
+ JSRetainPtr<JSStringRef> profileName(Adopt, JSStringCreateWithUTF8CString([_serverName UTF8String]));
+ JSEndProfiling(0, profileName.get());
+}
+
+@end
+
+namespace JSC {
+
+void startProfilerServerIfNeeded()
+{
+ [ProfilerServer sharedProfileServer];
+}
+
+} // namespace JSC