diff options
author | Konstantin Tokarev <annulen@yandex.ru> | 2016-08-25 19:20:41 +0300 |
---|---|---|
committer | Konstantin Tokarev <annulen@yandex.ru> | 2017-02-02 12:30:55 +0000 |
commit | 6882a04fb36642862b11efe514251d32070c3d65 (patch) | |
tree | b7959826000b061fd5ccc7512035c7478742f7b0 /Source/JavaScriptCore/profiler | |
parent | ab6df191029eeeb0b0f16f127d553265659f739e (diff) | |
download | qtwebkit-6882a04fb36642862b11efe514251d32070c3d65.tar.gz |
Imported QtWebKit TP3 (git b57bc6801f1876c3220d5a4bfea33d620d477443)
Change-Id: I3b1d8a2808782c9f34d50240000e20cb38d3680f
Reviewed-by: Konstantin Tokarev <annulen@yandex.ru>
Diffstat (limited to 'Source/JavaScriptCore/profiler')
28 files changed, 700 insertions, 598 deletions
diff --git a/Source/JavaScriptCore/profiler/CallIdentifier.h b/Source/JavaScriptCore/profiler/CallIdentifier.h index bf9f904b0..691fc6250 100644 --- a/Source/JavaScriptCore/profiler/CallIdentifier.h +++ b/Source/JavaScriptCore/profiler/CallIdentifier.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008, 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 @@ -36,32 +36,37 @@ 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& name, const String& url, int lineNumber) - : m_name(name) + CallIdentifier(const String& functionName, const String& url, unsigned lineNumber, unsigned columnNumber) + : m_functionName(functionName) , m_url(!url.isNull() ? url : "") , m_lineNumber(lineNumber) + , m_columnNumber(columnNumber) { } - 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); } + 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); } struct Hash { static unsigned hash(const CallIdentifier& key) { - unsigned hashCodes[3] = { - key.m_name.impl()->hash(), + unsigned hashCodes[4] = { + key.m_functionName.impl()->hash(), key.m_url.impl()->hash(), - key.m_lineNumber + key.m_lineNumber, + key.m_columnNumber }; return StringHasher::hashMemory<sizeof(hashCodes)>(hashCodes); } @@ -74,8 +79,14 @@ namespace JSC { #ifndef NDEBUG operator const char*() const { return c_str(); } - const char* c_str() const { return m_name.utf8().data(); } + const char* c_str() const { return m_functionName.utf8().data(); } #endif + + private: + String m_functionName; + String m_url; + unsigned m_lineNumber; + unsigned m_columnNumber; }; } // namespace JSC @@ -87,15 +98,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()); + new (NotNull, &slot) JSC::CallIdentifier(String(), String(), std::numeric_limits<unsigned>::max(), 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(); + return value.functionName().isNull() && value.url().isNull() && value.lineNumber() == std::numeric_limits<unsigned>::max() && value.columnNumber() == 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 1db2e625e..787d362dc 100644 --- a/Source/JavaScriptCore/profiler/LegacyProfiler.cpp +++ b/Source/JavaScriptCore/profiler/LegacyProfiler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2012 Apple Inc. All rights reserved. + * Copyright (C) 2008, 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 @@ -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 Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple 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,11 +36,10 @@ #include "JSFunction.h" #include "JSGlobalObject.h" #include "Nodes.h" -#include "Operations.h" +#include "JSCInlines.h" #include "Profile.h" #include "ProfileGenerator.h" #include "ProfileNode.h" -#include <stdio.h> namespace JSC { @@ -48,21 +47,19 @@ 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); +static CallIdentifier createCallIdentifierFromFunctionImp(ExecState*, JSObject*, const String& defaultSourceURL, unsigned defaultLineNumber, unsigned defaultColumnNumber); -LegacyProfiler* LegacyProfiler::s_sharedLegacyProfiler = 0; +LegacyProfiler* LegacyProfiler::s_sharedLegacyProfiler = nullptr; LegacyProfiler* LegacyProfiler::profiler() { if (!s_sharedLegacyProfiler) s_sharedLegacyProfiler = new LegacyProfiler(); return s_sharedLegacyProfiler; -} +} -void LegacyProfiler::startProfiling(ExecState* exec, const String& title) +void LegacyProfiler::startProfiling(ExecState* exec, const String& title, PassRefPtr<Stopwatch> stopwatch) { - ASSERT_ARG(title, !title.isNull()); - if (!exec) return; @@ -76,15 +73,15 @@ void LegacyProfiler::startProfiling(ExecState* exec, const String& title) return; } - exec->vm().m_enabledProfiler = this; - RefPtr<ProfileGenerator> profileGenerator = ProfileGenerator::create(exec, title, ++ProfilesUID); + exec->vm().setEnabledProfiler(this); + RefPtr<ProfileGenerator> profileGenerator = ProfileGenerator::create(exec, title, ++ProfilesUID, stopwatch); m_currentProfiles.append(profileGenerator); } -PassRefPtr<Profile> LegacyProfiler::stopProfiling(ExecState* exec, const String& title) +RefPtr<Profile> LegacyProfiler::stopProfiling(ExecState* exec, const String& title) { if (!exec) - return 0; + return nullptr; JSGlobalObject* origin = exec->lexicalGlobalObject(); for (ptrdiff_t i = m_currentProfiles.size() - 1; i >= 0; --i) { @@ -95,13 +92,13 @@ PassRefPtr<Profile> LegacyProfiler::stopProfiling(ExecState* exec, const String& m_currentProfiles.remove(i); if (!m_currentProfiles.size()) - exec->vm().m_enabledProfiler = 0; - + exec->vm().setEnabledProfiler(nullptr); + return returnProfile; } } - return 0; + return nullptr; } void LegacyProfiler::stopProfiling(JSGlobalObject* origin) @@ -112,74 +109,100 @@ void LegacyProfiler::stopProfiling(JSGlobalObject* origin) profileGenerator->stopProfiling(); m_currentProfiles.remove(i); if (!m_currentProfiles.size()) - origin->vm().m_enabledProfiler = 0; + origin->vm().setEnabledProfiler(nullptr); } } } -static inline void dispatchFunctionToProfiles(ExecState* callerOrHandlerCallFrame, const Vector<RefPtr<ProfileGenerator> >& profiles, ProfileGenerator::ProfileFunction function, const CallIdentifier& callIdentifier, unsigned currentProfileTargetGroup) +static inline void callFunctionForProfilesWithGroup(std::function<void(ProfileGenerator*)> callback, const Vector<RefPtr<ProfileGenerator>>& profiles, unsigned targetProfileGroup) { - for (size_t i = 0; i < profiles.size(); ++i) { - if (profiles[i]->profileGroup() == currentProfileTargetGroup || !profiles[i]->origin()) - (profiles[i].get()->*function)(callerOrHandlerCallFrame, callIdentifier); + for (const RefPtr<ProfileGenerator>& profile : profiles) { + if (profile->profileGroup() == targetProfileGroup || !profile->origin()) + callback(profile.get()); } } +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()); - dispatchFunctionToProfiles(callerCallFrame, m_currentProfiles, &ProfileGenerator::willExecute, createCallIdentifier(callerCallFrame, function, "", 0), callerCallFrame->lexicalGlobalObject()->profileGroup()); + CallIdentifier callIdentifier = createCallIdentifier(callerCallFrame, function, StringImpl::empty(), 0, 0); + + callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::willExecute, std::placeholders::_1, callerCallFrame, callIdentifier), m_currentProfiles, callerCallFrame->lexicalGlobalObject()->profileGroup()); } -void LegacyProfiler::willExecute(ExecState* callerCallFrame, const String& sourceURL, int startingLineNumber) +void LegacyProfiler::willExecute(ExecState* callerCallFrame, const String& sourceURL, unsigned startingLineNumber, unsigned startingColumnNumber) { ASSERT(!m_currentProfiles.isEmpty()); - CallIdentifier callIdentifier = createCallIdentifier(callerCallFrame, JSValue(), sourceURL, startingLineNumber); + CallIdentifier callIdentifier = createCallIdentifier(callerCallFrame, JSValue(), sourceURL, startingLineNumber, startingColumnNumber); - dispatchFunctionToProfiles(callerCallFrame, m_currentProfiles, &ProfileGenerator::willExecute, callIdentifier, callerCallFrame->lexicalGlobalObject()->profileGroup()); + callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::willExecute, std::placeholders::_1, callerCallFrame, callIdentifier), m_currentProfiles, 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()); + CallIdentifier callIdentifier = createCallIdentifier(callerCallFrame, function, StringImpl::empty(), 0, 0); + + callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::didExecute, std::placeholders::_1, callerCallFrame, callIdentifier), m_currentProfiles, callerCallFrame->lexicalGlobalObject()->profileGroup()); } -void LegacyProfiler::didExecute(ExecState* callerCallFrame, const String& sourceURL, int startingLineNumber) +void LegacyProfiler::didExecute(ExecState* callerCallFrame, const String& sourceURL, unsigned startingLineNumber, unsigned startingColumnNumber) { ASSERT(!m_currentProfiles.isEmpty()); - dispatchFunctionToProfiles(callerCallFrame, m_currentProfiles, &ProfileGenerator::didExecute, createCallIdentifier(callerCallFrame, JSValue(), sourceURL, startingLineNumber), callerCallFrame->lexicalGlobalObject()->profileGroup()); + CallIdentifier callIdentifier = createCallIdentifier(callerCallFrame, JSValue(), sourceURL, startingLineNumber, startingColumnNumber); + + callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::didExecute, std::placeholders::_1, callerCallFrame, callIdentifier), m_currentProfiles, 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 callIdentifier = createCallIdentifier(handlerCallFrame, JSValue(), StringImpl::empty(), 0, 0); + + callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::exceptionUnwind, std::placeholders::_1, handlerCallFrame, callIdentifier), m_currentProfiles, handlerCallFrame->lexicalGlobalObject()->profileGroup()); } -CallIdentifier LegacyProfiler::createCallIdentifier(ExecState* exec, JSValue functionValue, const String& defaultSourceURL, int defaultLineNumber) +CallIdentifier LegacyProfiler::createCallIdentifier(ExecState* exec, JSValue functionValue, const String& defaultSourceURL, unsigned defaultLineNumber, unsigned defaultColumnNumber) { if (!functionValue) - return CallIdentifier(GlobalCodeExecution, defaultSourceURL, defaultLineNumber); + return CallIdentifier(ASCIILiteral(GlobalCodeExecution), defaultSourceURL, defaultLineNumber, defaultColumnNumber); if (!functionValue.isObject()) - return CallIdentifier("(unknown)", defaultSourceURL, defaultLineNumber); - if (asObject(functionValue)->inherits(&JSFunction::s_info) || asObject(functionValue)->inherits(&InternalFunction::s_info)) - return createCallIdentifierFromFunctionImp(exec, asObject(functionValue), defaultSourceURL, defaultLineNumber); - return CallIdentifier(makeString("(", asObject(functionValue)->methodTable()->className(asObject(functionValue)), " object)"), defaultSourceURL, defaultLineNumber); + return CallIdentifier(ASCIILiteral("(unknown)"), defaultSourceURL, defaultLineNumber, defaultColumnNumber); + 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); } -CallIdentifier createCallIdentifierFromFunctionImp(ExecState* exec, JSObject* function, const String& defaultSourceURL, int defaultLineNumber) +CallIdentifier createCallIdentifierFromFunctionImp(ExecState* exec, JSObject* function, const String& defaultSourceURL, unsigned defaultLineNumber, unsigned defaultColumnNumber) { 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); + 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); } } // namespace JSC diff --git a/Source/JavaScriptCore/profiler/LegacyProfiler.h b/Source/JavaScriptCore/profiler/LegacyProfiler.h index 6db57cbf2..af0ab41e2 100644 --- a/Source/JavaScriptCore/profiler/LegacyProfiler.h +++ b/Source/JavaScriptCore/profiler/LegacyProfiler.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2012 Apple Inc. All rights reserved. + * Copyright (C) 2008, 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 @@ -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 Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple 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,24 +47,28 @@ 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 static LegacyProfiler* profiler(); + static CallIdentifier createCallIdentifier(ExecState*, JSValue, const WTF::String& sourceURL, unsigned defaultLineNumber, unsigned defaultColumnNumber); - JS_EXPORT_PRIVATE void startProfiling(ExecState*, const WTF::String& title); - JS_EXPORT_PRIVATE PassRefPtr<Profile> stopProfiling(ExecState*, const WTF::String& title); + JS_EXPORT_PRIVATE void startProfiling(ExecState*, const WTF::String& title, PassRefPtr<Stopwatch>); + JS_EXPORT_PRIVATE RefPtr<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, int startingLineNumber); + void willExecute(ExecState* callerCallFrame, const WTF::String& sourceURL, unsigned startingLineNumber, unsigned startingColumnNumber); void didExecute(ExecState* callerCallFrame, JSValue function); - void didExecute(ExecState* callerCallFrame, const WTF::String& sourceURL, int startingLineNumber); + void didExecute(ExecState* callerCallFrame, const WTF::String& sourceURL, unsigned startingLineNumber, unsigned startingColumnNumber); void exceptionUnwind(ExecState* handlerCallFrame); - const Vector<RefPtr<ProfileGenerator> >& currentProfiles() { return m_currentProfiles; }; + const Vector<RefPtr<ProfileGenerator>>& currentProfiles() { return m_currentProfiles; }; private: - Vector<RefPtr<ProfileGenerator> > m_currentProfiles; + Vector<RefPtr<ProfileGenerator>> m_currentProfiles; static LegacyProfiler* s_sharedLegacyProfiler; }; diff --git a/Source/JavaScriptCore/profiler/Profile.cpp b/Source/JavaScriptCore/profiler/Profile.cpp index 2274889a1..f3d450ab2 100644 --- a/Source/JavaScriptCore/profiler/Profile.cpp +++ b/Source/JavaScriptCore/profiler/Profile.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008, 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 @@ -27,84 +27,38 @@ #include "Profile.h" #include "ProfileNode.h" -#include <stdio.h> #include <wtf/DataLog.h> namespace JSC { -PassRefPtr<Profile> Profile::create(const String& title, unsigned uid) +Ref<Profile> Profile::create(const String& title, unsigned uid, double startTime) { - return adoptRef(new Profile(title, uid)); + return adoptRef(*new Profile(title, uid, startTime)); } -Profile::Profile(const String& title, unsigned uid) +Profile::Profile(const String& title, unsigned uid, double startTime) : 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); + m_rootNode = ProfileNode::create(nullptr, CallIdentifier(ASCIILiteral("Thread_1"), String(), 0, 0), nullptr); + m_rootNode->appendCall(ProfileNode::Call(startTime)); } Profile::~Profile() { } -void Profile::forEach(void (ProfileNode::*function)()) -{ - ProfileNode* currentNode = m_head->firstChild(); - for (ProfileNode* nextNode = currentNode; nextNode; nextNode = nextNode->firstChild()) - currentNode = nextNode; - - if (!currentNode) - currentNode = m_head.get(); - - ProfileNode* endNode = m_head->traverseNextNodePostOrder(); - while (currentNode && currentNode != endNode) { - (currentNode->*function)(); - currentNode = currentNode->traverseNextNodePostOrder(); - } -} - -void Profile::focus(const ProfileNode* profileNode) -{ - if (!profileNode || !m_head) - return; - - bool processChildren; - const CallIdentifier& callIdentifier = profileNode->callIdentifier(); - for (ProfileNode* currentNode = m_head.get(); currentNode; currentNode = currentNode->traverseNextNodePreOrder(processChildren)) - processChildren = currentNode->focus(callIdentifier); - - // Set the visible time of all nodes so that the %s display correctly. - forEach(&ProfileNode::calculateVisibleTotalTime); -} - -void Profile::exclude(const ProfileNode* profileNode) -{ - if (!profileNode || !m_head) - return; - - const CallIdentifier& callIdentifier = profileNode->callIdentifier(); - - for (ProfileNode* currentNode = m_head.get(); currentNode; currentNode = currentNode->traverseNextNodePreOrder()) - currentNode->exclude(callIdentifier); - - // Set the visible time of the head so the %s display correctly. - m_head->setVisibleTotalTime(m_head->totalTime() - m_head->selfTime()); - m_head->setVisibleSelfTime(0.0); -} - -void Profile::restoreAll() -{ - forEach(&ProfileNode::restore); -} - #ifndef NDEBUG -void Profile::debugPrintData() const +void Profile::debugPrint() { + CalculateProfileSubtreeDataFunctor functor; + m_rootNode->forEachNodePostorder(functor); + ProfileNode::ProfileSubtreeData data = functor.returnValue(); + dataLogF("Call graph:\n"); - m_head->debugPrintData(0); + m_rootNode->debugPrintRecursively(0, data); } typedef WTF::KeyValuePair<FunctionCallHashCount::ValueType, unsigned> NameCountPair; @@ -114,13 +68,17 @@ static inline bool functionNameCountPairComparator(const NameCountPair& a, const return a.value > b.value; } -void Profile::debugPrintDataSampleStyle() const +void Profile::debugPrintSampleStyle() { typedef Vector<NameCountPair> NameCountPairVector; + CalculateProfileSubtreeDataFunctor functor; + m_rootNode->forEachNodePostorder(functor); + ProfileNode::ProfileSubtreeData data = functor.returnValue(); + FunctionCallHashCount countedFunctions; dataLogF("Call graph:\n"); - m_head->debugPrintDataSampleStyle(0, countedFunctions); + m_rootNode->debugPrintSampleStyleRecursively(0, countedFunctions, data); 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 c1c69193c..41cb670ca 100644 --- a/Source/JavaScriptCore/profiler/Profile.h +++ b/Source/JavaScriptCore/profiler/Profile.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008, 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 @@ -33,39 +33,33 @@ namespace JSC { - class Profile : public RefCounted<Profile> { - public: - static PassRefPtr<Profile> create(const String& title, unsigned uid); - virtual ~Profile(); +class JS_EXPORT_PRIVATE Profile : public RefCounted<Profile> { +public: + static Ref<Profile> create(const String& title, unsigned uid, double); + virtual ~Profile(); - 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; } + const String& title() const { return m_title; } + unsigned uid() const { return m_uid; } - JS_EXPORT_PRIVATE void forEach(void (ProfileNode::*)()); - - JS_EXPORT_PRIVATE void focus(const ProfileNode*); - JS_EXPORT_PRIVATE void exclude(const ProfileNode*); - JS_EXPORT_PRIVATE void restoreAll(); + ProfileNode* rootNode() const { return m_rootNode.get(); } + void setRootNode(PassRefPtr<ProfileNode> rootNode) { m_rootNode = rootNode; } #ifndef NDEBUG - void debugPrintData() const; - void debugPrintDataSampleStyle() const; + void debugPrint(); + void debugPrintSampleStyle(); #endif - protected: - Profile(const String& title, unsigned uid); +protected: + Profile(const String& title, unsigned uid, double startTime); - private: - void removeProfileStart(); - void removeProfileEnd(); - - String m_title; - RefPtr<ProfileNode> m_head; - unsigned int m_uid; - }; +private: + void removeProfileStart(); + void removeProfileEnd(); + + String m_title; + RefPtr<ProfileNode> m_rootNode; + unsigned m_uid; +}; } // namespace JSC diff --git a/Source/JavaScriptCore/profiler/ProfileGenerator.cpp b/Source/JavaScriptCore/profiler/ProfileGenerator.cpp index d240aff34..f70e4a3f6 100644 --- a/Source/JavaScriptCore/profiler/ProfileGenerator.cpp +++ b/Source/JavaScriptCore/profiler/ProfileGenerator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008, 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 @@ -31,41 +31,80 @@ #include "JSGlobalObject.h" #include "JSStringRef.h" #include "JSFunction.h" -#include "Interpreter.h" #include "LegacyProfiler.h" -#include "Operations.h" +#include "JSCInlines.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) +Ref<ProfileGenerator> ProfileGenerator::create(ExecState* exec, const String& title, unsigned uid, PassRefPtr<Stopwatch> stopwatch) { - return adoptRef(new ProfileGenerator(exec, title, uid)); + return adoptRef(*new ProfileGenerator(exec, title, uid, stopwatch)); } -ProfileGenerator::ProfileGenerator(ExecState* exec, const String& title, unsigned uid) - : m_origin(exec ? exec->lexicalGlobalObject() : 0) +ProfileGenerator::ProfileGenerator(ExecState* exec, const String& title, unsigned uid, PassRefPtr<Stopwatch> stopwatch) + : m_origin(exec ? exec->lexicalGlobalObject() : nullptr) , m_profileGroup(exec ? exec->lexicalGlobalObject()->profileGroup() : 0) + , m_stopwatch(stopwatch) + , m_foundConsoleStartParent(false) + , m_suspended(false) { - m_profile = Profile::create(title, uid); - m_currentNode = m_head = m_profile->head(); + double startTime = m_stopwatch->elapsedTime(); + m_profile = Profile::create(title, uid, startTime); + m_currentNode = m_rootNode = m_profile->rootNode(); if (exec) - addParentForConsoleStart(exec); + addParentForConsoleStart(exec, startTime); } -void ProfileGenerator::addParentForConsoleStart(ExecState* exec) +class AddParentForConsoleStartFunctor { +public: + AddParentForConsoleStartFunctor(ExecState* exec, RefPtr<ProfileNode>& rootNode, RefPtr<ProfileNode>& currentNode, double startTime) + : m_exec(exec) + , m_hasSkippedFirstFrame(false) + , m_foundParent(false) + , m_rootNode(rootNode) + , m_currentNode(currentNode) + , m_startTime(startTime) + { + } + + bool foundParent() const { return m_foundParent; } + + StackVisitor::Status operator()(StackVisitor& visitor) + { + if (!m_hasSkippedFirstFrame) { + m_hasSkippedFirstFrame = true; + return StackVisitor::Continue; + } + + 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()); + + m_foundParent = true; + return StackVisitor::Done; + } + +private: + ExecState* m_exec; + bool m_hasSkippedFirstFrame; + bool m_foundParent; + RefPtr<ProfileNode>& m_rootNode; + RefPtr<ProfileNode>& m_currentNode; + double m_startTime; +}; + +void ProfileGenerator::addParentForConsoleStart(ExecState* exec, double startTime) { - int lineNumber; - intptr_t sourceID; - String sourceURL; - JSValue function; - - exec->interpreter()->retrieveLastCaller(exec, lineNumber, sourceID, sourceURL, function); - m_currentNode = ProfileNode::create(exec, LegacyProfiler::createCallIdentifier(exec, function ? function.toThisObject(exec) : 0, sourceURL, lineNumber), m_head.get(), m_head.get()); - m_head->insertNode(m_currentNode.get()); + AddParentForConsoleStartFunctor functor(exec, m_rootNode, m_currentNode, startTime); + exec->iterate(functor); + + m_foundConsoleStartParent = functor.foundParent(); } const String& ProfileGenerator::title() const @@ -73,46 +112,92 @@ 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.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); + 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()); } if (!m_origin) return; - ASSERT(m_currentNode); - m_currentNode = m_currentNode->willExecute(callerCallFrame, callIdentifier); + 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()); } 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); + 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()); } 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> returningNode = ProfileNode::create(callerCallFrame, callIdentifier, m_head.get(), m_currentNode.get()); - returningNode->setStartTime(m_currentNode->startTime()); - returningNode->didExecute(); - m_currentNode->insertNode(returningNode.release()); + 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()); return; } - m_currentNode = m_currentNode->didExecute(); + endCallEntry(m_currentNode.get()); + m_currentNode = m_currentNode->parent(); } 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); @@ -124,57 +209,44 @@ void ProfileGenerator::exceptionUnwind(ExecState* handlerCallFrame, const CallId void ProfileGenerator::stopProfiling() { - m_profile->forEach(&ProfileNode::stopProfiling); + for (ProfileNode* node = m_currentNode.get(); node != m_profile->rootNode(); node = node->parent()) + endCallEntry(node); - removeProfileStart(); - removeProfileEnd(); + if (m_foundConsoleStartParent) { + 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); - idleNode->setVisible(true); - - m_head->setSelfTime(0.0); - m_head->addChild(idleNode.release()); - } } -// The console.ProfileGenerator that started this ProfileGenerator will be the first child. +// 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()) + ProfileNode* currentNode = nullptr; + for (ProfileNode* next = m_rootNode.get(); next; next = next->firstChild()) currentNode = next; - if (currentNode->callIdentifier().m_name != "profile") + if (currentNode->callIdentifier().functionName() != "profile") return; - // Attribute the time of the node aobut to be removed to the self time of its parent - currentNode->parent()->setSelfTime(currentNode->parent()->selfTime() + currentNode->totalTime()); currentNode->parent()->removeChild(currentNode); } -// The console.ProfileGeneratorEnd that stopped this ProfileGenerator will be the last child. +// 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()) + ProfileNode* currentNode = nullptr; + for (ProfileNode* next = m_rootNode.get(); next; next = next->lastChild()) currentNode = next; - if (currentNode->callIdentifier().m_name != "profileEnd") + if (currentNode->callIdentifier().functionName() != "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 40cc8de01..387ed5f4a 100644 --- a/Source/JavaScriptCore/profiler/ProfileGenerator.h +++ b/Source/JavaScriptCore/profiler/ProfileGenerator.h @@ -22,26 +22,28 @@ * (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 PassRefPtr<ProfileGenerator> create(ExecState*, const WTF::String& title, unsigned uid); + static Ref<ProfileGenerator> create(ExecState*, const WTF::String& title, unsigned uid, PassRefPtr<Stopwatch>); // Members const WTF::String& title() const; @@ -49,29 +51,32 @@ 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&); - // Stopping Profiling - void stopProfiling(); + void setIsSuspended(bool suspended) { ASSERT(m_suspended != suspended); m_suspended = suspended; } - typedef void (ProfileGenerator::*ProfileFunction)(ExecState* callerOrHandlerCallFrame, const CallIdentifier& callIdentifier); + void stopProfiling(); private: - ProfileGenerator(ExecState*, const WTF::String& title, unsigned uid); - void addParentForConsoleStart(ExecState*); + ProfileGenerator(ExecState*, const WTF::String& title, unsigned uid, PassRefPtr<Stopwatch>); + void addParentForConsoleStart(ExecState*, double); void removeProfileStart(); void removeProfileEnd(); + void beginCallEntry(ProfileNode*, double startTime); + void endCallEntry(ProfileNode*); + RefPtr<Profile> m_profile; JSGlobalObject* m_origin; unsigned m_profileGroup; - RefPtr<ProfileNode> m_head; + RefPtr<Stopwatch> m_stopwatch; + RefPtr<ProfileNode> m_rootNode; 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 5b6a25411..9bcf37586 100644 --- a/Source/JavaScriptCore/profiler/ProfileNode.cpp +++ b/Source/JavaScriptCore/profiler/ProfileNode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 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 @@ -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 Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple 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. * @@ -30,126 +30,63 @@ #include "ProfileNode.h" #include "LegacyProfiler.h" -#include <stdio.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) +ProfileNode::ProfileNode(ExecState* callerCallFrame, const CallIdentifier& callIdentifier, ProfileNode* parentNode) : m_callerCallFrame(callerCallFrame) , m_callIdentifier(callIdentifier) - , m_head(headNode) , m_parent(parentNode) - , m_nextSibling(0) - , m_startTime(0.0) - , m_actualTotalTime(0.0) - , m_visibleTotalTime(0.0) - , m_actualSelfTime(0.0) - , m_visibleSelfTime(0.0) - , m_numberOfCalls(0) - , m_visible(true) +#ifndef NDEBUG + , m_nextSibling(nullptr) +#endif { - startTimer(); } -ProfileNode::ProfileNode(ExecState* callerCallFrame, ProfileNode* headNode, ProfileNode* nodeToCopy) +ProfileNode::ProfileNode(ExecState* callerCallFrame, ProfileNode* nodeToCopy) : m_callerCallFrame(callerCallFrame) , m_callIdentifier(nodeToCopy->callIdentifier()) - , m_head(headNode) , m_parent(nodeToCopy->parent()) - , m_nextSibling(0) - , m_startTime(0.0) - , m_actualTotalTime(nodeToCopy->actualTotalTime()) - , m_visibleTotalTime(nodeToCopy->totalTime()) - , m_actualSelfTime(nodeToCopy->actualSelfTime()) - , m_visibleSelfTime(nodeToCopy->selfTime()) - , m_numberOfCalls(nodeToCopy->numberOfCalls()) - , m_visible(nodeToCopy->visible()) -{ -} - -ProfileNode* ProfileNode::willExecute(ExecState* callerCallFrame, const CallIdentifier& callIdentifier) -{ - for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild) { - if ((*currentChild)->callIdentifier() == callIdentifier) { - (*currentChild)->startTimer(); - return (*currentChild).get(); - } - } - - RefPtr<ProfileNode> newChild = ProfileNode::create(callerCallFrame, callIdentifier, m_head ? m_head : this, this); // If this ProfileNode has no head it is the head. - if (m_children.size()) - m_children.last()->setNextSibling(newChild.get()); - m_children.append(newChild.release()); - return m_children.last().get(); -} - -ProfileNode* ProfileNode::didExecute() + , m_calls(nodeToCopy->calls()) +#ifndef NDEBUG + , m_nextSibling(nullptr) +#endif { - 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()); } -ProfileNode* ProfileNode::findChild(ProfileNode* node) const -{ - if (!node) - return 0; - - for (size_t i = 0; i < m_children.size(); ++i) { - if (*node == m_children[i].get()) - return m_children[i].get(); - } - - return 0; -} - void ProfileNode::removeChild(ProfileNode* node) { if (!node) return; - for (size_t i = 0; i < m_children.size(); ++i) { - if (*node == m_children[i].get()) { - m_children.remove(i); - break; - } - } - - resetChildrensSiblings(); + 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 } -void ProfileNode::insertNode(PassRefPtr<ProfileNode> prpNode) +void ProfileNode::spliceNode(PassRefPtr<ProfileNode> prpNode) { RefPtr<ProfileNode> node = prpNode; @@ -160,24 +97,7 @@ void ProfileNode::insertNode(PassRefPtr<ProfileNode> prpNode) m_children.append(node.release()); } -void ProfileNode::stopProfiling() -{ - if (m_startTime) - endAndRecordCall(); - - m_visibleTotalTime = m_actualTotalTime; - - ASSERT(m_actualSelfTime == 0.0 && m_startTime == 0.0); - - // Because we iterate in post order all of our children have been stopped before us. - for (unsigned i = 0; i < m_children.size(); ++i) - m_actualSelfTime += m_children[i]->totalTime(); - - ASSERT(m_actualSelfTime <= m_actualTotalTime); - m_actualSelfTime = m_actualTotalTime - m_actualSelfTime; - m_visibleSelfTime = m_actualSelfTime; -} - +#ifndef NDEBUG ProfileNode* ProfileNode::traverseNextNodePostOrder() const { ProfileNode* next = m_nextSibling; @@ -188,136 +108,63 @@ ProfileNode* ProfileNode::traverseNextNodePostOrder() const return next; } -ProfileNode* ProfileNode::traverseNextNodePreOrder(bool processChildren) const +void ProfileNode::debugPrint() { - if (processChildren && m_children.size()) - return m_children[0].get(); + CalculateProfileSubtreeDataFunctor functor; + forEachNodePostorder(functor); + ProfileNode::ProfileSubtreeData data = functor.returnValue(); - if (m_nextSibling) - return m_nextSibling; - - ProfileNode* nextParent = m_parent; - if (!nextParent) - return 0; - - ProfileNode* next; - for (next = m_parent->nextSibling(); !next; next = nextParent->nextSibling()) { - nextParent = nextParent->parent(); - if (!nextParent) - return 0; - } - - return next; -} - -void ProfileNode::setTreeVisible(ProfileNode* node, bool visible) -{ - ProfileNode* nodeParent = node->parent(); - ProfileNode* nodeSibling = node->nextSibling(); - node->setParent(0); - node->setNextSibling(0); - - for (ProfileNode* currentNode = node; currentNode; currentNode = currentNode->traverseNextNodePreOrder()) - currentNode->setVisible(visible); - - node->setParent(nodeParent); - node->setNextSibling(nodeSibling); -} - -void ProfileNode::calculateVisibleTotalTime() -{ - double sumOfVisibleChildrensTime = 0.0; - - for (unsigned i = 0; i < m_children.size(); ++i) { - if (m_children[i]->visible()) - sumOfVisibleChildrensTime += m_children[i]->totalTime(); - } - - m_visibleTotalTime = m_visibleSelfTime + sumOfVisibleChildrensTime; -} - -bool ProfileNode::focus(const CallIdentifier& callIdentifier) -{ - if (!m_visible) - return false; - - if (m_callIdentifier != callIdentifier) { - m_visible = false; - return true; - } - - for (ProfileNode* currentParent = m_parent; currentParent; currentParent = currentParent->parent()) - currentParent->setVisible(true); - - return false; -} - -void ProfileNode::exclude(const CallIdentifier& callIdentifier) -{ - if (m_visible && m_callIdentifier == callIdentifier) { - setTreeVisible(this, false); - - m_parent->setVisibleSelfTime(m_parent->selfTime() + m_visibleTotalTime); - } -} - -void ProfileNode::restore() -{ - m_visibleTotalTime = m_actualTotalTime; - m_visibleSelfTime = m_actualSelfTime; - m_visible = true; + debugPrintRecursively(0, data); } -void ProfileNode::endAndRecordCall() +void ProfileNode::debugPrintSampleStyle() { - m_actualTotalTime += m_startTime ? getCount() - m_startTime : 0.0; - m_startTime = 0.0; - - ++m_numberOfCalls; -} + FunctionCallHashCount countedFunctions; -void ProfileNode::startTimer() -{ - if (!m_startTime) - m_startTime = getCount(); -} + CalculateProfileSubtreeDataFunctor functor; + forEachNodePostorder(functor); + ProfileNode::ProfileSubtreeData data = functor.returnValue(); -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()); + debugPrintSampleStyleRecursively(0, countedFunctions, data); } -#ifndef NDEBUG -void ProfileNode::debugPrintData(int indentLevel) const +void ProfileNode::debugPrintRecursively(int indentLevel, const ProfileSubtreeData& data) { // Print function names for (int i = 0; i < indentLevel; ++i) dataLogF(" "); - dataLogF("Function Name %s %d SelfTime %.3fms/%.3f%% TotalTime %.3fms/%.3f%% VSelf %.3fms VTotal %.3fms Visible %s Next Sibling %s\n", - functionName().utf8().data(), - m_numberOfCalls, m_actualSelfTime, selfPercent(), m_actualTotalTime, totalPercent(), - m_visibleSelfTime, m_visibleTotalTime, - (m_visible ? "True" : "False"), + 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, 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); + (*currentChild)->debugPrintRecursively(indentLevel, data); } // print the profiled data in a format that matches the tool sample's output. -double ProfileNode::debugPrintDataSampleStyle(int indentLevel, FunctionCallHashCount& countedFunctions) const +double ProfileNode::debugPrintSampleStyleRecursively(int indentLevel, FunctionCallHashCount& countedFunctions, const ProfileSubtreeData& data) { 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 = m_actualTotalTime * 1000; + double sampleCount = nodeTotalTime * 1000; if (indentLevel) { for (int i = 0; i < indentLevel; ++i) dataLogF(" "); @@ -333,7 +180,7 @@ double ProfileNode::debugPrintDataSampleStyle(int indentLevel, FunctionCallHashC // 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 += (*currentChild)->debugPrintSampleStyleRecursively(indentLevel, countedFunctions, data); sumOfChildrensCount *= 1000; // // Print remainder of samples to match sample's output @@ -345,7 +192,7 @@ double ProfileNode::debugPrintDataSampleStyle(int indentLevel, FunctionCallHashC dataLogF("%.0f %s\n", sampleCount - sumOfChildrensCount, functionName().utf8().data()); } - return m_actualTotalTime; + return nodeTotalTime; } #endif diff --git a/Source/JavaScriptCore/profiler/ProfileNode.h b/Source/JavaScriptCore/profiler/ProfileNode.h index f5fef86f8..7ad149e17 100644 --- a/Source/JavaScriptCore/profiler/ProfileNode.h +++ b/Source/JavaScriptCore/profiler/ProfileNode.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 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 @@ -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 Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple 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. * @@ -40,133 +40,154 @@ namespace JSC { class ExecState; class ProfileNode; - typedef Vector<RefPtr<ProfileNode> >::const_iterator StackIterator; typedef HashCountedSet<StringImpl*> FunctionCallHashCount; class ProfileNode : public RefCounted<ProfileNode> { public: - static PassRefPtr<ProfileNode> create(ExecState* callerCallFrame, const CallIdentifier& callIdentifier, ProfileNode* headNode, ProfileNode* parentNode) + static Ref<ProfileNode> create(ExecState* callerCallFrame, const CallIdentifier& callIdentifier, ProfileNode* parentNode) { - return adoptRef(new ProfileNode(callerCallFrame, callIdentifier, headNode, parentNode)); + return adoptRef(*new ProfileNode(callerCallFrame, callIdentifier, parentNode)); } - static PassRefPtr<ProfileNode> create(ExecState* callerCallFrame, ProfileNode* headNode, ProfileNode* node) + + static Ref<ProfileNode> create(ExecState* callerCallFrame, ProfileNode* node) { - return adoptRef(new ProfileNode(callerCallFrame, headNode, node)); + return adoptRef(*new ProfileNode(callerCallFrame, node)); } - bool operator==(ProfileNode* node) { return m_callIdentifier == node->callIdentifier(); } - - ProfileNode* willExecute(ExecState* callerCallFrame, const CallIdentifier&); - ProfileNode* didExecute(); + 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; + }; - void stopProfiling(); + bool operator==(ProfileNode* node) { return m_callIdentifier == node->callIdentifier(); } - // 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; } + 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(); } + ProfileNode* parent() const { return m_parent; } void setParent(ProfileNode* parent) { m_parent = parent; } - ProfileNode* nextSibling() const { return m_nextSibling; } - void setNextSibling(ProfileNode* nextSibling) { m_nextSibling = nextSibling; } - // Time members - double startTime() const { return m_startTime; } - void setStartTime(double startTime) { m_startTime = startTime; } - double totalTime() const { return m_visibleTotalTime; } - double actualTotalTime() const { return m_actualTotalTime; } - void setTotalTime(double time) { m_actualTotalTime = time; m_visibleTotalTime = time; } - void setActualTotalTime(double time) { m_actualTotalTime = time; } - void setVisibleTotalTime(double time) { m_visibleTotalTime = time; } - double selfTime() const { return m_visibleSelfTime; } - double actualSelfTime() const { return m_actualSelfTime; } - void setSelfTime(double time) {m_actualSelfTime = time; m_visibleSelfTime = time; } - void setActualSelfTime(double time) { m_actualSelfTime = time; } - void setVisibleSelfTime(double time) { m_visibleSelfTime = time; } - - double totalPercent() const { return (m_visibleTotalTime / (m_head ? m_head->totalTime() : totalTime())) * 100.0; } - double selfPercent() const { return (m_visibleSelfTime / (m_head ? m_head->totalTime() : totalTime())) * 100.0; } - - unsigned numberOfCalls() const { return m_numberOfCalls; } - void setNumberOfCalls(unsigned number) { m_numberOfCalls = number; } - - // Children members - const Vector<RefPtr<ProfileNode> >& children() const { return m_children; } - ProfileNode* firstChild() const { return m_children.size() ? m_children.first().get() : 0; } - ProfileNode* lastChild() const { return m_children.size() ? m_children.last().get() : 0; } - ProfileNode* findChild(ProfileNode*) const; - void removeChild(ProfileNode*); - void addChild(PassRefPtr<ProfileNode> prpChild); - void insertNode(PassRefPtr<ProfileNode> prpNode); + 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); } - // Visiblity - bool visible() const { return m_visible; } - void setVisible(bool visible) { m_visible = visible; } + 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; } - static void setTreeVisible(ProfileNode*, bool visible); + 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>); - // Sorting - ProfileNode* traverseNextNodePostOrder() const; - ProfileNode* traverseNextNodePreOrder(bool processChildren = true) const; +#ifndef NDEBUG + struct ProfileSubtreeData { + HashMap<ProfileNode*, std::pair<double, double>> selfAndTotalTimes; + double rootTotalTime; + }; - // Views - void calculateVisibleTotalTime(); - bool focus(const CallIdentifier&); - void exclude(const CallIdentifier&); - void restore(); + // Use these functions to dump the subtree rooted at this node. + void debugPrint(); + void debugPrintSampleStyle(); - void endAndRecordCall(); + // These are used to recursively print entire subtrees using precomputed self and total times. + template <typename Functor> void forEachNodePostorder(Functor&); -#ifndef NDEBUG - const char* c_str() const { return m_callIdentifier; } - void debugPrintData(int indentLevel) const; - double debugPrintDataSampleStyle(int indentLevel, FunctionCallHashCount&) const; + void debugPrintRecursively(int indentLevel, const ProfileSubtreeData&); + double debugPrintSampleStyleRecursively(int indentLevel, FunctionCallHashCount&, const ProfileSubtreeData&); #endif private: - ProfileNode(ExecState* callerCallFrame, const CallIdentifier&, ProfileNode* headNode, ProfileNode* parentNode); - ProfileNode(ExecState* callerCallFrame, ProfileNode* headNode, ProfileNode* nodeToCopy); + typedef Vector<RefPtr<ProfileNode>>::const_iterator StackIterator; - void startTimer(); - void resetChildrensSiblings(); + ProfileNode(ExecState* callerCallFrame, const CallIdentifier&, ProfileNode* parentNode); + ProfileNode(ExecState* callerCallFrame, ProfileNode* nodeToCopy); - RefPtr<ProfileNode>* childrenBegin() { return m_children.begin(); } - RefPtr<ProfileNode>* childrenEnd() { return m_children.end(); } +#ifndef NDEBUG + ProfileNode* nextSibling() const { return m_nextSibling; } + void setNextSibling(ProfileNode* nextSibling) { m_nextSibling = nextSibling; } - // Sorting comparators - static inline bool totalTimeDescendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b) { return a->totalTime() > b->totalTime(); } - static inline bool totalTimeAscendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b) { return a->totalTime() < b->totalTime(); } - static inline bool selfTimeDescendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b) { return a->selfTime() > b->selfTime(); } - static inline bool selfTimeAscendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b) { return a->selfTime() < b->selfTime(); } - static inline bool callsDescendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b) { return a->numberOfCalls() > b->numberOfCalls(); } - static inline bool callsAscendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b) { return a->numberOfCalls() < b->numberOfCalls(); } - static inline bool functionNameDescendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b) { return codePointCompareLessThan(b->functionName(), a->functionName()); } - static inline bool functionNameAscendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b) { return codePointCompareLessThan(a->functionName(), b->functionName()); } + ProfileNode* traverseNextNodePostOrder() const; +#endif 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 + }; - double m_startTime; - double m_actualTotalTime; - double m_visibleTotalTime; - double m_actualSelfTime; - double m_visibleSelfTime; - unsigned m_numberOfCalls; +#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(); + } - bool m_visible; + functor(endNode); + } - Vector<RefPtr<ProfileNode> > m_children; + 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 WTFMove(m_data); } + + ProfileNode::ProfileSubtreeData m_data; }; +#endif } // namespace JSC diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecode.cpp b/Source/JavaScriptCore/profiler/ProfilerBytecode.cpp index ca602e42f..6eeeb27b9 100644 --- a/Source/JavaScriptCore/profiler/ProfilerBytecode.cpp +++ b/Source/JavaScriptCore/profiler/ProfilerBytecode.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/ProfilerBytecodeSequence.cpp b/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp index a98b8bace..145ee44d1 100644 --- a/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp +++ b/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2013, 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 @@ -29,7 +29,7 @@ #include "CodeBlock.h" #include "JSGlobalObject.h" #include "Operands.h" -#include "Operations.h" +#include "JSCInlines.h" #include <wtf/StringPrintStream.h> namespace JSC { namespace Profiler { @@ -38,20 +38,22 @@ BytecodeSequence::BytecodeSequence(CodeBlock* codeBlock) { StringPrintStream out; -#if ENABLE(VALUE_PROFILER) for (unsigned i = 0; i < codeBlock->numberOfArgumentValueProfiles(); ++i) { - CString description = codeBlock->valueProfileForArgument(i)->briefDescription(); + ConcurrentJITLocker locker(codeBlock->m_lock); + CString description = codeBlock->valueProfileForArgument(i)->briefDescription(locker); if (!description.length()) continue; out.reset(); - out.print("arg", i, " (r", argumentToOperand(i), "): ", description); + out.print("arg", i, ": ", description); m_header.append(out.toCString()); } -#endif // ENABLE(VALUE_PROFILER) + + 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( diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp b/Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp index 3ae35dcc0..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 { @@ -56,8 +56,8 @@ JSValue Bytecodes::toJS(ExecState* exec) const JSObject* result = constructEmptyObject(exec); result->putDirect(exec->vm(), exec->propertyNames().bytecodesID, jsNumber(m_id)); - result->putDirect(exec->vm(), exec->propertyNames().inferredName, jsString(exec, m_inferredName)); - result->putDirect(exec->vm(), exec->propertyNames().sourceCode, jsString(exec, m_sourceCode)); + result->putDirect(exec->vm(), exec->propertyNames().inferredName, jsString(exec, String::fromUTF8(m_inferredName))); + result->putDirect(exec->vm(), exec->propertyNames().sourceCode, jsString(exec, String::fromUTF8(m_sourceCode))); result->putDirect(exec->vm(), exec->propertyNames().hash, jsString(exec, String::fromUTF8(toCString(m_hash)))); result->putDirect(exec->vm(), exec->propertyNames().instructionCount, jsNumber(m_instructionCount)); addSequenceProperties(exec, result); diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecodes.h b/Source/JavaScriptCore/profiler/ProfilerBytecodes.h index 47d856cb4..e44598019 100644 --- a/Source/JavaScriptCore/profiler/ProfilerBytecodes.h +++ b/Source/JavaScriptCore/profiler/ProfilerBytecodes.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 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 @@ -40,8 +40,8 @@ public: ~Bytecodes(); size_t id() const { return m_id; } - const String& inferredName() const { return m_inferredName; } - const String& sourceCode() const { return m_sourceCode; } + const CString& inferredName() const { return m_inferredName; } + const CString& sourceCode() const { return m_sourceCode; } unsigned instructionCount() const { return m_instructionCount; } CodeBlockHash hash() const { return m_hash; } @@ -51,8 +51,8 @@ public: private: size_t m_id; - String m_inferredName; - String m_sourceCode; + CString m_inferredName; + CString m_sourceCode; CodeBlockHash m_hash; unsigned m_instructionCount; }; diff --git a/Source/JavaScriptCore/profiler/ProfilerCompilation.cpp b/Source/JavaScriptCore/profiler/ProfilerCompilation.cpp index f82414ffa..488f563de 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, 2013, 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 @@ -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,6 +38,7 @@ 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) @@ -67,16 +69,18 @@ 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) { - HashMap<OriginStack, OwnPtr<ExecutionCounter> >::iterator iter = m_counters.find(origin); - if (iter != m_counters.end()) - return iter->value.get(); - - OwnPtr<ExecutionCounter> counter = adoptPtr(new ExecutionCounter()); - ExecutionCounter* result = counter.get(); - m_counters.add(origin, counter.release()); - return result; + std::unique_ptr<ExecutionCounter>& counter = m_counters.add(origin, nullptr).iterator->value; + if (!counter) + counter = std::make_unique<ExecutionCounter>(); + + return counter.get(); } void Compilation::addOSRExitSite(const Vector<const void*>& codeAddresses) @@ -90,6 +94,18 @@ 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); @@ -108,11 +124,10 @@ JSValue Compilation::toJS(ExecState* exec) const result->putDirect(exec->vm(), exec->propertyNames().descriptions, descriptions); JSArray* counters = constructEmptyArray(exec, 0); - HashMap<OriginStack, OwnPtr<ExecutionCounter> >::const_iterator end = m_counters.end(); - for (HashMap<OriginStack, OwnPtr<ExecutionCounter> >::const_iterator iter = m_counters.begin(); iter != end; ++iter) { + for (auto it = m_counters.begin(), end = m_counters.end(); it != end; ++it) { JSObject* counterEntry = constructEmptyObject(exec); - counterEntry->putDirect(exec->vm(), exec->propertyNames().origin, iter->key.toJS(exec)); - counterEntry->putDirect(exec->vm(), exec->propertyNames().executionCount, jsNumber(iter->value->count())); + counterEntry->putDirect(exec->vm(), exec->propertyNames().origin, it->key.toJS(exec)); + counterEntry->putDirect(exec->vm(), exec->propertyNames().executionCount, jsNumber(it->value->count())); counters->push(exec, counterEntry); } result->putDirect(exec->vm(), exec->propertyNames().counters, counters); @@ -130,6 +145,9 @@ 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 b3183fa02..b358b659c 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, 2013, 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 @@ -31,6 +31,7 @@ #include "ProfilerCompilationKind.h" #include "ProfilerCompiledBytecode.h" #include "ProfilerExecutionCounter.h" +#include "ProfilerJettisonReason.h" #include "ProfilerOSRExit.h" #include "ProfilerOSRExitSite.h" #include "ProfilerOriginStack.h" @@ -38,7 +39,11 @@ #include <wtf/RefCounted.h> #include <wtf/SegmentedVector.h> -namespace JSC { namespace Profiler { +namespace JSC { + +class FireDetail; + +namespace Profiler { class Bytecodes; class Database; @@ -63,18 +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*); + 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, OwnPtr<ExecutionCounter> > m_counters; + HashMap<OriginStack, std::unique_ptr<ExecutionCounter>> m_counters; Vector<OSRExitSite> m_osrExitSites; SegmentedVector<OSRExit> m_osrExits; unsigned m_numInlinedGetByIds; 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..575ec2947 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 @@ -31,7 +31,9 @@ namespace JSC { namespace Profiler { enum CompilationKind { LLInt, Baseline, - DFG + DFG, + FTL, + FTLForOSREntry }; } } // namespace JSC::Profiler 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/ProfilerDatabase.cpp b/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp index a2fffd955..fc952c0c2 100644 --- a/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp +++ b/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp @@ -29,21 +29,18 @@ #include "CodeBlock.h" #include "JSONObject.h" #include "ObjectConstructor.h" -#include "Operations.h" +#include "JSCInlines.h" namespace JSC { namespace Profiler { -#if COMPILER(MINGW) || COMPILER(MSVC7_OR_LOWER) || OS(WINCE) -static int databaseCounter; -#else -static volatile int databaseCounter; -#endif -static SpinLock registrationLock = SPINLOCK_INITIALIZER; -static int didRegisterAtExit; +static std::atomic<int> databaseCounter; + +static StaticLock registrationLock; +static std::atomic<int> didRegisterAtExit; static Database* firstDatabase; Database::Database(VM& vm) - : m_databaseID(atomicIncrement(&databaseCounter)) + : m_databaseID(++databaseCounter) , m_vm(vm) , m_shouldSaveAtExit(false) , m_nextRegisteredDatabase(0) @@ -60,6 +57,8 @@ Database::~Database() Bytecodes* Database::ensureBytecodesFor(CodeBlock* codeBlock) { + LockHolder locker(m_lock); + codeBlock = codeBlock->baselineVersion(); HashMap<CodeBlock*, Bytecodes*>::iterator iter = m_bytecodesMap.find(codeBlock); @@ -76,19 +75,16 @@ Bytecodes* Database::ensureBytecodesFor(CodeBlock* codeBlock) void Database::notifyDestruction(CodeBlock* codeBlock) { + LockHolder locker(m_lock); + m_bytecodesMap.remove(codeBlock); } -PassRefPtr<Compilation> Database::newCompilation(Bytecodes* bytecodes, CompilationKind kind) +void Database::addCompilation(PassRefPtr<Compilation> compilation) { - RefPtr<Compilation> compilation = adoptRef(new Compilation(bytecodes, kind)); + ASSERT(!isCompilationThread()); + m_compilations.append(compilation); - return compilation.release(); -} - -PassRefPtr<Compilation> Database::newCompilation(CodeBlock* codeBlock, CompilationKind kind) -{ - return newCompilation(ensureBytecodesFor(codeBlock), kind); } JSValue Database::toJS(ExecState* exec) const @@ -118,7 +114,7 @@ String Database::toJSON() const bool Database::save(const char* filename) const { - OwnPtr<FilePrintStream> out = FilePrintStream::open(filename, "w"); + auto out = FilePrintStream::open(filename, "w"); if (!out) return false; @@ -139,17 +135,17 @@ void Database::registerToSaveAtExit(const char* filename) void Database::addDatabaseToAtExit() { - if (atomicIncrement(&didRegisterAtExit) == 1) + 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; @@ -167,7 +163,7 @@ void Database::performAtExitSave() const 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 172c8eeac..9bb64cf49 100644 --- a/Source/JavaScriptCore/profiler/ProfilerDatabase.h +++ b/Source/JavaScriptCore/profiler/ProfilerDatabase.h @@ -30,11 +30,13 @@ #include "ProfilerBytecodes.h" #include "ProfilerCompilation.h" #include "ProfilerCompilationKind.h" -#include <wtf/FastAllocBase.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> namespace JSC { namespace Profiler { @@ -50,8 +52,7 @@ public: Bytecodes* ensureBytecodesFor(CodeBlock*); void notifyDestruction(CodeBlock*); - PassRefPtr<Compilation> newCompilation(CodeBlock*, CompilationKind); - PassRefPtr<Compilation> newCompilation(Bytecodes*, CompilationKind); + void addCompilation(PassRefPtr<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 @@ -70,7 +71,6 @@ public: void registerToSaveAtExit(const char* filename); private: - void addDatabaseToAtExit(); void removeDatabaseFromAtExit(); void performAtExitSave() const; @@ -81,10 +81,11 @@ private: VM& m_vm; SegmentedVector<Bytecodes> m_bytecodes; HashMap<CodeBlock*, Bytecodes*> m_bytecodesMap; - Vector<RefPtr<Compilation> > m_compilations; + Vector<RefPtr<Compilation>> m_compilations; bool m_shouldSaveAtExit; CString m_atExitSaveFilename; Database* m_nextRegisteredDatabase; + Lock m_lock; }; } } // namespace JSC::Profiler diff --git a/Source/JavaScriptCore/profiler/ProfilerExecutionCounter.h b/Source/JavaScriptCore/profiler/ProfilerExecutionCounter.h index 2884bc5dc..8989e38b5 100644 --- a/Source/JavaScriptCore/profiler/ProfilerExecutionCounter.h +++ b/Source/JavaScriptCore/profiler/ProfilerExecutionCounter.h @@ -26,7 +26,7 @@ #ifndef ProfilerExecutionCounter_h #define ProfilerExecutionCounter_h -#include <wtf/FastAllocBase.h> +#include <wtf/FastMalloc.h> #include <wtf/Noncopyable.h> namespace JSC { namespace Profiler { diff --git a/Source/JavaScriptCore/profiler/ProfilerJettisonReason.cpp b/Source/JavaScriptCore/profiler/ProfilerJettisonReason.cpp new file mode 100644 index 000000000..3068ff34c --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerJettisonReason.cpp @@ -0,0 +1,76 @@ +/* + * 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; + case JettisonDueToOldAge: + out.print("JettisonDueToOldAge"); + return; + } + RELEASE_ASSERT_NOT_REACHED(); +} + +} // namespace WTF + diff --git a/Source/JavaScriptCore/profiler/ProfilerJettisonReason.h b/Source/JavaScriptCore/profiler/ProfilerJettisonReason.h new file mode 100644 index 000000000..6a7932604 --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerJettisonReason.h @@ -0,0 +1,55 @@ +/* + * 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, + JettisonDueToOldAge +}; + +} } // 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 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/ProfilerOSRExitSite.cpp b/Source/JavaScriptCore/profiler/ProfilerOSRExitSite.cpp index d54f7a275..b17d57e52 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 "Operations.h" +#include "JSCInlines.h" #include <wtf/StringPrintStream.h> namespace JSC { namespace Profiler { 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/ProfilerOriginStack.cpp b/Source/JavaScriptCore/profiler/ProfilerOriginStack.cpp index 018ceeb8c..b8eecdd60 100644 --- a/Source/JavaScriptCore/profiler/ProfilerOriginStack.cpp +++ b/Source/JavaScriptCore/profiler/ProfilerOriginStack.cpp @@ -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)); } } 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 { |