diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/profiler | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/JavaScriptCore/profiler')
39 files changed, 648 insertions, 1340 deletions
diff --git a/Source/JavaScriptCore/profiler/CallIdentifier.h b/Source/JavaScriptCore/profiler/CallIdentifier.h deleted file mode 100644 index bf9f904b0..000000000 --- a/Source/JavaScriptCore/profiler/CallIdentifier.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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 <wtf/text/CString.h> -#include <wtf/text/StringHash.h> -#include <wtf/text/WTFString.h> - -namespace JSC { - - struct CallIdentifier { - WTF_MAKE_FAST_ALLOCATED; - public: - String m_name; - String m_url; - unsigned m_lineNumber; - - CallIdentifier() - : m_lineNumber(0) - { - } - - CallIdentifier(const String& name, const String& 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 StringHasher::hashMemory<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 (NotNull, &slot) JSC::CallIdentifier(String(), String(), 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/LegacyProfiler.cpp b/Source/JavaScriptCore/profiler/LegacyProfiler.cpp deleted file mode 100644 index dd2acd9f0..000000000 --- a/Source/JavaScriptCore/profiler/LegacyProfiler.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2008, 2012 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 "LegacyProfiler.h" - -#include "CallFrame.h" -#include "CodeBlock.h" -#include "CommonIdentifiers.h" -#include "InternalFunction.h" -#include "JSFunction.h" -#include "JSGlobalObject.h" -#include "Nodes.h" -#include "Operations.h" -#include "Profile.h" -#include "ProfileGenerator.h" -#include "ProfileNode.h" - -namespace JSC { - -static const char* GlobalCodeExecution = "(program)"; -static const char* AnonymousFunction = "(anonymous function)"; -static unsigned ProfilesUID = 0; - -static CallIdentifier createCallIdentifierFromFunctionImp(ExecState*, JSObject*, const String& defaultSourceURL, int defaultLineNumber); - -LegacyProfiler* LegacyProfiler::s_sharedLegacyProfiler = 0; - -LegacyProfiler* LegacyProfiler::profiler() -{ - if (!s_sharedLegacyProfiler) - s_sharedLegacyProfiler = new LegacyProfiler(); - return s_sharedLegacyProfiler; -} - -void LegacyProfiler::startProfiling(ExecState* exec, const String& title) -{ - ASSERT_ARG(title, !title.isNull()); - - if (!exec) - return; - - // Check if we currently have a Profile for this global ExecState and title. - // If so return early and don't create a new Profile. - JSGlobalObject* origin = exec->lexicalGlobalObject(); - - for (size_t i = 0; i < m_currentProfiles.size(); ++i) { - ProfileGenerator* profileGenerator = m_currentProfiles[i].get(); - if (profileGenerator->origin() == origin && profileGenerator->title() == title) - return; - } - - exec->vm().setEnabledProfiler(this); - RefPtr<ProfileGenerator> profileGenerator = ProfileGenerator::create(exec, title, ++ProfilesUID); - m_currentProfiles.append(profileGenerator); -} - -PassRefPtr<Profile> LegacyProfiler::stopProfiling(ExecState* exec, const String& title) -{ - if (!exec) - return 0; - - JSGlobalObject* origin = exec->lexicalGlobalObject(); - for (ptrdiff_t i = m_currentProfiles.size() - 1; i >= 0; --i) { - ProfileGenerator* profileGenerator = m_currentProfiles[i].get(); - if (profileGenerator->origin() == origin && (title.isNull() || profileGenerator->title() == title)) { - profileGenerator->stopProfiling(); - RefPtr<Profile> returnProfile = profileGenerator->profile(); - - m_currentProfiles.remove(i); - if (!m_currentProfiles.size()) - exec->vm().setEnabledProfiler(nullptr); - - return returnProfile; - } - } - - return 0; -} - -void LegacyProfiler::stopProfiling(JSGlobalObject* origin) -{ - for (ptrdiff_t i = m_currentProfiles.size() - 1; i >= 0; --i) { - ProfileGenerator* profileGenerator = m_currentProfiles[i].get(); - if (profileGenerator->origin() == origin) { - profileGenerator->stopProfiling(); - m_currentProfiles.remove(i); - if (!m_currentProfiles.size()) - origin->vm().setEnabledProfiler(nullptr); - } - } -} - -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]->origin()) - (profiles[i].get()->*function)(callerOrHandlerCallFrame, callIdentifier); - } -} - -void LegacyProfiler::willExecute(ExecState* callerCallFrame, JSValue function) -{ - ASSERT(!m_currentProfiles.isEmpty()); - - dispatchFunctionToProfiles(callerCallFrame, m_currentProfiles, &ProfileGenerator::willExecute, createCallIdentifier(callerCallFrame, function, "", 0), callerCallFrame->lexicalGlobalObject()->profileGroup()); -} - -void LegacyProfiler::willExecute(ExecState* callerCallFrame, const String& 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 LegacyProfiler::didExecute(ExecState* callerCallFrame, JSValue function) -{ - ASSERT(!m_currentProfiles.isEmpty()); - - dispatchFunctionToProfiles(callerCallFrame, m_currentProfiles, &ProfileGenerator::didExecute, createCallIdentifier(callerCallFrame, function, "", 0), callerCallFrame->lexicalGlobalObject()->profileGroup()); -} - -void LegacyProfiler::didExecute(ExecState* callerCallFrame, const String& sourceURL, int startingLineNumber) -{ - ASSERT(!m_currentProfiles.isEmpty()); - - dispatchFunctionToProfiles(callerCallFrame, m_currentProfiles, &ProfileGenerator::didExecute, createCallIdentifier(callerCallFrame, JSValue(), sourceURL, startingLineNumber), callerCallFrame->lexicalGlobalObject()->profileGroup()); -} - -void LegacyProfiler::exceptionUnwind(ExecState* handlerCallFrame) -{ - ASSERT(!m_currentProfiles.isEmpty()); - - dispatchFunctionToProfiles(handlerCallFrame, m_currentProfiles, &ProfileGenerator::exceptionUnwind, createCallIdentifier(handlerCallFrame, JSValue(), "", 0), handlerCallFrame->lexicalGlobalObject()->profileGroup()); -} - -CallIdentifier LegacyProfiler::createCallIdentifier(ExecState* exec, JSValue functionValue, const String& defaultSourceURL, int defaultLineNumber) -{ - if (!functionValue) - return CallIdentifier(GlobalCodeExecution, defaultSourceURL, defaultLineNumber); - if (!functionValue.isObject()) - return CallIdentifier("(unknown)", defaultSourceURL, defaultLineNumber); - if (asObject(functionValue)->inherits(JSFunction::info()) || asObject(functionValue)->inherits(InternalFunction::info())) - return createCallIdentifierFromFunctionImp(exec, asObject(functionValue), defaultSourceURL, defaultLineNumber); - return CallIdentifier(makeString("(", asObject(functionValue)->methodTable()->className(asObject(functionValue)), " object)"), defaultSourceURL, defaultLineNumber); -} - -CallIdentifier createCallIdentifierFromFunctionImp(ExecState* exec, JSObject* function, const String& defaultSourceURL, int defaultLineNumber) -{ - const String& name = getCalculatedDisplayName(exec, function); - JSFunction* jsFunction = jsDynamicCast<JSFunction*>(function); - if (jsFunction && !jsFunction->isHostFunction()) - return CallIdentifier(name.isEmpty() ? AnonymousFunction : name, jsFunction->jsExecutable()->sourceURL(), jsFunction->jsExecutable()->lineNo()); - return CallIdentifier(name.isEmpty() ? AnonymousFunction : name, defaultSourceURL, defaultLineNumber); -} - -} // namespace JSC diff --git a/Source/JavaScriptCore/profiler/LegacyProfiler.h b/Source/JavaScriptCore/profiler/LegacyProfiler.h deleted file mode 100644 index 607ddec9d..000000000 --- a/Source/JavaScriptCore/profiler/LegacyProfiler.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2008, 2012 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 LegacyProfiler_h -#define LegacyProfiler_h - -#include "Profile.h" -#include <wtf/PassRefPtr.h> -#include <wtf/RefPtr.h> -#include <wtf/Vector.h> - -namespace JSC { - -class ExecState; -class VM; -class JSGlobalObject; -class JSObject; -class JSValue; -class ProfileGenerator; -struct CallIdentifier; - -class LegacyProfiler { - WTF_MAKE_FAST_ALLOCATED; -public: - JS_EXPORT_PRIVATE static LegacyProfiler* profiler(); - static CallIdentifier createCallIdentifier(ExecState*, JSValue, const WTF::String& sourceURL, int lineNumber); - - JS_EXPORT_PRIVATE void startProfiling(ExecState*, const WTF::String& title); - JS_EXPORT_PRIVATE PassRefPtr<Profile> stopProfiling(ExecState*, const WTF::String& title); - void stopProfiling(JSGlobalObject*); - - void willExecute(ExecState* callerCallFrame, JSValue function); - void willExecute(ExecState* callerCallFrame, const WTF::String& sourceURL, int startingLineNumber); - void didExecute(ExecState* callerCallFrame, JSValue function); - void didExecute(ExecState* callerCallFrame, const WTF::String& sourceURL, int startingLineNumber); - - void exceptionUnwind(ExecState* handlerCallFrame); - - const Vector<RefPtr<ProfileGenerator>>& currentProfiles() { return m_currentProfiles; }; - -private: - Vector<RefPtr<ProfileGenerator>> m_currentProfiles; - static LegacyProfiler* s_sharedLegacyProfiler; -}; - -} // namespace JSC - -#endif // LegacyProfiler_h diff --git a/Source/JavaScriptCore/profiler/Profile.cpp b/Source/JavaScriptCore/profiler/Profile.cpp deleted file mode 100644 index ed21e7879..000000000 --- a/Source/JavaScriptCore/profiler/Profile.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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 <wtf/DataLog.h> - -namespace JSC { - -PassRefPtr<Profile> Profile::create(const String& title, unsigned uid) -{ - return adoptRef(new Profile(title, uid)); -} - -Profile::Profile(const String& 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", String(), 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(); - } -} - -#ifndef NDEBUG -void Profile::debugPrintData() const -{ - dataLogF("Call graph:\n"); - m_head->debugPrintData(0); -} - -typedef WTF::KeyValuePair<FunctionCallHashCount::ValueType, unsigned> NameCountPair; - -static inline bool functionNameCountPairComparator(const NameCountPair& a, const NameCountPair& b) -{ - return a.value > b.value; -} - -void Profile::debugPrintDataSampleStyle() const -{ - typedef Vector<NameCountPair> NameCountPairVector; - - FunctionCallHashCount countedFunctions; - dataLogF("Call graph:\n"); - m_head->debugPrintDataSampleStyle(0, countedFunctions); - - dataLogF("\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) - dataLogF(" %-12d%s\n", (*it).value, String((*it).key).utf8().data()); - - dataLogF("\nSort by top of stack, same collapsed (when >= 5):\n"); -} -#endif - -} // namespace JSC diff --git a/Source/JavaScriptCore/profiler/ProfileGenerator.cpp b/Source/JavaScriptCore/profiler/ProfileGenerator.cpp deleted file mode 100644 index 9361caf70..000000000 --- a/Source/JavaScriptCore/profiler/ProfileGenerator.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/* - * 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 "CallFrameInlines.h" -#include "CodeBlock.h" -#include "JSGlobalObject.h" -#include "JSStringRef.h" -#include "JSFunction.h" -#include "LegacyProfiler.h" -#include "Operations.h" -#include "Profile.h" -#include "StackVisitor.h" -#include "Tracing.h" - -namespace JSC { - -static const char* NonJSExecution = "(idle)"; - -PassRefPtr<ProfileGenerator> ProfileGenerator::create(ExecState* exec, const String& title, unsigned uid) -{ - return adoptRef(new ProfileGenerator(exec, title, uid)); -} - -ProfileGenerator::ProfileGenerator(ExecState* exec, const String& title, unsigned uid) - : m_origin(exec ? exec->lexicalGlobalObject() : 0) - , m_profileGroup(exec ? exec->lexicalGlobalObject()->profileGroup() : 0) -{ - m_profile = Profile::create(title, uid); - m_currentNode = m_head = m_profile->head(); - if (exec) - addParentForConsoleStart(exec); -} - -class AddParentForConsoleStartFunctor { -public: - AddParentForConsoleStartFunctor(ExecState* exec, RefPtr<ProfileNode>& head, RefPtr<ProfileNode>& currentNode) - : m_exec(exec) - , m_hasSkippedFirstFrame(false) - , m_foundParent(false) - , m_head(head) - , m_currentNode(currentNode) - { - } - - bool foundParent() const { return m_foundParent; } - - StackVisitor::Status operator()(StackVisitor& visitor) - { - if (!m_hasSkippedFirstFrame) { - m_hasSkippedFirstFrame = true; - return StackVisitor::Continue; - } - - unsigned line = 0; - unsigned unusedColumn = 0; - visitor->computeLineAndColumn(line, unusedColumn); - m_currentNode = ProfileNode::create(m_exec, LegacyProfiler::createCallIdentifier(m_exec, visitor->callee(), visitor->sourceURL(), line), m_head.get(), m_head.get()); - m_head->insertNode(m_currentNode.get()); - - m_foundParent = true; - return StackVisitor::Done; - } - -private: - ExecState* m_exec; - bool m_hasSkippedFirstFrame; - bool m_foundParent; - RefPtr<ProfileNode>& m_head; - RefPtr<ProfileNode>& m_currentNode; -}; - -void ProfileGenerator::addParentForConsoleStart(ExecState* exec) -{ - AddParentForConsoleStartFunctor functor(exec, m_head, m_currentNode); - exec->iterate(functor); - - if (!functor.foundParent()) { - m_currentNode = ProfileNode::create(exec, LegacyProfiler::createCallIdentifier(exec, JSValue(), String(), 0), m_head.get(), m_head.get()); - m_head->insertNode(m_currentNode.get()); - } -} - -const String& 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_origin) - 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_origin) - 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, String(), 0), m_head.get(), m_head.get()); - - idleNode->setTotalTime(headSelfTime); - idleNode->setSelfTime(headSelfTime); - - m_head->setSelfTime(0.0); - m_head->addChild(idleNode.release()); - } -} - -// The console.profile 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.profileEnd 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 deleted file mode 100644 index 40cc8de01..000000000 --- a/Source/JavaScriptCore/profiler/ProfileGenerator.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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 JSGlobalObject; - class Profile; - class ProfileNode; - struct CallIdentifier; - - class ProfileGenerator : public RefCounted<ProfileGenerator> { - public: - static PassRefPtr<ProfileGenerator> create(ExecState*, const WTF::String& title, unsigned uid); - - // Members - const WTF::String& title() const; - PassRefPtr<Profile> profile() const { return m_profile; } - JSGlobalObject* origin() const { return m_origin; } - 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(ExecState*, const WTF::String& title, unsigned uid); - void addParentForConsoleStart(ExecState*); - - void removeProfileStart(); - void removeProfileEnd(); - - RefPtr<Profile> m_profile; - JSGlobalObject* m_origin; - 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 deleted file mode 100644 index fe2342ea4..000000000 --- a/Source/JavaScriptCore/profiler/ProfileNode.cpp +++ /dev/null @@ -1,247 +0,0 @@ -/* - * 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 "LegacyProfiler.h" -#include <wtf/DateMath.h> -#include <wtf/DataLog.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_totalTime(0.0) - , m_selfTime(0.0) - , m_numberOfCalls(0) -{ - 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_totalTime(nodeToCopy->totalTime()) - , m_selfTime(nodeToCopy->selfTime()) - , m_numberOfCalls(nodeToCopy->numberOfCalls()) -{ -} - -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()); -} - -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(); - - ASSERT(m_selfTime == 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_selfTime += m_children[i]->totalTime(); - - ASSERT(m_selfTime <= m_totalTime); - m_selfTime = m_totalTime - m_selfTime; -} - -ProfileNode* ProfileNode::traverseNextNodePostOrder() const -{ - ProfileNode* next = m_nextSibling; - if (!next) - return m_parent; - while (ProfileNode* firstChild = next->firstChild()) - next = firstChild; - return next; -} - -void ProfileNode::endAndRecordCall() -{ - m_totalTime += 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) - dataLogF(" "); - - dataLogF("Function Name %s %d SelfTime %.3fms/%.3f%% TotalTime %.3fms/%.3f%% Next Sibling %s\n", - functionName().utf8().data(), - m_numberOfCalls, m_selfTime, selfPercent(), m_totalTime, totalPercent(), - 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 -{ - dataLogF(" "); - - // Print function names - const char* name = functionName().utf8().data(); - double sampleCount = m_totalTime * 1000; - if (indentLevel) { - for (int i = 0; i < indentLevel; ++i) - dataLogF(" "); - - countedFunctions.add(functionName().impl()); - - dataLogF("%.0f %s\n", sampleCount ? sampleCount : 1, name); - } else - dataLogF("%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) { - dataLogF(" "); - while (indentLevel--) - dataLogF(" "); - - dataLogF("%.0f %s\n", sampleCount - sumOfChildrensCount, functionName().utf8().data()); - } - - return m_totalTime; -} -#endif - -} // namespace JSC diff --git a/Source/JavaScriptCore/profiler/ProfileNode.h b/Source/JavaScriptCore/profiler/ProfileNode.h deleted file mode 100644 index e21b42282..000000000 --- a/Source/JavaScriptCore/profiler/ProfileNode.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * 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 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; } - unsigned long callUID() const { return m_callIdentifier.hash(); }; - const String& functionName() const { return m_callIdentifier.m_name; } - const String& 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_totalTime; } - void setTotalTime(double time) { m_totalTime = time; } - - double selfTime() const { return m_selfTime; } - void setSelfTime(double time) { m_selfTime = time; } - - double totalPercent() const { return (m_totalTime / (m_head ? m_head->totalTime() : totalTime())) * 100.0; } - double selfPercent() const { return (m_selfTime / (m_head ? m_head->totalTime() : totalTime())) * 100.0; } - - unsigned numberOfCalls() const { return m_numberOfCalls; } - - // 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; } - void removeChild(ProfileNode*); - void addChild(PassRefPtr<ProfileNode> prpChild); - void insertNode(PassRefPtr<ProfileNode> prpNode); - - ProfileNode* traverseNextNodePostOrder() const; - - 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: - typedef Vector<RefPtr<ProfileNode>>::const_iterator StackIterator; - - ProfileNode(ExecState* callerCallFrame, const CallIdentifier&, ProfileNode* headNode, ProfileNode* parentNode); - ProfileNode(ExecState* callerCallFrame, ProfileNode* headNode, ProfileNode* nodeToCopy); - - void startTimer(); - void resetChildrensSiblings(); - - ExecState* m_callerCallFrame; - CallIdentifier m_callIdentifier; - ProfileNode* m_head; - ProfileNode* m_parent; - ProfileNode* m_nextSibling; - - double m_startTime; - double m_totalTime; - double m_selfTime; - unsigned m_numberOfCalls; - - Vector<RefPtr<ProfileNode>> m_children; - }; - -} // namespace JSC - -#endif // ProfileNode_h diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecode.cpp b/Source/JavaScriptCore/profiler/ProfilerBytecode.cpp index ca602e42f..b76e78f98 100644 --- a/Source/JavaScriptCore/profiler/ProfilerBytecode.cpp +++ b/Source/JavaScriptCore/profiler/ProfilerBytecode.cpp @@ -28,7 +28,8 @@ #include "JSGlobalObject.h" #include "ObjectConstructor.h" -#include "Operations.h" +#include "Opcode.h" +#include "JSCInlines.h" namespace JSC { namespace Profiler { diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecode.h b/Source/JavaScriptCore/profiler/ProfilerBytecode.h index 8e99c9a09..72c66c5c3 100644 --- a/Source/JavaScriptCore/profiler/ProfilerBytecode.h +++ b/Source/JavaScriptCore/profiler/ProfilerBytecode.h @@ -23,14 +23,16 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ProfilerBytecode_h -#define ProfilerBytecode_h +#pragma once #include "JSCJSValue.h" -#include "Opcode.h" #include <wtf/text/CString.h> -namespace JSC { namespace Profiler { +namespace JSC { + +enum OpcodeID : unsigned; + +namespace Profiler { class Bytecode { public: @@ -60,6 +62,3 @@ private: inline unsigned getBytecodeIndexForBytecode(Bytecode* bytecode) { return bytecode->bytecodeIndex(); } } } // namespace JSC::Profiler - -#endif // ProfilerBytecode_h - diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp b/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp index 838153bea..09b8213d9 100644 --- a/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp +++ b/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2012-2014, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,9 +27,10 @@ #include "ProfilerBytecodeSequence.h" #include "CodeBlock.h" +#include "Interpreter.h" +#include "JSCInlines.h" #include "JSGlobalObject.h" #include "Operands.h" -#include "Operations.h" #include <wtf/StringPrintStream.h> namespace JSC { namespace Profiler { @@ -39,18 +40,21 @@ BytecodeSequence::BytecodeSequence(CodeBlock* codeBlock) StringPrintStream out; for (unsigned i = 0; i < codeBlock->numberOfArgumentValueProfiles(); ++i) { - ConcurrentJITLocker locker(codeBlock->m_lock); + ConcurrentJSLocker locker(codeBlock->m_lock); CString description = codeBlock->valueProfileForArgument(i)->briefDescription(locker); if (!description.length()) continue; out.reset(); - out.print("arg", i, " (r", virtualRegisterForArgument(i).offset(), "): ", description); + out.print("arg", i, ": ", description); m_header.append(out.toCString()); } + StubInfoMap stubInfos; + codeBlock->getStubInfoMap(stubInfos); + for (unsigned bytecodeIndex = 0; bytecodeIndex < codeBlock->instructions().size();) { out.reset(); - codeBlock->dumpBytecode(out, bytecodeIndex); + codeBlock->dumpBytecode(out, bytecodeIndex, stubInfos); m_sequence.append(Bytecode(bytecodeIndex, codeBlock->vm()->interpreter->getOpcodeID(codeBlock->instructions()[bytecodeIndex].u.opcode), out.toCString())); bytecodeIndex += opcodeLength( codeBlock->vm()->interpreter->getOpcodeID( @@ -74,15 +78,23 @@ const Bytecode& BytecodeSequence::forBytecodeIndex(unsigned bytecodeIndex) const void BytecodeSequence::addSequenceProperties(ExecState* exec, JSObject* result) const { + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); JSArray* header = constructEmptyArray(exec, 0); - for (unsigned i = 0; i < m_header.size(); ++i) + RETURN_IF_EXCEPTION(scope, void()); + for (unsigned i = 0; i < m_header.size(); ++i) { header->putDirectIndex(exec, i, jsString(exec, String::fromUTF8(m_header[i]))); - result->putDirect(exec->vm(), exec->propertyNames().header, header); + RETURN_IF_EXCEPTION(scope, void()); + } + result->putDirect(vm, exec->propertyNames().header, header); JSArray* sequence = constructEmptyArray(exec, 0); - for (unsigned i = 0; i < m_sequence.size(); ++i) + RETURN_IF_EXCEPTION(scope, void()); + for (unsigned i = 0; i < m_sequence.size(); ++i) { sequence->putDirectIndex(exec, i, m_sequence[i].toJS(exec)); - result->putDirect(exec->vm(), exec->propertyNames().bytecode, sequence); + RETURN_IF_EXCEPTION(scope, void()); + } + result->putDirect(vm, exec->propertyNames().bytecode, sequence); } } } // namespace JSC::Profiler diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.h b/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.h index 1d5c82a18..979f0c4a9 100644 --- a/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.h +++ b/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.h @@ -23,8 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ProfilerBytecodeSequence_h -#define ProfilerBytecodeSequence_h +#pragma once #include "JSCJSValue.h" #include "ProfilerBytecode.h" @@ -60,6 +59,3 @@ private: }; } } // namespace JSC::Profiler - -#endif // ProfilerBytecodeSequence_h - diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp b/Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp index aa5a6d9c9..74c55abcf 100644 --- a/Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp +++ b/Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp @@ -29,7 +29,7 @@ #include "CodeBlock.h" #include "JSGlobalObject.h" #include "ObjectConstructor.h" -#include "Operations.h" +#include "JSCInlines.h" #include <wtf/StringPrintStream.h> namespace JSC { namespace Profiler { diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecodes.h b/Source/JavaScriptCore/profiler/ProfilerBytecodes.h index e44598019..b85936da0 100644 --- a/Source/JavaScriptCore/profiler/ProfilerBytecodes.h +++ b/Source/JavaScriptCore/profiler/ProfilerBytecodes.h @@ -23,8 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ProfilerBytecodes_h -#define ProfilerBytecodes_h +#pragma once #include "CodeBlockHash.h" #include "JSCJSValue.h" @@ -58,6 +57,3 @@ private: }; } } // namespace JSC::Profiler - -#endif // ProfilerBytecodes_h - diff --git a/Source/JavaScriptCore/profiler/ProfilerCompilation.cpp b/Source/JavaScriptCore/profiler/ProfilerCompilation.cpp index 55766ce5c..255f8319c 100644 --- a/Source/JavaScriptCore/profiler/ProfilerCompilation.cpp +++ b/Source/JavaScriptCore/profiler/ProfilerCompilation.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2012-2014, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,8 +28,9 @@ #include "JSGlobalObject.h" #include "ObjectConstructor.h" -#include "Operations.h" +#include "JSCInlines.h" #include "ProfilerDatabase.h" +#include "Watchpoint.h" #include <wtf/StringPrintStream.h> namespace JSC { namespace Profiler { @@ -37,9 +38,11 @@ namespace JSC { namespace Profiler { Compilation::Compilation(Bytecodes* bytecodes, CompilationKind kind) : m_bytecodes(bytecodes) , m_kind(kind) + , m_jettisonReason(NotJettisoned) , m_numInlinedGetByIds(0) , m_numInlinedPutByIds(0) , m_numInlinedCalls(0) + , m_uid(UID::create()) { } @@ -67,6 +70,11 @@ void Compilation::addDescription(const CompiledBytecode& compiledBytecode) m_descriptions.append(compiledBytecode); } +void Compilation::addDescription(const OriginStack& stack, const CString& description) +{ + addDescription(CompiledBytecode(stack, description)); +} + ExecutionCounter* Compilation::executionCounterFor(const OriginStack& origin) { std::unique_ptr<ExecutionCounter>& counter = m_counters.add(origin, nullptr).iterator->value; @@ -87,45 +95,92 @@ OSRExit* Compilation::addOSRExit(unsigned id, const OriginStack& originStack, Ex return &m_osrExits.last(); } +void Compilation::setJettisonReason(JettisonReason jettisonReason, const FireDetail* detail) +{ + if (m_jettisonReason != NotJettisoned) + return; // We only care about the original jettison reason. + + m_jettisonReason = jettisonReason; + if (detail) + m_additionalJettisonReason = toCString(*detail); + else + m_additionalJettisonReason = CString(); +} + +void Compilation::dump(PrintStream& out) const +{ + out.print("Comp", m_uid); +} + JSValue Compilation::toJS(ExecState* exec) const { + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); JSObject* result = constructEmptyObject(exec); - - result->putDirect(exec->vm(), exec->propertyNames().bytecodesID, jsNumber(m_bytecodes->id())); - result->putDirect(exec->vm(), exec->propertyNames().compilationKind, jsString(exec, String::fromUTF8(toCString(m_kind)))); + RETURN_IF_EXCEPTION(scope, { }); + result->putDirect(vm, exec->propertyNames().bytecodesID, jsNumber(m_bytecodes->id())); + result->putDirect(vm, exec->propertyNames().compilationKind, jsString(exec, String::fromUTF8(toCString(m_kind)))); JSArray* profiledBytecodes = constructEmptyArray(exec, 0); - for (unsigned i = 0; i < m_profiledBytecodes.size(); ++i) - profiledBytecodes->putDirectIndex(exec, i, m_profiledBytecodes[i].toJS(exec)); - result->putDirect(exec->vm(), exec->propertyNames().profiledBytecodes, profiledBytecodes); + RETURN_IF_EXCEPTION(scope, { }); + for (unsigned i = 0; i < m_profiledBytecodes.size(); ++i) { + auto value = m_profiledBytecodes[i].toJS(exec); + RETURN_IF_EXCEPTION(scope, { }); + profiledBytecodes->putDirectIndex(exec, i, value); + RETURN_IF_EXCEPTION(scope, { }); + } + result->putDirect(vm, exec->propertyNames().profiledBytecodes, profiledBytecodes); JSArray* descriptions = constructEmptyArray(exec, 0); - for (unsigned i = 0; i < m_descriptions.size(); ++i) - descriptions->putDirectIndex(exec, i, m_descriptions[i].toJS(exec)); - result->putDirect(exec->vm(), exec->propertyNames().descriptions, descriptions); + RETURN_IF_EXCEPTION(scope, { }); + for (unsigned i = 0; i < m_descriptions.size(); ++i) { + auto value = m_descriptions[i].toJS(exec); + RETURN_IF_EXCEPTION(scope, { }); + descriptions->putDirectIndex(exec, i, value); + RETURN_IF_EXCEPTION(scope, { }); + } + result->putDirect(vm, exec->propertyNames().descriptions, descriptions); JSArray* counters = constructEmptyArray(exec, 0); + RETURN_IF_EXCEPTION(scope, { }); for (auto it = m_counters.begin(), end = m_counters.end(); it != end; ++it) { JSObject* counterEntry = constructEmptyObject(exec); - counterEntry->putDirect(exec->vm(), exec->propertyNames().origin, it->key.toJS(exec)); - counterEntry->putDirect(exec->vm(), exec->propertyNames().executionCount, jsNumber(it->value->count())); + RETURN_IF_EXCEPTION(scope, { }); + auto value = it->key.toJS(exec); + RETURN_IF_EXCEPTION(scope, { }); + counterEntry->putDirect(vm, exec->propertyNames().origin, value); + counterEntry->putDirect(vm, exec->propertyNames().executionCount, jsNumber(it->value->count())); counters->push(exec, counterEntry); + RETURN_IF_EXCEPTION(scope, { }); } - result->putDirect(exec->vm(), exec->propertyNames().counters, counters); + result->putDirect(vm, exec->propertyNames().counters, counters); JSArray* exitSites = constructEmptyArray(exec, 0); - for (unsigned i = 0; i < m_osrExitSites.size(); ++i) - exitSites->putDirectIndex(exec, i, m_osrExitSites[i].toJS(exec)); - result->putDirect(exec->vm(), exec->propertyNames().osrExitSites, exitSites); + RETURN_IF_EXCEPTION(scope, { }); + for (unsigned i = 0; i < m_osrExitSites.size(); ++i) { + auto value = m_osrExitSites[i].toJS(exec); + RETURN_IF_EXCEPTION(scope, { }); + exitSites->putDirectIndex(exec, i, value); + RETURN_IF_EXCEPTION(scope, { }); + } + result->putDirect(vm, exec->propertyNames().osrExitSites, exitSites); JSArray* exits = constructEmptyArray(exec, 0); - for (unsigned i = 0; i < m_osrExits.size(); ++i) + RETURN_IF_EXCEPTION(scope, { }); + for (unsigned i = 0; i < m_osrExits.size(); ++i) { exits->putDirectIndex(exec, i, m_osrExits[i].toJS(exec)); - result->putDirect(exec->vm(), exec->propertyNames().osrExits, exits); + RETURN_IF_EXCEPTION(scope, { }); + } + result->putDirect(vm, exec->propertyNames().osrExits, exits); + + result->putDirect(vm, exec->propertyNames().numInlinedGetByIds, jsNumber(m_numInlinedGetByIds)); + result->putDirect(vm, exec->propertyNames().numInlinedPutByIds, jsNumber(m_numInlinedPutByIds)); + result->putDirect(vm, exec->propertyNames().numInlinedCalls, jsNumber(m_numInlinedCalls)); + result->putDirect(vm, exec->propertyNames().jettisonReason, jsString(exec, String::fromUTF8(toCString(m_jettisonReason)))); + if (!m_additionalJettisonReason.isNull()) + result->putDirect(vm, exec->propertyNames().additionalJettisonReason, jsString(exec, String::fromUTF8(m_additionalJettisonReason))); - result->putDirect(exec->vm(), exec->propertyNames().numInlinedGetByIds, jsNumber(m_numInlinedGetByIds)); - result->putDirect(exec->vm(), exec->propertyNames().numInlinedPutByIds, jsNumber(m_numInlinedPutByIds)); - result->putDirect(exec->vm(), exec->propertyNames().numInlinedCalls, jsNumber(m_numInlinedCalls)); + result->putDirect(vm, exec->propertyNames().uid, m_uid.toJS(exec)); return result; } diff --git a/Source/JavaScriptCore/profiler/ProfilerCompilation.h b/Source/JavaScriptCore/profiler/ProfilerCompilation.h index dc2810525..1e058627c 100644 --- a/Source/JavaScriptCore/profiler/ProfilerCompilation.h +++ b/Source/JavaScriptCore/profiler/ProfilerCompilation.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2012-2014, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,22 +23,27 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ProfilerCompilation_h -#define ProfilerCompilation_h +#pragma once #include "ExitKind.h" #include "JSCJSValue.h" #include "ProfilerCompilationKind.h" #include "ProfilerCompiledBytecode.h" #include "ProfilerExecutionCounter.h" +#include "ProfilerJettisonReason.h" #include "ProfilerOSRExit.h" #include "ProfilerOSRExitSite.h" #include "ProfilerOriginStack.h" #include "ProfilerProfiledBytecodes.h" +#include "ProfilerUID.h" #include <wtf/RefCounted.h> #include <wtf/SegmentedVector.h> -namespace JSC { namespace Profiler { +namespace JSC { + +class FireDetail; + +namespace Profiler { class Bytecodes; class Database; @@ -63,15 +68,23 @@ public: CompilationKind kind() const { return m_kind; } void addDescription(const CompiledBytecode&); + void addDescription(const OriginStack&, const CString& description); ExecutionCounter* executionCounterFor(const OriginStack&); void addOSRExitSite(const Vector<const void*>& codeAddresses); OSRExit* addOSRExit(unsigned id, const OriginStack&, ExitKind, bool isWatchpoint); + void setJettisonReason(JettisonReason, const FireDetail*); + + UID uid() const { return m_uid; } + + void dump(PrintStream&) const; JSValue toJS(ExecState*) const; private: Bytecodes* m_bytecodes; CompilationKind m_kind; + JettisonReason m_jettisonReason; + CString m_additionalJettisonReason; Vector<ProfiledBytecodes> m_profiledBytecodes; Vector<CompiledBytecode> m_descriptions; HashMap<OriginStack, std::unique_ptr<ExecutionCounter>> m_counters; @@ -80,9 +93,7 @@ private: unsigned m_numInlinedGetByIds; unsigned m_numInlinedPutByIds; unsigned m_numInlinedCalls; + UID m_uid; }; } } // namespace JSC::Profiler - -#endif // ProfilerCompilation_h - diff --git a/Source/JavaScriptCore/profiler/ProfilerCompilationKind.cpp b/Source/JavaScriptCore/profiler/ProfilerCompilationKind.cpp index 78ce70586..3fbe25192 100644 --- a/Source/JavaScriptCore/profiler/ProfilerCompilationKind.cpp +++ b/Source/JavaScriptCore/profiler/ProfilerCompilationKind.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -42,6 +42,12 @@ void printInternal(PrintStream& out, JSC::Profiler::CompilationKind kind) case JSC::Profiler::DFG: out.print("DFG"); return; + case JSC::Profiler::FTL: + out.print("FTL"); + return; + case JSC::Profiler::FTLForOSREntry: + out.print("FTLForOSREntry"); + return; default: CRASH(); return; diff --git a/Source/JavaScriptCore/profiler/ProfilerCompilationKind.h b/Source/JavaScriptCore/profiler/ProfilerCompilationKind.h index 4806d39b9..aaefd4b46 100644 --- a/Source/JavaScriptCore/profiler/ProfilerCompilationKind.h +++ b/Source/JavaScriptCore/profiler/ProfilerCompilationKind.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,15 +23,16 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ProfilerCompilationKind_h -#define ProfilerCompilationKind_h +#pragma once namespace JSC { namespace Profiler { enum CompilationKind { LLInt, Baseline, - DFG + DFG, + FTL, + FTLForOSREntry }; } } // namespace JSC::Profiler @@ -42,6 +43,3 @@ class PrintStream; void printInternal(PrintStream&, JSC::Profiler::CompilationKind); } // namespace WTF - -#endif // ProfilerCompilationKind_h - diff --git a/Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.cpp b/Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.cpp index 455a48ed9..4891c315c 100644 --- a/Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.cpp +++ b/Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.cpp @@ -28,7 +28,7 @@ #include "JSGlobalObject.h" #include "ObjectConstructor.h" -#include "Operations.h" +#include "JSCInlines.h" namespace JSC { namespace Profiler { diff --git a/Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.h b/Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.h index 84044445a..5f8e4dfe5 100644 --- a/Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.h +++ b/Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.h @@ -23,8 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ProfilerCompiledBytecode_h -#define ProfilerCompiledBytecode_h +#pragma once #include "JSCJSValue.h" #include "ProfilerOriginStack.h" @@ -50,6 +49,3 @@ private: }; } } // namespace JSC::Profiler - -#endif // ProfilerCompiledBytecode_h - diff --git a/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp b/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp index f83652dda..01cefc443 100644 --- a/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp +++ b/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2012-2013, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,13 +29,14 @@ #include "CodeBlock.h" #include "JSONObject.h" #include "ObjectConstructor.h" -#include "Operations.h" +#include "JSCInlines.h" +#include <wtf/CurrentTime.h> namespace JSC { namespace Profiler { static std::atomic<int> databaseCounter; -static SpinLock registrationLock = SPINLOCK_INITIALIZER; +static StaticLock registrationLock; static std::atomic<int> didRegisterAtExit; static Database* firstDatabase; @@ -57,9 +58,13 @@ Database::~Database() Bytecodes* Database::ensureBytecodesFor(CodeBlock* codeBlock) { - Locker locker(m_lock); - - codeBlock = codeBlock->baselineVersion(); + LockHolder locker(m_lock); + return ensureBytecodesFor(locker, codeBlock); +} + +Bytecodes* Database::ensureBytecodesFor(const LockHolder&, CodeBlock* codeBlock) +{ + codeBlock = codeBlock->baselineAlternative(); HashMap<CodeBlock*, Bytecodes*>::iterator iter = m_bytecodesMap.find(codeBlock); if (iter != m_bytecodesMap.end()) @@ -75,50 +80,85 @@ Bytecodes* Database::ensureBytecodesFor(CodeBlock* codeBlock) void Database::notifyDestruction(CodeBlock* codeBlock) { - Locker locker(m_lock); + LockHolder locker(m_lock); m_bytecodesMap.remove(codeBlock); + m_compilationMap.remove(codeBlock); } -void Database::addCompilation(PassRefPtr<Compilation> compilation) +void Database::addCompilation(CodeBlock* codeBlock, Ref<Compilation>&& compilation) { + LockHolder locker(m_lock); ASSERT(!isCompilationThread()); - - m_compilations.append(compilation); + + m_compilations.append(compilation.copyRef()); + m_compilationMap.set(codeBlock, WTFMove(compilation)); } JSValue Database::toJS(ExecState* exec) const { + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); JSObject* result = constructEmptyObject(exec); JSArray* bytecodes = constructEmptyArray(exec, 0); - for (unsigned i = 0; i < m_bytecodes.size(); ++i) - bytecodes->putDirectIndex(exec, i, m_bytecodes[i].toJS(exec)); - result->putDirect(exec->vm(), exec->propertyNames().bytecodes, bytecodes); + RETURN_IF_EXCEPTION(scope, { }); + for (unsigned i = 0; i < m_bytecodes.size(); ++i) { + auto value = m_bytecodes[i].toJS(exec); + RETURN_IF_EXCEPTION(scope, { }); + bytecodes->putDirectIndex(exec, i, value); + RETURN_IF_EXCEPTION(scope, { }); + } + result->putDirect(vm, exec->propertyNames().bytecodes, bytecodes); JSArray* compilations = constructEmptyArray(exec, 0); - for (unsigned i = 0; i < m_compilations.size(); ++i) - compilations->putDirectIndex(exec, i, m_compilations[i]->toJS(exec)); - result->putDirect(exec->vm(), exec->propertyNames().compilations, compilations); + RETURN_IF_EXCEPTION(scope, { }); + for (unsigned i = 0; i < m_compilations.size(); ++i) { + auto value = m_compilations[i]->toJS(exec); + RETURN_IF_EXCEPTION(scope, { }); + compilations->putDirectIndex(exec, i, value); + RETURN_IF_EXCEPTION(scope, { }); + } + result->putDirect(vm, exec->propertyNames().compilations, compilations); + + JSArray* events = constructEmptyArray(exec, 0); + RETURN_IF_EXCEPTION(scope, { }); + for (unsigned i = 0; i < m_events.size(); ++i) { + auto value = m_events[i].toJS(exec); + RETURN_IF_EXCEPTION(scope, { }); + events->putDirectIndex(exec, i, value); + RETURN_IF_EXCEPTION(scope, { }); + } + result->putDirect(vm, exec->propertyNames().events, events); return result; } String Database::toJSON() const { + auto scope = DECLARE_THROW_SCOPE(m_vm); JSGlobalObject* globalObject = JSGlobalObject::create( m_vm, JSGlobalObject::createStructure(m_vm, jsNull())); - - return JSONStringify(globalObject->globalExec(), toJS(globalObject->globalExec()), 0); + + auto value = toJS(globalObject->globalExec()); + RETURN_IF_EXCEPTION(scope, String()); + scope.release(); + return JSONStringify(globalObject->globalExec(), value, 0); } bool Database::save(const char* filename) const { + auto scope = DECLARE_CATCH_SCOPE(m_vm); auto out = FilePrintStream::open(filename, "w"); if (!out) return false; - out->print(toJSON()); + String data = toJSON(); + if (UNLIKELY(scope.exception())) { + scope.clearException(); + return false; + } + out->print(data); return true; } @@ -133,19 +173,28 @@ void Database::registerToSaveAtExit(const char* filename) m_shouldSaveAtExit = true; } +void Database::logEvent(CodeBlock* codeBlock, const char* summary, const CString& detail) +{ + LockHolder locker(m_lock); + + Bytecodes* bytecodes = ensureBytecodesFor(locker, codeBlock); + Compilation* compilation = m_compilationMap.get(codeBlock); + m_events.append(Event(currentTime(), bytecodes, compilation, summary, detail)); +} + void Database::addDatabaseToAtExit() { if (++didRegisterAtExit == 1) atexit(atExitCallback); - TCMalloc_SpinLockHolder holder(®istrationLock); + LockHolder holder(registrationLock); m_nextRegisteredDatabase = firstDatabase; firstDatabase = this; } void Database::removeDatabaseFromAtExit() { - TCMalloc_SpinLockHolder holder(®istrationLock); + LockHolder holder(registrationLock); for (Database** current = &firstDatabase; *current; current = &(*current)->m_nextRegisteredDatabase) { if (*current != this) continue; @@ -158,12 +207,13 @@ void Database::removeDatabaseFromAtExit() void Database::performAtExitSave() const { + JSLockHolder lock(m_vm); save(m_atExitSaveFilename.data()); } Database* Database::removeFirstAtExitDatabase() { - TCMalloc_SpinLockHolder holder(®istrationLock); + LockHolder holder(registrationLock); Database* result = firstDatabase; if (result) { firstDatabase = result->m_nextRegisteredDatabase; diff --git a/Source/JavaScriptCore/profiler/ProfilerDatabase.h b/Source/JavaScriptCore/profiler/ProfilerDatabase.h index 7d4f3cf2c..b9ef36c03 100644 --- a/Source/JavaScriptCore/profiler/ProfilerDatabase.h +++ b/Source/JavaScriptCore/profiler/ProfilerDatabase.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2012-2013, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,17 +23,17 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ProfilerDatabase_h -#define ProfilerDatabase_h +#pragma once #include "JSCJSValue.h" #include "ProfilerBytecodes.h" #include "ProfilerCompilation.h" #include "ProfilerCompilationKind.h" +#include "ProfilerEvent.h" #include <wtf/FastMalloc.h> #include <wtf/HashMap.h> +#include <wtf/Lock.h> #include <wtf/Noncopyable.h> -#include <wtf/PassRefPtr.h> #include <wtf/SegmentedVector.h> #include <wtf/ThreadingPrimitives.h> #include <wtf/text/WTFString.h> @@ -51,7 +51,7 @@ public: Bytecodes* ensureBytecodesFor(CodeBlock*); void notifyDestruction(CodeBlock*); - void addCompilation(PassRefPtr<Compilation>); + void addCompilation(CodeBlock*, Ref<Compilation>&&); // Converts the database to a JavaScript object that is suitable for JSON stringification. // Note that it's probably a good idea to use an ExecState* associated with a global @@ -69,22 +69,11 @@ public: void registerToSaveAtExit(const char* filename); + JS_EXPORT_PRIVATE void logEvent(CodeBlock* codeBlock, const char* summary, const CString& detail); + private: - // Use a full-blown adaptive mutex because: - // - There is only one ProfilerDatabase per VM. The size overhead of the system's - // mutex is negligible if you only have one of them. - // - It's locked infrequently - once per bytecode generation, compilation, and - // code block collection - so the fact that the fast path still requires a - // function call is neglible. - // - It tends to be held for a while. Currently, we hold it while generating - // Profiler::Bytecodes for a CodeBlock. That's uncommon and shouldn't affect - // performance, but if we did have contention, we would want a sensible, - // power-aware backoff. An adaptive mutex will do this as a matter of course, - // but a spinlock won't. - typedef Mutex Lock; - typedef MutexLocker Locker; + Bytecodes* ensureBytecodesFor(const LockHolder&, CodeBlock*); - void addDatabaseToAtExit(); void removeDatabaseFromAtExit(); void performAtExitSave() const; @@ -95,7 +84,9 @@ private: VM& m_vm; SegmentedVector<Bytecodes> m_bytecodes; HashMap<CodeBlock*, Bytecodes*> m_bytecodesMap; - Vector<RefPtr<Compilation>> m_compilations; + Vector<Ref<Compilation>> m_compilations; + HashMap<CodeBlock*, Ref<Compilation>> m_compilationMap; + Vector<Event> m_events; bool m_shouldSaveAtExit; CString m_atExitSaveFilename; Database* m_nextRegisteredDatabase; @@ -103,6 +94,3 @@ private: }; } } // namespace JSC::Profiler - -#endif // ProfilerDatabase_h - diff --git a/Source/JavaScriptCore/profiler/ProfilerEvent.cpp b/Source/JavaScriptCore/profiler/ProfilerEvent.cpp new file mode 100644 index 000000000..e84ef6f3c --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerEvent.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2016 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 "ProfilerEvent.h" + +#include "JSCInlines.h" +#include "ObjectConstructor.h" +#include "ProfilerBytecodes.h" +#include "ProfilerCompilation.h" +#include "ProfilerUID.h" + +namespace JSC { namespace Profiler { + +void Event::dump(PrintStream& out) const +{ + out.print(m_time, ": ", pointerDump(m_bytecodes)); + if (m_compilation) + out.print(" ", *m_compilation); + out.print(": ", m_summary); + if (m_detail.length()) + out.print(" (", m_detail, ")"); +} + +JSValue Event::toJS(ExecState* exec) const +{ + JSObject* result = constructEmptyObject(exec); + + result->putDirect(exec->vm(), exec->propertyNames().time, jsNumber(m_time)); + result->putDirect(exec->vm(), exec->propertyNames().bytecodesID, jsNumber(m_bytecodes->id())); + if (m_compilation) + result->putDirect(exec->vm(), exec->propertyNames().compilationUID, m_compilation->uid().toJS(exec)); + result->putDirect(exec->vm(), exec->propertyNames().summary, jsString(exec, String::fromUTF8(m_summary))); + if (m_detail.length()) + result->putDirect(exec->vm(), exec->propertyNames().detail, jsString(exec, String::fromUTF8(m_detail))); + + return result; +} + +} } // namespace JSC::Profiler + diff --git a/Source/JavaScriptCore/profiler/ProfilerEvent.h b/Source/JavaScriptCore/profiler/ProfilerEvent.h new file mode 100644 index 000000000..11cb6dab2 --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerEvent.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "JSCJSValue.h" +#include <wtf/PrintStream.h> +#include <wtf/text/CString.h> + +namespace JSC { namespace Profiler { + +class Bytecodes; +class Compilation; + +class Event { +public: + Event() + { + } + + Event(double time, Bytecodes* bytecodes, Compilation* compilation, const char* summary, const CString& detail) + : m_time(time) + , m_bytecodes(bytecodes) + , m_compilation(compilation) + , m_summary(summary) + , m_detail(detail) + { + } + + explicit operator bool() const + { + return m_bytecodes; + } + + double time() const { return m_time; } + Bytecodes* bytecodes() const { return m_bytecodes; } + Compilation* compilation() const { return m_compilation; } + const char* summary() const { return m_summary; } + const CString& detail() const { return m_detail; } + + void dump(PrintStream&) const; + JSValue toJS(ExecState*) const; + +private: + double m_time { 0 }; + Bytecodes* m_bytecodes { nullptr }; + Compilation* m_compilation { nullptr }; + const char* m_summary { nullptr }; + CString m_detail; +}; + +} } // namespace JSC::Profiler diff --git a/Source/JavaScriptCore/profiler/ProfilerExecutionCounter.h b/Source/JavaScriptCore/profiler/ProfilerExecutionCounter.h index 8989e38b5..e11747c3b 100644 --- a/Source/JavaScriptCore/profiler/ProfilerExecutionCounter.h +++ b/Source/JavaScriptCore/profiler/ProfilerExecutionCounter.h @@ -23,8 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ProfilerExecutionCounter_h -#define ProfilerExecutionCounter_h +#pragma once #include <wtf/FastMalloc.h> #include <wtf/Noncopyable.h> @@ -45,6 +44,3 @@ private: }; } } // namespace JSC::Profiler - -#endif // ProfilerExecutionCounter_h - diff --git a/Source/JavaScriptCore/profiler/ProfilerJettisonReason.cpp b/Source/JavaScriptCore/profiler/ProfilerJettisonReason.cpp new file mode 100644 index 000000000..3751feda0 --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerJettisonReason.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2014 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 "ProfilerJettisonReason.h" + +#include <wtf/PrintStream.h> + +namespace WTF { + +using namespace JSC::Profiler; + +void printInternal(PrintStream& out, JettisonReason reason) +{ + switch (reason) { + case NotJettisoned: + out.print("NotJettisoned"); + return; + case JettisonDueToWeakReference: + out.print("WeakReference"); + return; + case JettisonDueToDebuggerBreakpoint: + out.print("DebuggerBreakpoint"); + return; + case JettisonDueToDebuggerStepping: + out.print("DebuggerStepping"); + return; + case JettisonDueToBaselineLoopReoptimizationTrigger: + out.print("BaselineLoopReoptimizationTrigger"); + return; + case JettisonDueToBaselineLoopReoptimizationTriggerOnOSREntryFail: + out.print("BaselineLoopReoptimizationTriggerOnOSREntryFail"); + return; + case JettisonDueToOSRExit: + out.print("OSRExit"); + return; + case JettisonDueToProfiledWatchpoint: + out.print("ProfiledWatchpoint"); + return; + case JettisonDueToUnprofiledWatchpoint: + out.print("UnprofiledWatchpoint"); + return; + case JettisonDueToOldAge: + out.print("JettisonDueToOldAge"); + return; + } + RELEASE_ASSERT_NOT_REACHED(); +} + +} // namespace WTF + diff --git a/Source/JavaScriptCore/profiler/Profile.h b/Source/JavaScriptCore/profiler/ProfilerJettisonReason.h index b1f093d69..745964fe1 100644 --- a/Source/JavaScriptCore/profiler/Profile.h +++ b/Source/JavaScriptCore/profiler/ProfilerJettisonReason.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -20,49 +20,31 @@ * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -#ifndef Profile_h -#define Profile_h -#include "ProfileNode.h" -#include <wtf/RefCounted.h> -#include <wtf/RefPtr.h> -#include <wtf/text/WTFString.h> +#pragma once -namespace JSC { +namespace JSC { namespace Profiler { - class Profile : public RefCounted<Profile> { - public: - static PassRefPtr<Profile> create(const String& title, unsigned uid); - virtual ~Profile(); +enum JettisonReason { + NotJettisoned, + JettisonDueToWeakReference, + JettisonDueToDebuggerBreakpoint, + JettisonDueToDebuggerStepping, + JettisonDueToBaselineLoopReoptimizationTrigger, + JettisonDueToBaselineLoopReoptimizationTriggerOnOSREntryFail, + JettisonDueToOSRExit, + JettisonDueToProfiledWatchpoint, + JettisonDueToUnprofiledWatchpoint, + JettisonDueToOldAge +}; - const String& 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; } +} } // namespace JSC::Profiler - void forEach(void (ProfileNode::*)()); +namespace WTF { -#ifndef NDEBUG - void debugPrintData() const; - void debugPrintDataSampleStyle() const; -#endif +class PrintStream; +void printInternal(PrintStream&, JSC::Profiler::JettisonReason); - protected: - Profile(const String& title, unsigned uid); - - private: - void removeProfileStart(); - void removeProfileEnd(); - - String m_title; - RefPtr<ProfileNode> m_head; - unsigned int m_uid; - }; - -} // namespace JSC - -#endif // Profile_h +} // namespace WTF diff --git a/Source/JavaScriptCore/profiler/ProfilerOSRExit.cpp b/Source/JavaScriptCore/profiler/ProfilerOSRExit.cpp index 0024791b4..2a5d5be40 100644 --- a/Source/JavaScriptCore/profiler/ProfilerOSRExit.cpp +++ b/Source/JavaScriptCore/profiler/ProfilerOSRExit.cpp @@ -28,7 +28,7 @@ #include "JSGlobalObject.h" #include "ObjectConstructor.h" -#include "Operations.h" +#include "JSCInlines.h" namespace JSC { namespace Profiler { diff --git a/Source/JavaScriptCore/profiler/ProfilerOSRExit.h b/Source/JavaScriptCore/profiler/ProfilerOSRExit.h index 2a23d0b2c..733df6370 100644 --- a/Source/JavaScriptCore/profiler/ProfilerOSRExit.h +++ b/Source/JavaScriptCore/profiler/ProfilerOSRExit.h @@ -23,8 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ProfilerOSRExit_h -#define ProfilerOSRExit_h +#pragma once #include "ExitKind.h" #include "JSCJSValue.h" @@ -56,6 +55,3 @@ private: }; } } // namespace JSC::Profiler - -#endif // ProfilerOSRExit_h - diff --git a/Source/JavaScriptCore/profiler/ProfilerOSRExitSite.cpp b/Source/JavaScriptCore/profiler/ProfilerOSRExitSite.cpp index d54f7a275..8b5568f2c 100644 --- a/Source/JavaScriptCore/profiler/ProfilerOSRExitSite.cpp +++ b/Source/JavaScriptCore/profiler/ProfilerOSRExitSite.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,16 +29,21 @@ #include "JSGlobalObject.h" #include "JSScope.h" #include "JSString.h" -#include "Operations.h" +#include "JSCInlines.h" #include <wtf/StringPrintStream.h> namespace JSC { namespace Profiler { JSValue OSRExitSite::toJS(ExecState* exec) const { + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); JSArray* result = constructEmptyArray(exec, 0); - for (unsigned i = 0; i < m_codeAddresses.size(); ++i) + RETURN_IF_EXCEPTION(scope, { }); + for (unsigned i = 0; i < m_codeAddresses.size(); ++i) { result->putDirectIndex(exec, i, jsString(exec, toString(RawPointer(m_codeAddresses[i])))); + RETURN_IF_EXCEPTION(scope, { }); + } return result; } diff --git a/Source/JavaScriptCore/profiler/ProfilerOSRExitSite.h b/Source/JavaScriptCore/profiler/ProfilerOSRExitSite.h index fa418e9b8..1776f1dd8 100644 --- a/Source/JavaScriptCore/profiler/ProfilerOSRExitSite.h +++ b/Source/JavaScriptCore/profiler/ProfilerOSRExitSite.h @@ -23,8 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ProfilerOSRExitSite_h -#define ProfilerOSRExitSite_h +#pragma once #include "JSCJSValue.h" #include <wtf/Vector.h> @@ -47,6 +46,3 @@ private: }; } } // namespace JSC::Profiler - -#endif // ProfilerOSRExitSite_h - diff --git a/Source/JavaScriptCore/profiler/ProfilerOrigin.cpp b/Source/JavaScriptCore/profiler/ProfilerOrigin.cpp index 1ac29d1cc..7c28f7ba3 100644 --- a/Source/JavaScriptCore/profiler/ProfilerOrigin.cpp +++ b/Source/JavaScriptCore/profiler/ProfilerOrigin.cpp @@ -28,7 +28,7 @@ #include "JSGlobalObject.h" #include "ObjectConstructor.h" -#include "Operations.h" +#include "JSCInlines.h" #include "ProfilerBytecodes.h" #include "ProfilerDatabase.h" diff --git a/Source/JavaScriptCore/profiler/ProfilerOrigin.h b/Source/JavaScriptCore/profiler/ProfilerOrigin.h index 09b388451..4844f03e0 100644 --- a/Source/JavaScriptCore/profiler/ProfilerOrigin.h +++ b/Source/JavaScriptCore/profiler/ProfilerOrigin.h @@ -23,8 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ProfilerOrigin_h -#define ProfilerOrigin_h +#pragma once #include "CodeBlockHash.h" #include "JSCJSValue.h" @@ -115,6 +114,3 @@ template<typename T> struct HashTraits; template<> struct HashTraits<JSC::Profiler::Origin> : SimpleClassHashTraits<JSC::Profiler::Origin> { }; } // namespace WTF - -#endif // ProfilerOrigin_h - diff --git a/Source/JavaScriptCore/profiler/ProfilerOriginStack.cpp b/Source/JavaScriptCore/profiler/ProfilerOriginStack.cpp index 018ceeb8c..61dfb63c6 100644 --- a/Source/JavaScriptCore/profiler/ProfilerOriginStack.cpp +++ b/Source/JavaScriptCore/profiler/ProfilerOriginStack.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,8 +27,9 @@ #include "ProfilerOriginStack.h" #include "CodeOrigin.h" +#include "InlineCallFrame.h" #include "JSGlobalObject.h" -#include "Operations.h" +#include "JSCInlines.h" #include "ProfilerDatabase.h" namespace JSC { namespace Profiler { @@ -51,7 +52,7 @@ OriginStack::OriginStack(Database& database, CodeBlock* codeBlock, const CodeOri for (unsigned i = 1; i < stack.size(); ++i) { append(Origin( - database.ensureBytecodesFor(stack[i].inlineCallFrame->baselineCodeBlock()), + database.ensureBytecodesFor(stack[i].inlineCallFrame->baselineCodeBlock.get()), stack[i].bytecodeIndex)); } } @@ -99,10 +100,15 @@ void OriginStack::dump(PrintStream& out) const JSValue OriginStack::toJS(ExecState* exec) const { + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); JSArray* result = constructEmptyArray(exec, 0); + RETURN_IF_EXCEPTION(scope, { }); - for (unsigned i = 0; i < m_stack.size(); ++i) + for (unsigned i = 0; i < m_stack.size(); ++i) { result->putDirectIndex(exec, i, m_stack[i].toJS(exec)); + RETURN_IF_EXCEPTION(scope, { }); + } return result; } diff --git a/Source/JavaScriptCore/profiler/ProfilerOriginStack.h b/Source/JavaScriptCore/profiler/ProfilerOriginStack.h index 415e8d9b0..36bc13a57 100644 --- a/Source/JavaScriptCore/profiler/ProfilerOriginStack.h +++ b/Source/JavaScriptCore/profiler/ProfilerOriginStack.h @@ -23,8 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ProfilerOriginStack_h -#define ProfilerOriginStack_h +#pragma once #include "JSCJSValue.h" #include "ProfilerOrigin.h" @@ -97,6 +96,3 @@ template<typename T> struct HashTraits; template<> struct HashTraits<JSC::Profiler::OriginStack> : SimpleClassHashTraits<JSC::Profiler::OriginStack> { }; } // namespace WTF - -#endif // ProfilerOriginStack_h - diff --git a/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.cpp b/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.cpp index 6ca6c9f15..fe590ff78 100644 --- a/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.cpp +++ b/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.cpp @@ -28,7 +28,7 @@ #include "JSGlobalObject.h" #include "ObjectConstructor.h" -#include "Operations.h" +#include "JSCInlines.h" namespace JSC { namespace Profiler { diff --git a/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.h b/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.h index d7cb6ffa8..2ef9f449f 100644 --- a/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.h +++ b/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.h @@ -23,8 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ProfilerProfiledBytecodes_h -#define ProfilerProfiledBytecodes_h +#pragma once #include "ProfilerBytecodeSequence.h" #include "ProfilerBytecodes.h" @@ -46,6 +45,3 @@ private: }; } } // namespace JSC::Profiler - -#endif // ProfilerProfiledBytecodes_h - diff --git a/Source/JavaScriptCore/profiler/ProfilerUID.cpp b/Source/JavaScriptCore/profiler/ProfilerUID.cpp new file mode 100644 index 000000000..228988bc5 --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerUID.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 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 "ProfilerUID.h" + +#include "JSCInlines.h" +#include <wtf/Lock.h> + +namespace JSC { namespace Profiler { + +UID UID::create() +{ + static StaticLock lock; + static uint64_t counter; + + LockHolder locker(lock); + UID result; + result.m_uid = ++counter; + return result; +} + +void UID::dump(PrintStream& out) const +{ + out.print(m_uid); +} + +JSValue UID::toJS(ExecState* exec) const +{ + return jsString(exec, toString(*this)); +} + +} } // namespace JSC::Profiler + diff --git a/Source/JavaScriptCore/profiler/ProfilerUID.h b/Source/JavaScriptCore/profiler/ProfilerUID.h new file mode 100644 index 000000000..97dc3206a --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerUID.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "JSCJSValue.h" +#include <wtf/HashMap.h> +#include <wtf/PrintStream.h> + +namespace JSC { namespace Profiler { + +class UID { +public: + UID() + : m_uid(0) + { + } + + static UID fromInt(uint64_t value) + { + UID result; + result.m_uid = value; + return result; + } + + UID(WTF::HashTableDeletedValueType) + : m_uid(std::numeric_limits<uint64_t>::max()) + { + } + + static UID create(); + + uint64_t toInt() const + { + return m_uid; + } + + bool operator==(const UID& other) const + { + return m_uid == other.m_uid; + } + + bool operator!=(const UID& other) const + { + return !(*this == other); + } + + explicit operator bool() const + { + return *this != UID(); + } + + bool isHashTableDeletedValue() const + { + return *this != UID(WTF::HashTableDeletedValue); + } + + unsigned hash() const + { + return IntHash<uint64_t>::hash(m_uid); + } + + void dump(PrintStream&) const; + JSValue toJS(ExecState*) const; + +private: + uint64_t m_uid; +}; + +struct UIDHash { + static unsigned hash(const UID& key) { return key.hash(); } + static bool equal(const UID& a, const UID& b) { return a == b; } + static const bool safeToCompareToEmptyOrDeleted = true; +}; + +} } // namespace JSC::Profiler + +namespace WTF { + +template<typename T> struct DefaultHash; +template<> struct DefaultHash<JSC::Profiler::UID> { + typedef JSC::Profiler::UIDHash Hash; +}; + +template<typename T> struct HashTraits; +template<> struct HashTraits<JSC::Profiler::UID> : SimpleClassHashTraits<JSC::Profiler::UID> { }; + +} // namespace WTF |