diff options
| author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2015-05-20 09:56:07 +0000 |
|---|---|---|
| committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2015-05-20 09:56:07 +0000 |
| commit | 41386e9cb918eed93b3f13648cbef387e371e451 (patch) | |
| tree | a97f9d7bd1d9d091833286085f72da9d83fd0606 /Source/JavaScriptCore/profiler | |
| parent | e15dd966d523731101f70ccf768bba12435a0208 (diff) | |
| download | WebKitGtk-tarball-41386e9cb918eed93b3f13648cbef387e371e451.tar.gz | |
webkitgtk-2.4.9webkitgtk-2.4.9
Diffstat (limited to 'Source/JavaScriptCore/profiler')
26 files changed, 386 insertions, 618 deletions
diff --git a/Source/JavaScriptCore/profiler/CallIdentifier.h b/Source/JavaScriptCore/profiler/CallIdentifier.h index 691fc6250..bf9f904b0 100644 --- a/Source/JavaScriptCore/profiler/CallIdentifier.h +++ b/Source/JavaScriptCore/profiler/CallIdentifier.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2014 Apple Inc. All Rights Reserved. + * 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 @@ -36,37 +36,32 @@ namespace JSC { struct CallIdentifier { WTF_MAKE_FAST_ALLOCATED; public: + String m_name; + String m_url; + unsigned m_lineNumber; + CallIdentifier() : m_lineNumber(0) - , m_columnNumber(0) { } - CallIdentifier(const String& functionName, const String& url, unsigned lineNumber, unsigned columnNumber) - : m_functionName(functionName) + CallIdentifier(const String& name, const String& url, int lineNumber) + : m_name(name) , m_url(!url.isNull() ? url : "") , m_lineNumber(lineNumber) - , m_columnNumber(columnNumber) { } - const String& functionName() const { return m_functionName; } - - const String& url() const { return m_url; } - unsigned lineNumber() const { return m_lineNumber; } - unsigned columnNumber() const { return m_columnNumber; } - - inline bool operator==(const CallIdentifier& other) const { return other.m_lineNumber == m_lineNumber && other.m_columnNumber == m_columnNumber && other.m_functionName == m_functionName && other.m_url == m_url; } - inline bool operator!=(const CallIdentifier& other) const { return !(*this == other); } + 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[4] = { - key.m_functionName.impl()->hash(), + unsigned hashCodes[3] = { + key.m_name.impl()->hash(), key.m_url.impl()->hash(), - key.m_lineNumber, - key.m_columnNumber + key.m_lineNumber }; return StringHasher::hashMemory<sizeof(hashCodes)>(hashCodes); } @@ -79,14 +74,8 @@ namespace JSC { #ifndef NDEBUG operator const char*() const { return c_str(); } - const char* c_str() const { return m_functionName.utf8().data(); } + const char* c_str() const { return m_name.utf8().data(); } #endif - - private: - String m_functionName; - String m_url; - unsigned m_lineNumber; - unsigned m_columnNumber; }; } // namespace JSC @@ -98,15 +87,15 @@ namespace WTF { 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(), std::numeric_limits<unsigned>::max()); + new (NotNull, &slot) JSC::CallIdentifier(String(), String(), std::numeric_limits<unsigned>::max()); } - static bool isDeletedValue(const JSC::CallIdentifier& value) { - return value.functionName().isNull() && value.url().isNull() && value.lineNumber() == std::numeric_limits<unsigned>::max() && value.columnNumber() == std::numeric_limits<unsigned>::max(); + 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 index 787d362dc..dd2acd9f0 100644 --- a/Source/JavaScriptCore/profiler/LegacyProfiler.cpp +++ b/Source/JavaScriptCore/profiler/LegacyProfiler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2012, 2014 Apple Inc. All rights reserved. + * 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 @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -36,7 +36,7 @@ #include "JSFunction.h" #include "JSGlobalObject.h" #include "Nodes.h" -#include "JSCInlines.h" +#include "Operations.h" #include "Profile.h" #include "ProfileGenerator.h" #include "ProfileNode.h" @@ -47,19 +47,21 @@ static const char* GlobalCodeExecution = "(program)"; static const char* AnonymousFunction = "(anonymous function)"; static unsigned ProfilesUID = 0; -static CallIdentifier createCallIdentifierFromFunctionImp(ExecState*, JSObject*, const String& defaultSourceURL, unsigned defaultLineNumber, unsigned defaultColumnNumber); +static CallIdentifier createCallIdentifierFromFunctionImp(ExecState*, JSObject*, const String& defaultSourceURL, int defaultLineNumber); -LegacyProfiler* LegacyProfiler::s_sharedLegacyProfiler = nullptr; +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, PassRefPtr<Stopwatch> stopwatch) +void LegacyProfiler::startProfiling(ExecState* exec, const String& title) { + ASSERT_ARG(title, !title.isNull()); + if (!exec) return; @@ -74,14 +76,14 @@ void LegacyProfiler::startProfiling(ExecState* exec, const String& title, PassRe } exec->vm().setEnabledProfiler(this); - RefPtr<ProfileGenerator> profileGenerator = ProfileGenerator::create(exec, title, ++ProfilesUID, stopwatch); + RefPtr<ProfileGenerator> profileGenerator = ProfileGenerator::create(exec, title, ++ProfilesUID); m_currentProfiles.append(profileGenerator); } -RefPtr<Profile> LegacyProfiler::stopProfiling(ExecState* exec, const String& title) +PassRefPtr<Profile> LegacyProfiler::stopProfiling(ExecState* exec, const String& title) { if (!exec) - return nullptr; + return 0; JSGlobalObject* origin = exec->lexicalGlobalObject(); for (ptrdiff_t i = m_currentProfiles.size() - 1; i >= 0; --i) { @@ -93,12 +95,12 @@ RefPtr<Profile> LegacyProfiler::stopProfiling(ExecState* exec, const String& tit m_currentProfiles.remove(i); if (!m_currentProfiles.size()) exec->vm().setEnabledProfiler(nullptr); - + return returnProfile; } } - return nullptr; + return 0; } void LegacyProfiler::stopProfiling(JSGlobalObject* origin) @@ -114,95 +116,69 @@ void LegacyProfiler::stopProfiling(JSGlobalObject* origin) } } -static inline void callFunctionForProfilesWithGroup(std::function<void(ProfileGenerator*)> callback, const Vector<RefPtr<ProfileGenerator>>& profiles, unsigned targetProfileGroup) +static inline void dispatchFunctionToProfiles(ExecState* callerOrHandlerCallFrame, const Vector<RefPtr<ProfileGenerator>>& profiles, ProfileGenerator::ProfileFunction function, const CallIdentifier& callIdentifier, unsigned currentProfileTargetGroup) { - for (const RefPtr<ProfileGenerator>& profile : profiles) { - if (profile->profileGroup() == targetProfileGroup || !profile->origin()) - callback(profile.get()); + 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::suspendProfiling(JSC::ExecState* exec) -{ - if (!exec) - return; - - callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::setIsSuspended, std::placeholders::_1, true), m_currentProfiles, exec->lexicalGlobalObject()->profileGroup()); -} - -void LegacyProfiler::unsuspendProfiling(JSC::ExecState* exec) -{ - if (!exec) - return; - - callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::setIsSuspended, std::placeholders::_1, false), m_currentProfiles, exec->lexicalGlobalObject()->profileGroup()); -} - void LegacyProfiler::willExecute(ExecState* callerCallFrame, JSValue function) { ASSERT(!m_currentProfiles.isEmpty()); - CallIdentifier callIdentifier = createCallIdentifier(callerCallFrame, function, StringImpl::empty(), 0, 0); - - callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::willExecute, std::placeholders::_1, callerCallFrame, callIdentifier), m_currentProfiles, callerCallFrame->lexicalGlobalObject()->profileGroup()); + dispatchFunctionToProfiles(callerCallFrame, m_currentProfiles, &ProfileGenerator::willExecute, createCallIdentifier(callerCallFrame, function, "", 0), callerCallFrame->lexicalGlobalObject()->profileGroup()); } -void LegacyProfiler::willExecute(ExecState* callerCallFrame, const String& sourceURL, unsigned startingLineNumber, unsigned startingColumnNumber) +void LegacyProfiler::willExecute(ExecState* callerCallFrame, const String& sourceURL, int startingLineNumber) { ASSERT(!m_currentProfiles.isEmpty()); - CallIdentifier callIdentifier = createCallIdentifier(callerCallFrame, JSValue(), sourceURL, startingLineNumber, startingColumnNumber); + CallIdentifier callIdentifier = createCallIdentifier(callerCallFrame, JSValue(), sourceURL, startingLineNumber); - callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::willExecute, std::placeholders::_1, callerCallFrame, callIdentifier), m_currentProfiles, callerCallFrame->lexicalGlobalObject()->profileGroup()); + dispatchFunctionToProfiles(callerCallFrame, m_currentProfiles, &ProfileGenerator::willExecute, callIdentifier, callerCallFrame->lexicalGlobalObject()->profileGroup()); } void LegacyProfiler::didExecute(ExecState* callerCallFrame, JSValue function) { ASSERT(!m_currentProfiles.isEmpty()); - CallIdentifier callIdentifier = createCallIdentifier(callerCallFrame, function, StringImpl::empty(), 0, 0); - - callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::didExecute, std::placeholders::_1, callerCallFrame, callIdentifier), m_currentProfiles, callerCallFrame->lexicalGlobalObject()->profileGroup()); + dispatchFunctionToProfiles(callerCallFrame, m_currentProfiles, &ProfileGenerator::didExecute, createCallIdentifier(callerCallFrame, function, "", 0), callerCallFrame->lexicalGlobalObject()->profileGroup()); } -void LegacyProfiler::didExecute(ExecState* callerCallFrame, const String& sourceURL, unsigned startingLineNumber, unsigned startingColumnNumber) +void LegacyProfiler::didExecute(ExecState* callerCallFrame, const String& sourceURL, int startingLineNumber) { ASSERT(!m_currentProfiles.isEmpty()); - CallIdentifier callIdentifier = createCallIdentifier(callerCallFrame, JSValue(), sourceURL, startingLineNumber, startingColumnNumber); - - callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::didExecute, std::placeholders::_1, callerCallFrame, callIdentifier), m_currentProfiles, callerCallFrame->lexicalGlobalObject()->profileGroup()); + dispatchFunctionToProfiles(callerCallFrame, m_currentProfiles, &ProfileGenerator::didExecute, createCallIdentifier(callerCallFrame, JSValue(), sourceURL, startingLineNumber), callerCallFrame->lexicalGlobalObject()->profileGroup()); } void LegacyProfiler::exceptionUnwind(ExecState* handlerCallFrame) { ASSERT(!m_currentProfiles.isEmpty()); - CallIdentifier callIdentifier = createCallIdentifier(handlerCallFrame, JSValue(), StringImpl::empty(), 0, 0); - - callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::exceptionUnwind, std::placeholders::_1, handlerCallFrame, callIdentifier), m_currentProfiles, handlerCallFrame->lexicalGlobalObject()->profileGroup()); + dispatchFunctionToProfiles(handlerCallFrame, m_currentProfiles, &ProfileGenerator::exceptionUnwind, createCallIdentifier(handlerCallFrame, JSValue(), "", 0), handlerCallFrame->lexicalGlobalObject()->profileGroup()); } -CallIdentifier LegacyProfiler::createCallIdentifier(ExecState* exec, JSValue functionValue, const String& defaultSourceURL, unsigned defaultLineNumber, unsigned defaultColumnNumber) +CallIdentifier LegacyProfiler::createCallIdentifier(ExecState* exec, JSValue functionValue, const String& defaultSourceURL, int defaultLineNumber) { if (!functionValue) - return CallIdentifier(ASCIILiteral(GlobalCodeExecution), defaultSourceURL, defaultLineNumber, defaultColumnNumber); + return CallIdentifier(GlobalCodeExecution, defaultSourceURL, defaultLineNumber); if (!functionValue.isObject()) - return CallIdentifier(ASCIILiteral("(unknown)"), defaultSourceURL, defaultLineNumber, defaultColumnNumber); + return CallIdentifier("(unknown)", defaultSourceURL, defaultLineNumber); if (asObject(functionValue)->inherits(JSFunction::info()) || asObject(functionValue)->inherits(InternalFunction::info())) - return createCallIdentifierFromFunctionImp(exec, asObject(functionValue), defaultSourceURL, defaultLineNumber, defaultColumnNumber); - if (asObject(functionValue)->inherits(JSCallee::info())) - return CallIdentifier(ASCIILiteral(GlobalCodeExecution), defaultSourceURL, defaultLineNumber, defaultColumnNumber); - return CallIdentifier(asObject(functionValue)->methodTable()->className(asObject(functionValue)), defaultSourceURL, defaultLineNumber, defaultColumnNumber); + 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, unsigned defaultLineNumber, unsigned defaultColumnNumber) +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->isHostOrBuiltinFunction()) - return CallIdentifier(name.isEmpty() ? ASCIILiteral(AnonymousFunction) : name, jsFunction->jsExecutable()->sourceURL(), jsFunction->jsExecutable()->firstLine(), jsFunction->jsExecutable()->startColumn()); - return CallIdentifier(name.isEmpty() ? ASCIILiteral(AnonymousFunction) : name, defaultSourceURL, defaultLineNumber, defaultColumnNumber); + 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 index af0ab41e2..607ddec9d 100644 --- a/Source/JavaScriptCore/profiler/LegacyProfiler.h +++ b/Source/JavaScriptCore/profiler/LegacyProfiler.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2012, 2014 Apple Inc. All rights reserved. + * 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 @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -32,12 +32,12 @@ #include "Profile.h" #include <wtf/PassRefPtr.h> #include <wtf/RefPtr.h> -#include <wtf/Stopwatch.h> #include <wtf/Vector.h> namespace JSC { class ExecState; +class VM; class JSGlobalObject; class JSObject; class JSValue; @@ -47,21 +47,17 @@ struct CallIdentifier; class LegacyProfiler { WTF_MAKE_FAST_ALLOCATED; public: - JS_EXPORT_PRIVATE static LegacyProfiler* profiler(); - static CallIdentifier createCallIdentifier(ExecState*, JSValue, const WTF::String& sourceURL, unsigned defaultLineNumber, unsigned defaultColumnNumber); + 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, PassRefPtr<Stopwatch>); - JS_EXPORT_PRIVATE RefPtr<Profile> stopProfiling(ExecState*, const WTF::String& title); + JS_EXPORT_PRIVATE void startProfiling(ExecState*, const WTF::String& title); + JS_EXPORT_PRIVATE PassRefPtr<Profile> stopProfiling(ExecState*, const WTF::String& title); void stopProfiling(JSGlobalObject*); - // Used to ignore profile node subtrees rooted at InjectedScript calls. - JS_EXPORT_PRIVATE void suspendProfiling(ExecState*); - JS_EXPORT_PRIVATE void unsuspendProfiling(ExecState*); - void willExecute(ExecState* callerCallFrame, JSValue function); - void willExecute(ExecState* callerCallFrame, const WTF::String& sourceURL, unsigned startingLineNumber, unsigned startingColumnNumber); + void willExecute(ExecState* callerCallFrame, const WTF::String& sourceURL, int startingLineNumber); void didExecute(ExecState* callerCallFrame, JSValue function); - void didExecute(ExecState* callerCallFrame, const WTF::String& sourceURL, unsigned startingLineNumber, unsigned startingColumnNumber); + void didExecute(ExecState* callerCallFrame, const WTF::String& sourceURL, int startingLineNumber); void exceptionUnwind(ExecState* handlerCallFrame); diff --git a/Source/JavaScriptCore/profiler/Profile.cpp b/Source/JavaScriptCore/profiler/Profile.cpp index f3d450ab2..ed21e7879 100644 --- a/Source/JavaScriptCore/profiler/Profile.cpp +++ b/Source/JavaScriptCore/profiler/Profile.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2014 Apple Inc. All Rights Reserved. + * 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 @@ -31,34 +31,45 @@ namespace JSC { -Ref<Profile> Profile::create(const String& title, unsigned uid, double startTime) +PassRefPtr<Profile> Profile::create(const String& title, unsigned uid) { - return adoptRef(*new Profile(title, uid, startTime)); + return adoptRef(new Profile(title, uid)); } -Profile::Profile(const String& title, unsigned uid, double startTime) +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_rootNode = ProfileNode::create(nullptr, CallIdentifier(ASCIILiteral("Thread_1"), String(), 0, 0), nullptr); - m_rootNode->appendCall(ProfileNode::Call(startTime)); + m_head = ProfileNode::create(0, CallIdentifier("Thread_1", String(), 0), 0, 0); } Profile::~Profile() { } -#ifndef NDEBUG -void Profile::debugPrint() +void Profile::forEach(void (ProfileNode::*function)()) { - CalculateProfileSubtreeDataFunctor functor; - m_rootNode->forEachNodePostorder(functor); - ProfileNode::ProfileSubtreeData data = functor.returnValue(); + 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_rootNode->debugPrintRecursively(0, data); + m_head->debugPrintData(0); } typedef WTF::KeyValuePair<FunctionCallHashCount::ValueType, unsigned> NameCountPair; @@ -68,17 +79,13 @@ static inline bool functionNameCountPairComparator(const NameCountPair& a, const return a.value > b.value; } -void Profile::debugPrintSampleStyle() +void Profile::debugPrintDataSampleStyle() const { typedef Vector<NameCountPair> NameCountPairVector; - CalculateProfileSubtreeDataFunctor functor; - m_rootNode->forEachNodePostorder(functor); - ProfileNode::ProfileSubtreeData data = functor.returnValue(); - FunctionCallHashCount countedFunctions; dataLogF("Call graph:\n"); - m_rootNode->debugPrintSampleStyleRecursively(0, countedFunctions, data); + m_head->debugPrintDataSampleStyle(0, countedFunctions); dataLogF("\nTotal number in stack:\n"); NameCountPairVector sortedFunctions(countedFunctions.size()); diff --git a/Source/JavaScriptCore/profiler/Profile.h b/Source/JavaScriptCore/profiler/Profile.h index 41cb670ca..b1f093d69 100644 --- a/Source/JavaScriptCore/profiler/Profile.h +++ b/Source/JavaScriptCore/profiler/Profile.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2014 Apple Inc. All Rights Reserved. + * 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 @@ -33,33 +33,35 @@ namespace JSC { -class JS_EXPORT_PRIVATE Profile : public RefCounted<Profile> { -public: - static Ref<Profile> create(const String& title, unsigned uid, double); - virtual ~Profile(); + class Profile : public RefCounted<Profile> { + public: + static PassRefPtr<Profile> create(const String& title, unsigned uid); + virtual ~Profile(); - const String& title() const { return m_title; } - unsigned uid() const { return m_uid; } + 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; } - ProfileNode* rootNode() const { return m_rootNode.get(); } - void setRootNode(PassRefPtr<ProfileNode> rootNode) { m_rootNode = rootNode; } + void forEach(void (ProfileNode::*)()); #ifndef NDEBUG - void debugPrint(); - void debugPrintSampleStyle(); + void debugPrintData() const; + void debugPrintDataSampleStyle() const; #endif -protected: - Profile(const String& title, unsigned uid, double startTime); + protected: + Profile(const String& title, unsigned uid); -private: - void removeProfileStart(); - void removeProfileEnd(); - - String m_title; - RefPtr<ProfileNode> m_rootNode; - unsigned m_uid; -}; + private: + void removeProfileStart(); + void removeProfileEnd(); + + String m_title; + RefPtr<ProfileNode> m_head; + unsigned int m_uid; + }; } // namespace JSC diff --git a/Source/JavaScriptCore/profiler/ProfileGenerator.cpp b/Source/JavaScriptCore/profiler/ProfileGenerator.cpp index f70e4a3f6..9361caf70 100644 --- a/Source/JavaScriptCore/profiler/ProfileGenerator.cpp +++ b/Source/JavaScriptCore/profiler/ProfileGenerator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2014 Apple Inc. All Rights Reserved. + * 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 @@ -27,46 +27,44 @@ #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 "JSCInlines.h" +#include "Operations.h" #include "Profile.h" #include "StackVisitor.h" #include "Tracing.h" namespace JSC { -Ref<ProfileGenerator> ProfileGenerator::create(ExecState* exec, const String& title, unsigned uid, PassRefPtr<Stopwatch> stopwatch) +static const char* NonJSExecution = "(idle)"; + +PassRefPtr<ProfileGenerator> ProfileGenerator::create(ExecState* exec, const String& title, unsigned uid) { - return adoptRef(*new ProfileGenerator(exec, title, uid, stopwatch)); + return adoptRef(new ProfileGenerator(exec, title, uid)); } -ProfileGenerator::ProfileGenerator(ExecState* exec, const String& title, unsigned uid, PassRefPtr<Stopwatch> stopwatch) - : m_origin(exec ? exec->lexicalGlobalObject() : nullptr) +ProfileGenerator::ProfileGenerator(ExecState* exec, const String& title, unsigned uid) + : m_origin(exec ? exec->lexicalGlobalObject() : 0) , m_profileGroup(exec ? exec->lexicalGlobalObject()->profileGroup() : 0) - , m_stopwatch(stopwatch) - , m_foundConsoleStartParent(false) - , m_suspended(false) { - double startTime = m_stopwatch->elapsedTime(); - m_profile = Profile::create(title, uid, startTime); - m_currentNode = m_rootNode = m_profile->rootNode(); + m_profile = Profile::create(title, uid); + m_currentNode = m_head = m_profile->head(); if (exec) - addParentForConsoleStart(exec, startTime); + addParentForConsoleStart(exec); } class AddParentForConsoleStartFunctor { public: - AddParentForConsoleStartFunctor(ExecState* exec, RefPtr<ProfileNode>& rootNode, RefPtr<ProfileNode>& currentNode, double startTime) + AddParentForConsoleStartFunctor(ExecState* exec, RefPtr<ProfileNode>& head, RefPtr<ProfileNode>& currentNode) : m_exec(exec) , m_hasSkippedFirstFrame(false) , m_foundParent(false) - , m_rootNode(rootNode) + , m_head(head) , m_currentNode(currentNode) - , m_startTime(startTime) { } @@ -80,11 +78,10 @@ public: } unsigned line = 0; - unsigned column = 0; - visitor->computeLineAndColumn(line, column); - m_currentNode = ProfileNode::create(m_exec, LegacyProfiler::createCallIdentifier(m_exec, visitor->callee(), visitor->sourceURL(), line, column), m_rootNode.get()); - m_currentNode->appendCall(ProfileNode::Call(m_startTime)); - m_rootNode->spliceNode(m_currentNode.get()); + 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; @@ -93,18 +90,20 @@ public: private: ExecState* m_exec; bool m_hasSkippedFirstFrame; - bool m_foundParent; - RefPtr<ProfileNode>& m_rootNode; + bool m_foundParent; + RefPtr<ProfileNode>& m_head; RefPtr<ProfileNode>& m_currentNode; - double m_startTime; }; -void ProfileGenerator::addParentForConsoleStart(ExecState* exec, double startTime) +void ProfileGenerator::addParentForConsoleStart(ExecState* exec) { - AddParentForConsoleStartFunctor functor(exec, m_rootNode, m_currentNode, startTime); + AddParentForConsoleStartFunctor functor(exec, m_head, m_currentNode); exec->iterate(functor); - m_foundConsoleStartParent = functor.foundParent(); + 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 @@ -112,92 +111,46 @@ const String& ProfileGenerator::title() const return m_profile->title(); } -void ProfileGenerator::beginCallEntry(ProfileNode* node, double startTime) -{ - ASSERT_ARG(node, node); - - if (std::isnan(startTime)) - startTime = m_stopwatch->elapsedTime(); - - node->appendCall(ProfileNode::Call(startTime)); -} - -void ProfileGenerator::endCallEntry(ProfileNode* node) -{ - ASSERT_ARG(node, node); - - ProfileNode::Call& last = node->lastCall(); - - double previousElapsedTime = std::isnan(last.elapsedTime()) ? 0.0 : last.elapsedTime(); - double newlyElapsedTime = m_stopwatch->elapsedTime() - last.startTime(); - last.setElapsedTime(previousElapsedTime + newlyElapsedTime); -} - void ProfileGenerator::willExecute(ExecState* callerCallFrame, const CallIdentifier& callIdentifier) { if (JAVASCRIPTCORE_PROFILE_WILL_EXECUTE_ENABLED()) { - CString name = callIdentifier.functionName().utf8(); - CString url = callIdentifier.url().utf8(); - JAVASCRIPTCORE_PROFILE_WILL_EXECUTE(m_profileGroup, const_cast<char*>(name.data()), const_cast<char*>(url.data()), callIdentifier.lineNumber(), callIdentifier.columnNumber()); + 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; - if (m_suspended) - return; - - RefPtr<ProfileNode> calleeNode = nullptr; - - // Find or create a node for the callee call frame. - for (const RefPtr<ProfileNode>& child : m_currentNode->children()) { - if (child->callIdentifier() == callIdentifier) - calleeNode = child; - } - - if (!calleeNode) { - calleeNode = ProfileNode::create(callerCallFrame, callIdentifier, m_currentNode.get()); - m_currentNode->addChild(calleeNode); - } - - m_currentNode = calleeNode; - beginCallEntry(calleeNode.get(), m_stopwatch->elapsedTime()); + 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.functionName().utf8(); - CString url = callIdentifier.url().utf8(); - JAVASCRIPTCORE_PROFILE_DID_EXECUTE(m_profileGroup, const_cast<char*>(name.data()), const_cast<char*>(url.data()), callIdentifier.lineNumber(), callIdentifier.columnNumber()); + 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; - if (m_suspended) - return; - - // Make a new node if the caller node has never seen this callee call frame before. - // This can happen if |console.profile()| is called several frames deep in the call stack. ASSERT(m_currentNode); if (m_currentNode->callIdentifier() != callIdentifier) { - RefPtr<ProfileNode> calleeNode = ProfileNode::create(callerCallFrame, callIdentifier, m_currentNode.get()); - beginCallEntry(calleeNode.get(), m_currentNode->lastCall().startTime()); - endCallEntry(calleeNode.get()); - m_currentNode->spliceNode(calleeNode.release()); + 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; } - endCallEntry(m_currentNode.get()); - m_currentNode = m_currentNode->parent(); + m_currentNode = m_currentNode->didExecute(); } void ProfileGenerator::exceptionUnwind(ExecState* handlerCallFrame, const CallIdentifier&) { - if (m_suspended) - return; - // If the current node was called by the handler (==) or any // more nested function (>) the we have exited early from it. ASSERT(m_currentNode); @@ -209,44 +162,56 @@ void ProfileGenerator::exceptionUnwind(ExecState* handlerCallFrame, const CallId void ProfileGenerator::stopProfiling() { - for (ProfileNode* node = m_currentNode.get(); node != m_profile->rootNode(); node = node->parent()) - endCallEntry(node); + m_profile->forEach(&ProfileNode::stopProfiling); - if (m_foundConsoleStartParent) { - removeProfileStart(); - removeProfileEnd(); - } + 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 = nullptr; - for (ProfileNode* next = m_rootNode.get(); next; next = next->firstChild()) + ProfileNode* currentNode = 0; + for (ProfileNode* next = m_head.get(); next; next = next->firstChild()) currentNode = next; - if (currentNode->callIdentifier().functionName() != "profile") + 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 = nullptr; - for (ProfileNode* next = m_rootNode.get(); next; next = next->lastChild()) + ProfileNode* currentNode = 0; + for (ProfileNode* next = m_head.get(); next; next = next->lastChild()) currentNode = next; - if (currentNode->callIdentifier().functionName() != "profileEnd") + 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); } diff --git a/Source/JavaScriptCore/profiler/ProfileGenerator.h b/Source/JavaScriptCore/profiler/ProfileGenerator.h index 387ed5f4a..40cc8de01 100644 --- a/Source/JavaScriptCore/profiler/ProfileGenerator.h +++ b/Source/JavaScriptCore/profiler/ProfileGenerator.h @@ -22,28 +22,26 @@ * (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> -#include <wtf/Stopwatch.h> -#include <wtf/text/WTFString.h> namespace JSC { - class DebuggerCallFrame; class ExecState; class JSGlobalObject; class Profile; class ProfileNode; - struct CallIdentifier; + struct CallIdentifier; class ProfileGenerator : public RefCounted<ProfileGenerator> { public: - static Ref<ProfileGenerator> create(ExecState*, const WTF::String& title, unsigned uid, PassRefPtr<Stopwatch>); + static PassRefPtr<ProfileGenerator> create(ExecState*, const WTF::String& title, unsigned uid); // Members const WTF::String& title() const; @@ -51,32 +49,29 @@ namespace JSC { 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&); - void setIsSuspended(bool suspended) { ASSERT(m_suspended != suspended); m_suspended = suspended; } + 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, PassRefPtr<Stopwatch>); - void addParentForConsoleStart(ExecState*, double); + ProfileGenerator(ExecState*, const WTF::String& title, unsigned uid); + void addParentForConsoleStart(ExecState*); void removeProfileStart(); void removeProfileEnd(); - void beginCallEntry(ProfileNode*, double startTime); - void endCallEntry(ProfileNode*); - RefPtr<Profile> m_profile; JSGlobalObject* m_origin; unsigned m_profileGroup; - RefPtr<Stopwatch> m_stopwatch; - RefPtr<ProfileNode> m_rootNode; + RefPtr<ProfileNode> m_head; RefPtr<ProfileNode> m_currentNode; - bool m_foundConsoleStartParent; - bool m_suspended; }; } // namespace JSC diff --git a/Source/JavaScriptCore/profiler/ProfileNode.cpp b/Source/JavaScriptCore/profiler/ProfileNode.cpp index 9bcf37586..fe2342ea4 100644 --- a/Source/JavaScriptCore/profiler/ProfileNode.cpp +++ b/Source/JavaScriptCore/profiler/ProfileNode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2014 Apple Inc. All rights reserved. + * 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 @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -34,39 +34,83 @@ #include <wtf/DataLog.h> #include <wtf/text/StringHash.h> +#if OS(WINDOWS) +#include <windows.h> +#endif + using namespace WTF; namespace JSC { -ProfileNode::ProfileNode(ExecState* callerCallFrame, const CallIdentifier& callIdentifier, ProfileNode* parentNode) +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) -#ifndef NDEBUG - , m_nextSibling(nullptr) -#endif + , m_nextSibling(0) + , m_startTime(0.0) + , m_totalTime(0.0) + , m_selfTime(0.0) + , m_numberOfCalls(0) { + startTimer(); } -ProfileNode::ProfileNode(ExecState* callerCallFrame, ProfileNode* nodeToCopy) +ProfileNode::ProfileNode(ExecState* callerCallFrame, ProfileNode* headNode, ProfileNode* nodeToCopy) : m_callerCallFrame(callerCallFrame) , m_callIdentifier(nodeToCopy->callIdentifier()) + , m_head(headNode) , m_parent(nodeToCopy->parent()) - , m_calls(nodeToCopy->calls()) -#ifndef NDEBUG - , m_nextSibling(nullptr) -#endif + , 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); -#ifndef NDEBUG if (m_children.size()) m_children.last()->setNextSibling(child.get()); -#endif m_children.append(child.release()); } @@ -75,18 +119,17 @@ void ProfileNode::removeChild(ProfileNode* node) if (!node) return; - m_children.removeFirstMatching([node] (const RefPtr<ProfileNode>& current) { - return *node == current.get(); - }); - -#ifndef NDEBUG - size_t size = m_children.size(); - for (size_t i = 0; i < size; ++i) - m_children[i]->setNextSibling(i + 1 == size ? nullptr : m_children[i + 1].get()); -#endif + for (size_t i = 0; i < m_children.size(); ++i) { + if (*node == m_children[i].get()) { + m_children.remove(i); + break; + } + } + + resetChildrensSiblings(); } -void ProfileNode::spliceNode(PassRefPtr<ProfileNode> prpNode) +void ProfileNode::insertNode(PassRefPtr<ProfileNode> prpNode) { RefPtr<ProfileNode> node = prpNode; @@ -97,7 +140,21 @@ void ProfileNode::spliceNode(PassRefPtr<ProfileNode> prpNode) m_children.append(node.release()); } -#ifndef NDEBUG +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; @@ -108,63 +165,54 @@ ProfileNode* ProfileNode::traverseNextNodePostOrder() const return next; } -void ProfileNode::debugPrint() +void ProfileNode::endAndRecordCall() { - CalculateProfileSubtreeDataFunctor functor; - forEachNodePostorder(functor); - ProfileNode::ProfileSubtreeData data = functor.returnValue(); + m_totalTime += m_startTime ? getCount() - m_startTime : 0.0; + m_startTime = 0.0; - debugPrintRecursively(0, data); + ++m_numberOfCalls; } -void ProfileNode::debugPrintSampleStyle() +void ProfileNode::startTimer() { - FunctionCallHashCount countedFunctions; - - CalculateProfileSubtreeDataFunctor functor; - forEachNodePostorder(functor); - ProfileNode::ProfileSubtreeData data = functor.returnValue(); + if (!m_startTime) + m_startTime = getCount(); +} - debugPrintSampleStyleRecursively(0, countedFunctions, data); +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()); } -void ProfileNode::debugPrintRecursively(int indentLevel, const ProfileSubtreeData& data) +#ifndef NDEBUG +void ProfileNode::debugPrintData(int indentLevel) const { // Print function names for (int i = 0; i < indentLevel; ++i) dataLogF(" "); - auto it = data.selfAndTotalTimes.find(this); - ASSERT(it != data.selfAndTotalTimes.end()); - - double nodeSelfTime = it->value.first; - double nodeTotalTime = it->value.second; - double rootTotalTime = data.rootTotalTime; - - dataLogF("Function Name %s %zu SelfTime %.3fms/%.3f%% TotalTime %.3fms/%.3f%% Next Sibling %s\n", - functionName().utf8().data(), - m_calls.size(), nodeSelfTime, nodeSelfTime / rootTotalTime * 100.0, nodeTotalTime, nodeTotalTime / rootTotalTime * 100.0, + 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)->debugPrintRecursively(indentLevel, data); + (*currentChild)->debugPrintData(indentLevel); } // print the profiled data in a format that matches the tool sample's output. -double ProfileNode::debugPrintSampleStyleRecursively(int indentLevel, FunctionCallHashCount& countedFunctions, const ProfileSubtreeData& data) +double ProfileNode::debugPrintDataSampleStyle(int indentLevel, FunctionCallHashCount& countedFunctions) const { dataLogF(" "); - auto it = data.selfAndTotalTimes.find(this); - ASSERT(it != data.selfAndTotalTimes.end()); - double nodeTotalTime = it->value.second; - // Print function names const char* name = functionName().utf8().data(); - double sampleCount = nodeTotalTime * 1000; + double sampleCount = m_totalTime * 1000; if (indentLevel) { for (int i = 0; i < indentLevel; ++i) dataLogF(" "); @@ -180,7 +228,7 @@ double ProfileNode::debugPrintSampleStyleRecursively(int indentLevel, FunctionCa // Print children's names and information double sumOfChildrensCount = 0.0; for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild) - sumOfChildrensCount += (*currentChild)->debugPrintSampleStyleRecursively(indentLevel, countedFunctions, data); + sumOfChildrensCount += (*currentChild)->debugPrintDataSampleStyle(indentLevel, countedFunctions); sumOfChildrensCount *= 1000; // // Print remainder of samples to match sample's output @@ -192,7 +240,7 @@ double ProfileNode::debugPrintSampleStyleRecursively(int indentLevel, FunctionCa dataLogF("%.0f %s\n", sampleCount - sumOfChildrensCount, functionName().utf8().data()); } - return nodeTotalTime; + return m_totalTime; } #endif diff --git a/Source/JavaScriptCore/profiler/ProfileNode.h b/Source/JavaScriptCore/profiler/ProfileNode.h index fcaee0e24..e21b42282 100644 --- a/Source/JavaScriptCore/profiler/ProfileNode.h +++ b/Source/JavaScriptCore/profiler/ProfileNode.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2014 Apple Inc. All rights reserved. + * 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 @@ -10,7 +10,7 @@ * 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 Inc. ("Apple") nor the names of + * 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. * @@ -44,150 +44,96 @@ namespace JSC { class ProfileNode : public RefCounted<ProfileNode> { public: - static Ref<ProfileNode> create(ExecState* callerCallFrame, const CallIdentifier& callIdentifier, ProfileNode* parentNode) + static PassRefPtr<ProfileNode> create(ExecState* callerCallFrame, const CallIdentifier& callIdentifier, ProfileNode* headNode, ProfileNode* parentNode) { - return adoptRef(*new ProfileNode(callerCallFrame, callIdentifier, parentNode)); + return adoptRef(new ProfileNode(callerCallFrame, callIdentifier, headNode, parentNode)); } - static Ref<ProfileNode> create(ExecState* callerCallFrame, ProfileNode* node) + static PassRefPtr<ProfileNode> create(ExecState* callerCallFrame, ProfileNode* headNode, ProfileNode* node) { - return adoptRef(*new ProfileNode(callerCallFrame, node)); + return adoptRef(new ProfileNode(callerCallFrame, headNode, node)); } - struct Call { - public: - Call(double startTime, double elapsedTime = NAN) - : m_startTime(startTime) - , m_elapsedTime(elapsedTime) - { - } - - double startTime() const { return m_startTime; } - void setStartTime(double time) - { - ASSERT_ARG(time, time >= 0.0 || std::isnan(time)); - m_startTime = time; - } - - double elapsedTime() const { return m_elapsedTime; } - void setElapsedTime(double time) - { - ASSERT_ARG(time, time >= 0.0 || std::isnan(time)); - m_elapsedTime = time; - } - - private: - double m_startTime; - double m_elapsedTime; - }; - 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 id() const { return m_callIdentifier.hash(); } - const String& functionName() const { return m_callIdentifier.functionName(); } - const String& url() const { return m_callIdentifier.url(); } - unsigned lineNumber() const { return m_callIdentifier.lineNumber(); } - unsigned columnNumber() const { return m_callIdentifier.columnNumber(); } + 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; } - const Vector<Call>& calls() const { return m_calls; } - Call& lastCall() { ASSERT(!m_calls.isEmpty()); return m_calls.last(); } - void appendCall(Call call) { m_calls.append(call); } + ProfileNode* nextSibling() const { return m_nextSibling; } + void setNextSibling(ProfileNode* nextSibling) { m_nextSibling = nextSibling; } - const Vector<RefPtr<ProfileNode>>& children() const { return m_children; } - ProfileNode* firstChild() const { return m_children.size() ? m_children.first().get() : nullptr; } - ProfileNode* lastChild() const { return m_children.size() ? m_children.last().get() : nullptr; } + // Time members + double startTime() const { return m_startTime; } + void setStartTime(double startTime) { m_startTime = startTime; } - void removeChild(ProfileNode*); - void addChild(PassRefPtr<ProfileNode>); - // Reparent our child nodes to the passed node, and make it a child node of |this|. - void spliceNode(PassRefPtr<ProfileNode>); + double totalTime() const { return m_totalTime; } + void setTotalTime(double time) { m_totalTime = time; } -#ifndef NDEBUG - struct ProfileSubtreeData { - HashMap<ProfileNode*, std::pair<double, double>> selfAndTotalTimes; - double rootTotalTime; - }; + double selfTime() const { return m_selfTime; } + void setSelfTime(double time) { m_selfTime = time; } - // Use these functions to dump the subtree rooted at this node. - void debugPrint(); - void debugPrintSampleStyle(); + 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; } - // These are used to recursively print entire subtrees using precomputed self and total times. - template <typename Functor> void forEachNodePostorder(Functor&); + unsigned numberOfCalls() const { return m_numberOfCalls; } - void debugPrintRecursively(int indentLevel, const ProfileSubtreeData&); - double debugPrintSampleStyleRecursively(int indentLevel, FunctionCallHashCount&, const ProfileSubtreeData&); + // 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* parentNode); - ProfileNode(ExecState* callerCallFrame, ProfileNode* nodeToCopy); - -#ifndef NDEBUG - ProfileNode* nextSibling() const { return m_nextSibling; } - void setNextSibling(ProfileNode* nextSibling) { m_nextSibling = nextSibling; } + ProfileNode(ExecState* callerCallFrame, const CallIdentifier&, ProfileNode* headNode, ProfileNode* parentNode); + ProfileNode(ExecState* callerCallFrame, ProfileNode* headNode, ProfileNode* nodeToCopy); - ProfileNode* traverseNextNodePostOrder() const; -#endif + void startTimer(); + void resetChildrensSiblings(); ExecState* m_callerCallFrame; CallIdentifier m_callIdentifier; + ProfileNode* m_head; ProfileNode* m_parent; - Vector<Call> m_calls; - Vector<RefPtr<ProfileNode>> m_children; - -#ifndef NDEBUG ProfileNode* m_nextSibling; -#endif - }; -#ifndef NDEBUG - template <typename Functor> inline void ProfileNode::forEachNodePostorder(Functor& functor) - { - ProfileNode* currentNode = this; - // Go down to the first node of the traversal, and slowly walk back up. - for (ProfileNode* nextNode = currentNode; nextNode; nextNode = nextNode->firstChild()) - currentNode = nextNode; - - ProfileNode* endNode = this; - while (currentNode && currentNode != endNode) { - functor(currentNode); - currentNode = currentNode->traverseNextNodePostOrder(); - } - - functor(endNode); - } + double m_startTime; + double m_totalTime; + double m_selfTime; + unsigned m_numberOfCalls; - struct CalculateProfileSubtreeDataFunctor { - void operator()(ProfileNode* node) - { - double selfTime = 0.0; - for (const ProfileNode::Call& call : node->calls()) - selfTime += call.elapsedTime(); - - double totalTime = selfTime; - for (RefPtr<ProfileNode> child : node->children()) { - auto it = m_data.selfAndTotalTimes.find(child.get()); - if (it != m_data.selfAndTotalTimes.end()) - totalTime += it->value.second; - } - - ASSERT(node); - m_data.selfAndTotalTimes.set(node, std::make_pair(selfTime, totalTime)); - } - - ProfileNode::ProfileSubtreeData returnValue() { return WTF::move(m_data); } - - ProfileNode::ProfileSubtreeData m_data; + Vector<RefPtr<ProfileNode>> m_children; }; -#endif } // namespace JSC diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecode.cpp b/Source/JavaScriptCore/profiler/ProfilerBytecode.cpp index 6eeeb27b9..ca602e42f 100644 --- a/Source/JavaScriptCore/profiler/ProfilerBytecode.cpp +++ b/Source/JavaScriptCore/profiler/ProfilerBytecode.cpp @@ -28,7 +28,7 @@ #include "JSGlobalObject.h" #include "ObjectConstructor.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { namespace Profiler { diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp b/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp index 145ee44d1..838153bea 100644 --- a/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp +++ b/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2013 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,7 +29,7 @@ #include "CodeBlock.h" #include "JSGlobalObject.h" #include "Operands.h" -#include "JSCInlines.h" +#include "Operations.h" #include <wtf/StringPrintStream.h> namespace JSC { namespace Profiler { @@ -44,16 +44,13 @@ BytecodeSequence::BytecodeSequence(CodeBlock* codeBlock) if (!description.length()) continue; out.reset(); - out.print("arg", i, ": ", description); + out.print("arg", i, " (r", virtualRegisterForArgument(i).offset(), "): ", 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, stubInfos); + codeBlock->dumpBytecode(out, bytecodeIndex); m_sequence.append(Bytecode(bytecodeIndex, codeBlock->vm()->interpreter->getOpcodeID(codeBlock->instructions()[bytecodeIndex].u.opcode), out.toCString())); bytecodeIndex += opcodeLength( codeBlock->vm()->interpreter->getOpcodeID( diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp b/Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp index 74c55abcf..aa5a6d9c9 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 "JSCInlines.h" +#include "Operations.h" #include <wtf/StringPrintStream.h> namespace JSC { namespace Profiler { diff --git a/Source/JavaScriptCore/profiler/ProfilerCompilation.cpp b/Source/JavaScriptCore/profiler/ProfilerCompilation.cpp index 488f563de..55766ce5c 100644 --- a/Source/JavaScriptCore/profiler/ProfilerCompilation.cpp +++ b/Source/JavaScriptCore/profiler/ProfilerCompilation.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2013 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,9 +28,8 @@ #include "JSGlobalObject.h" #include "ObjectConstructor.h" -#include "JSCInlines.h" +#include "Operations.h" #include "ProfilerDatabase.h" -#include "Watchpoint.h" #include <wtf/StringPrintStream.h> namespace JSC { namespace Profiler { @@ -38,7 +37,6 @@ 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) @@ -69,11 +67,6 @@ 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; @@ -94,18 +87,6 @@ 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(); -} - JSValue Compilation::toJS(ExecState* exec) const { JSObject* result = constructEmptyObject(exec); @@ -145,9 +126,6 @@ JSValue Compilation::toJS(ExecState* exec) const 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(exec->vm(), exec->propertyNames().jettisonReason, jsString(exec, String::fromUTF8(toCString(m_jettisonReason)))); - if (!m_additionalJettisonReason.isNull()) - result->putDirect(exec->vm(), exec->propertyNames().additionalJettisonReason, jsString(exec, String::fromUTF8(m_additionalJettisonReason))); return result; } diff --git a/Source/JavaScriptCore/profiler/ProfilerCompilation.h b/Source/JavaScriptCore/profiler/ProfilerCompilation.h index b358b659c..dc2810525 100644 --- a/Source/JavaScriptCore/profiler/ProfilerCompilation.h +++ b/Source/JavaScriptCore/profiler/ProfilerCompilation.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,7 +31,6 @@ #include "ProfilerCompilationKind.h" #include "ProfilerCompiledBytecode.h" #include "ProfilerExecutionCounter.h" -#include "ProfilerJettisonReason.h" #include "ProfilerOSRExit.h" #include "ProfilerOSRExitSite.h" #include "ProfilerOriginStack.h" @@ -39,11 +38,7 @@ #include <wtf/RefCounted.h> #include <wtf/SegmentedVector.h> -namespace JSC { - -class FireDetail; - -namespace Profiler { +namespace JSC { namespace Profiler { class Bytecodes; class Database; @@ -68,20 +63,15 @@ 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*); - 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; diff --git a/Source/JavaScriptCore/profiler/ProfilerCompilationKind.cpp b/Source/JavaScriptCore/profiler/ProfilerCompilationKind.cpp index 3fbe25192..78ce70586 100644 --- a/Source/JavaScriptCore/profiler/ProfilerCompilationKind.cpp +++ b/Source/JavaScriptCore/profiler/ProfilerCompilationKind.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2014 Apple Inc. All rights reserved. + * Copyright (C) 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 @@ -42,12 +42,6 @@ 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 575ec2947..4806d39b9 100644 --- a/Source/JavaScriptCore/profiler/ProfilerCompilationKind.h +++ b/Source/JavaScriptCore/profiler/ProfilerCompilationKind.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2014 Apple Inc. All rights reserved. + * Copyright (C) 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 @@ -31,9 +31,7 @@ namespace JSC { namespace Profiler { enum CompilationKind { LLInt, Baseline, - DFG, - FTL, - FTLForOSREntry + DFG }; } } // namespace JSC::Profiler diff --git a/Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.cpp b/Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.cpp index 4891c315c..455a48ed9 100644 --- a/Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.cpp +++ b/Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.cpp @@ -28,7 +28,7 @@ #include "JSGlobalObject.h" #include "ObjectConstructor.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { namespace Profiler { diff --git a/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp b/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp index fc952c0c2..f83652dda 100644 --- a/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp +++ b/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp @@ -29,13 +29,13 @@ #include "CodeBlock.h" #include "JSONObject.h" #include "ObjectConstructor.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { namespace Profiler { static std::atomic<int> databaseCounter; -static StaticLock registrationLock; +static SpinLock registrationLock = SPINLOCK_INITIALIZER; static std::atomic<int> didRegisterAtExit; static Database* firstDatabase; @@ -57,7 +57,7 @@ Database::~Database() Bytecodes* Database::ensureBytecodesFor(CodeBlock* codeBlock) { - LockHolder locker(m_lock); + Locker locker(m_lock); codeBlock = codeBlock->baselineVersion(); @@ -75,7 +75,7 @@ Bytecodes* Database::ensureBytecodesFor(CodeBlock* codeBlock) void Database::notifyDestruction(CodeBlock* codeBlock) { - LockHolder locker(m_lock); + Locker locker(m_lock); m_bytecodesMap.remove(codeBlock); } @@ -138,14 +138,14 @@ void Database::addDatabaseToAtExit() if (++didRegisterAtExit == 1) atexit(atExitCallback); - LockHolder holder(registrationLock); + TCMalloc_SpinLockHolder holder(®istrationLock); m_nextRegisteredDatabase = firstDatabase; firstDatabase = this; } void Database::removeDatabaseFromAtExit() { - LockHolder holder(registrationLock); + TCMalloc_SpinLockHolder holder(®istrationLock); for (Database** current = &firstDatabase; *current; current = &(*current)->m_nextRegisteredDatabase) { if (*current != this) continue; @@ -163,7 +163,7 @@ void Database::performAtExitSave() const Database* Database::removeFirstAtExitDatabase() { - LockHolder holder(registrationLock); + TCMalloc_SpinLockHolder holder(®istrationLock); Database* result = firstDatabase; if (result) { firstDatabase = result->m_nextRegisteredDatabase; diff --git a/Source/JavaScriptCore/profiler/ProfilerDatabase.h b/Source/JavaScriptCore/profiler/ProfilerDatabase.h index 9bb64cf49..7d4f3cf2c 100644 --- a/Source/JavaScriptCore/profiler/ProfilerDatabase.h +++ b/Source/JavaScriptCore/profiler/ProfilerDatabase.h @@ -32,7 +32,6 @@ #include "ProfilerCompilationKind.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> @@ -71,6 +70,21 @@ public: void registerToSaveAtExit(const char* filename); 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; + + void addDatabaseToAtExit(); void removeDatabaseFromAtExit(); void performAtExitSave() const; diff --git a/Source/JavaScriptCore/profiler/ProfilerJettisonReason.cpp b/Source/JavaScriptCore/profiler/ProfilerJettisonReason.cpp deleted file mode 100644 index 5fad7297f..000000000 --- a/Source/JavaScriptCore/profiler/ProfilerJettisonReason.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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 JettisonDueToLegacyProfiler: - out.print("LegacyProfiler"); - 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; - } - RELEASE_ASSERT_NOT_REACHED(); -} - -} // namespace WTF - diff --git a/Source/JavaScriptCore/profiler/ProfilerJettisonReason.h b/Source/JavaScriptCore/profiler/ProfilerJettisonReason.h deleted file mode 100644 index 0a15ba30e..000000000 --- a/Source/JavaScriptCore/profiler/ProfilerJettisonReason.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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. - */ - -#ifndef ProfilerJettisonReason_h -#define ProfilerJettisonReason_h - -namespace JSC { namespace Profiler { - -enum JettisonReason { - NotJettisoned, - JettisonDueToWeakReference, - JettisonDueToDebuggerBreakpoint, - JettisonDueToDebuggerStepping, - JettisonDueToLegacyProfiler, - JettisonDueToBaselineLoopReoptimizationTrigger, - JettisonDueToBaselineLoopReoptimizationTriggerOnOSREntryFail, - JettisonDueToOSRExit, - JettisonDueToProfiledWatchpoint, - JettisonDueToUnprofiledWatchpoint -}; - -} } // namespace JSC::Profiler - -namespace WTF { - -class PrintStream; -void printInternal(PrintStream&, JSC::Profiler::JettisonReason); - -} // namespace WTF - -#endif // ProfilerJettisonReason_h - diff --git a/Source/JavaScriptCore/profiler/ProfilerOSRExit.cpp b/Source/JavaScriptCore/profiler/ProfilerOSRExit.cpp index 2a5d5be40..0024791b4 100644 --- a/Source/JavaScriptCore/profiler/ProfilerOSRExit.cpp +++ b/Source/JavaScriptCore/profiler/ProfilerOSRExit.cpp @@ -28,7 +28,7 @@ #include "JSGlobalObject.h" #include "ObjectConstructor.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { namespace Profiler { diff --git a/Source/JavaScriptCore/profiler/ProfilerOSRExitSite.cpp b/Source/JavaScriptCore/profiler/ProfilerOSRExitSite.cpp index b17d57e52..d54f7a275 100644 --- a/Source/JavaScriptCore/profiler/ProfilerOSRExitSite.cpp +++ b/Source/JavaScriptCore/profiler/ProfilerOSRExitSite.cpp @@ -29,7 +29,7 @@ #include "JSGlobalObject.h" #include "JSScope.h" #include "JSString.h" -#include "JSCInlines.h" +#include "Operations.h" #include <wtf/StringPrintStream.h> namespace JSC { namespace Profiler { diff --git a/Source/JavaScriptCore/profiler/ProfilerOrigin.cpp b/Source/JavaScriptCore/profiler/ProfilerOrigin.cpp index 7c28f7ba3..1ac29d1cc 100644 --- a/Source/JavaScriptCore/profiler/ProfilerOrigin.cpp +++ b/Source/JavaScriptCore/profiler/ProfilerOrigin.cpp @@ -28,7 +28,7 @@ #include "JSGlobalObject.h" #include "ObjectConstructor.h" -#include "JSCInlines.h" +#include "Operations.h" #include "ProfilerBytecodes.h" #include "ProfilerDatabase.h" diff --git a/Source/JavaScriptCore/profiler/ProfilerOriginStack.cpp b/Source/JavaScriptCore/profiler/ProfilerOriginStack.cpp index 9b61daec1..018ceeb8c 100644 --- a/Source/JavaScriptCore/profiler/ProfilerOriginStack.cpp +++ b/Source/JavaScriptCore/profiler/ProfilerOriginStack.cpp @@ -28,7 +28,7 @@ #include "CodeOrigin.h" #include "JSGlobalObject.h" -#include "JSCInlines.h" +#include "Operations.h" #include "ProfilerDatabase.h" namespace JSC { namespace Profiler { diff --git a/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.cpp b/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.cpp index fe590ff78..6ca6c9f15 100644 --- a/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.cpp +++ b/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.cpp @@ -28,7 +28,7 @@ #include "JSGlobalObject.h" #include "ObjectConstructor.h" -#include "JSCInlines.h" +#include "Operations.h" namespace JSC { namespace Profiler { |
