diff options
| author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2015-10-15 09:45:50 +0000 |
|---|---|---|
| committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2015-10-15 09:45:50 +0000 |
| commit | e15dd966d523731101f70ccf768bba12435a0208 (patch) | |
| tree | ae9cb828a24ded2585a41af3f21411523b47897d /Source/JavaScriptCore/profiler | |
| download | WebKitGtk-tarball-e15dd966d523731101f70ccf768bba12435a0208.tar.gz | |
webkitgtk-2.10.2webkitgtk-2.10.2
Diffstat (limited to 'Source/JavaScriptCore/profiler')
36 files changed, 3330 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/profiler/CallIdentifier.h b/Source/JavaScriptCore/profiler/CallIdentifier.h new file mode 100644 index 000000000..691fc6250 --- /dev/null +++ b/Source/JavaScriptCore/profiler/CallIdentifier.h @@ -0,0 +1,112 @@ +/* + * 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef CallIdentifier_h +#define CallIdentifier_h + +#include <wtf/text/CString.h> +#include <wtf/text/StringHash.h> +#include <wtf/text/WTFString.h> + +namespace JSC { + + struct CallIdentifier { + WTF_MAKE_FAST_ALLOCATED; + public: + CallIdentifier() + : m_lineNumber(0) + , m_columnNumber(0) + { + } + + 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) + { + } + + 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[4] = { + key.m_functionName.impl()->hash(), + key.m_url.impl()->hash(), + key.m_lineNumber, + key.m_columnNumber + }; + return StringHasher::hashMemory<sizeof(hashCodes)>(hashCodes); + } + + static bool equal(const CallIdentifier& a, const CallIdentifier& b) { return a == b; } + static const bool safeToCompareToEmptyOrDeleted = true; + }; + + unsigned hash() const { return Hash::hash(*this); } + +#ifndef NDEBUG + operator const char*() const { return c_str(); } + const char* c_str() const { return m_functionName.utf8().data(); } +#endif + + private: + String m_functionName; + String m_url; + unsigned m_lineNumber; + unsigned m_columnNumber; + }; + +} // namespace JSC + +namespace WTF { + + template<> struct DefaultHash<JSC::CallIdentifier> { typedef JSC::CallIdentifier::Hash Hash; }; + + template<> struct HashTraits<JSC::CallIdentifier> : GenericHashTraits<JSC::CallIdentifier> { + static void constructDeletedValue(JSC::CallIdentifier& slot) + { + new (NotNull, &slot) JSC::CallIdentifier(String(), String(), std::numeric_limits<unsigned>::max(), 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(); + } + }; + +} // namespace WTF + +#endif // CallIdentifier_h diff --git a/Source/JavaScriptCore/profiler/LegacyProfiler.cpp b/Source/JavaScriptCore/profiler/LegacyProfiler.cpp new file mode 100644 index 000000000..787d362dc --- /dev/null +++ b/Source/JavaScriptCore/profiler/LegacyProfiler.cpp @@ -0,0 +1,208 @@ +/* + * 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 + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "LegacyProfiler.h" + +#include "CallFrame.h" +#include "CodeBlock.h" +#include "CommonIdentifiers.h" +#include "InternalFunction.h" +#include "JSFunction.h" +#include "JSGlobalObject.h" +#include "Nodes.h" +#include "JSCInlines.h" +#include "Profile.h" +#include "ProfileGenerator.h" +#include "ProfileNode.h" + +namespace JSC { + +static const char* GlobalCodeExecution = "(program)"; +static const char* AnonymousFunction = "(anonymous function)"; +static unsigned ProfilesUID = 0; + +static CallIdentifier createCallIdentifierFromFunctionImp(ExecState*, JSObject*, const String& defaultSourceURL, unsigned defaultLineNumber, unsigned defaultColumnNumber); + +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, PassRefPtr<Stopwatch> stopwatch) +{ + if (!exec) + return; + + // Check if we currently have a Profile for this global ExecState and title. + // If so return early and don't create a new Profile. + JSGlobalObject* origin = exec->lexicalGlobalObject(); + + for (size_t i = 0; i < m_currentProfiles.size(); ++i) { + ProfileGenerator* profileGenerator = m_currentProfiles[i].get(); + if (profileGenerator->origin() == origin && profileGenerator->title() == title) + return; + } + + exec->vm().setEnabledProfiler(this); + RefPtr<ProfileGenerator> profileGenerator = ProfileGenerator::create(exec, title, ++ProfilesUID, stopwatch); + m_currentProfiles.append(profileGenerator); +} + +RefPtr<Profile> LegacyProfiler::stopProfiling(ExecState* exec, const String& title) +{ + if (!exec) + return nullptr; + + JSGlobalObject* origin = exec->lexicalGlobalObject(); + for (ptrdiff_t i = m_currentProfiles.size() - 1; i >= 0; --i) { + ProfileGenerator* profileGenerator = m_currentProfiles[i].get(); + if (profileGenerator->origin() == origin && (title.isNull() || profileGenerator->title() == title)) { + profileGenerator->stopProfiling(); + RefPtr<Profile> returnProfile = profileGenerator->profile(); + + m_currentProfiles.remove(i); + if (!m_currentProfiles.size()) + exec->vm().setEnabledProfiler(nullptr); + + return returnProfile; + } + } + + return nullptr; +} + +void LegacyProfiler::stopProfiling(JSGlobalObject* origin) +{ + for (ptrdiff_t i = m_currentProfiles.size() - 1; i >= 0; --i) { + ProfileGenerator* profileGenerator = m_currentProfiles[i].get(); + if (profileGenerator->origin() == origin) { + profileGenerator->stopProfiling(); + m_currentProfiles.remove(i); + if (!m_currentProfiles.size()) + origin->vm().setEnabledProfiler(nullptr); + } + } +} + +static inline void callFunctionForProfilesWithGroup(std::function<void(ProfileGenerator*)> callback, const Vector<RefPtr<ProfileGenerator>>& profiles, unsigned targetProfileGroup) +{ + 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()); + + 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, unsigned startingLineNumber, unsigned startingColumnNumber) +{ + ASSERT(!m_currentProfiles.isEmpty()); + + CallIdentifier callIdentifier = createCallIdentifier(callerCallFrame, JSValue(), sourceURL, startingLineNumber, startingColumnNumber); + + 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()); + + 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, unsigned startingLineNumber, unsigned startingColumnNumber) +{ + 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()); +} + +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()); +} + +CallIdentifier LegacyProfiler::createCallIdentifier(ExecState* exec, JSValue functionValue, const String& defaultSourceURL, unsigned defaultLineNumber, unsigned defaultColumnNumber) +{ + if (!functionValue) + return CallIdentifier(ASCIILiteral(GlobalCodeExecution), defaultSourceURL, defaultLineNumber, defaultColumnNumber); + if (!functionValue.isObject()) + 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, unsigned defaultLineNumber, unsigned defaultColumnNumber) +{ + 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); +} + +} // namespace JSC diff --git a/Source/JavaScriptCore/profiler/LegacyProfiler.h b/Source/JavaScriptCore/profiler/LegacyProfiler.h new file mode 100644 index 000000000..af0ab41e2 --- /dev/null +++ b/Source/JavaScriptCore/profiler/LegacyProfiler.h @@ -0,0 +1,77 @@ +/* + * 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 + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LegacyProfiler_h +#define LegacyProfiler_h + +#include "Profile.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> +#include <wtf/Stopwatch.h> +#include <wtf/Vector.h> + +namespace JSC { + +class ExecState; +class JSGlobalObject; +class JSObject; +class JSValue; +class ProfileGenerator; +struct CallIdentifier; + +class LegacyProfiler { + WTF_MAKE_FAST_ALLOCATED; +public: + JS_EXPORT_PRIVATE static LegacyProfiler* profiler(); + static CallIdentifier createCallIdentifier(ExecState*, JSValue, const WTF::String& sourceURL, unsigned defaultLineNumber, unsigned defaultColumnNumber); + + 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, unsigned startingLineNumber, unsigned startingColumnNumber); + void didExecute(ExecState* callerCallFrame, JSValue function); + void didExecute(ExecState* callerCallFrame, const WTF::String& sourceURL, unsigned startingLineNumber, unsigned startingColumnNumber); + + void exceptionUnwind(ExecState* handlerCallFrame); + + const Vector<RefPtr<ProfileGenerator>>& currentProfiles() { return m_currentProfiles; }; + +private: + Vector<RefPtr<ProfileGenerator>> m_currentProfiles; + static LegacyProfiler* s_sharedLegacyProfiler; +}; + +} // namespace JSC + +#endif // LegacyProfiler_h diff --git a/Source/JavaScriptCore/profiler/Profile.cpp b/Source/JavaScriptCore/profiler/Profile.cpp new file mode 100644 index 000000000..f3d450ab2 --- /dev/null +++ b/Source/JavaScriptCore/profiler/Profile.cpp @@ -0,0 +1,95 @@ +/* + * 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Profile.h" + +#include "ProfileNode.h" +#include <wtf/DataLog.h> + +namespace JSC { + +Ref<Profile> Profile::create(const String& title, unsigned uid, double startTime) +{ + return adoptRef(*new Profile(title, uid, startTime)); +} + +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_rootNode = ProfileNode::create(nullptr, CallIdentifier(ASCIILiteral("Thread_1"), String(), 0, 0), nullptr); + m_rootNode->appendCall(ProfileNode::Call(startTime)); +} + +Profile::~Profile() +{ +} + +#ifndef NDEBUG +void Profile::debugPrint() +{ + CalculateProfileSubtreeDataFunctor functor; + m_rootNode->forEachNodePostorder(functor); + ProfileNode::ProfileSubtreeData data = functor.returnValue(); + + dataLogF("Call graph:\n"); + m_rootNode->debugPrintRecursively(0, data); +} + +typedef WTF::KeyValuePair<FunctionCallHashCount::ValueType, unsigned> NameCountPair; + +static inline bool functionNameCountPairComparator(const NameCountPair& a, const NameCountPair& b) +{ + return a.value > b.value; +} + +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_rootNode->debugPrintSampleStyleRecursively(0, countedFunctions, data); + + dataLogF("\nTotal number in stack:\n"); + NameCountPairVector sortedFunctions(countedFunctions.size()); + copyToVector(countedFunctions, sortedFunctions); + + std::sort(sortedFunctions.begin(), sortedFunctions.end(), functionNameCountPairComparator); + for (NameCountPairVector::iterator it = sortedFunctions.begin(); it != sortedFunctions.end(); ++it) + dataLogF(" %-12d%s\n", (*it).value, String((*it).key).utf8().data()); + + dataLogF("\nSort by top of stack, same collapsed (when >= 5):\n"); +} +#endif + +} // namespace JSC diff --git a/Source/JavaScriptCore/profiler/Profile.h b/Source/JavaScriptCore/profiler/Profile.h new file mode 100644 index 000000000..41cb670ca --- /dev/null +++ b/Source/JavaScriptCore/profiler/Profile.h @@ -0,0 +1,66 @@ +/* + * 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef Profile_h +#define Profile_h + +#include "ProfileNode.h" +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> +#include <wtf/text/WTFString.h> + +namespace JSC { + +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; } + unsigned uid() const { return m_uid; } + + ProfileNode* rootNode() const { return m_rootNode.get(); } + void setRootNode(PassRefPtr<ProfileNode> rootNode) { m_rootNode = rootNode; } + +#ifndef NDEBUG + void debugPrint(); + void debugPrintSampleStyle(); +#endif + +protected: + Profile(const String& title, unsigned uid, double startTime); + +private: + void removeProfileStart(); + void removeProfileEnd(); + + String m_title; + RefPtr<ProfileNode> m_rootNode; + unsigned m_uid; +}; + +} // namespace JSC + +#endif // Profile_h diff --git a/Source/JavaScriptCore/profiler/ProfileGenerator.cpp b/Source/JavaScriptCore/profiler/ProfileGenerator.cpp new file mode 100644 index 000000000..f70e4a3f6 --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfileGenerator.cpp @@ -0,0 +1,254 @@ +/* + * 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ProfileGenerator.h" + +#include "CallFrame.h" +#include "CodeBlock.h" +#include "JSGlobalObject.h" +#include "JSStringRef.h" +#include "JSFunction.h" +#include "LegacyProfiler.h" +#include "JSCInlines.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) +{ + return adoptRef(*new ProfileGenerator(exec, title, uid, stopwatch)); +} + +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) +{ + double startTime = m_stopwatch->elapsedTime(); + m_profile = Profile::create(title, uid, startTime); + m_currentNode = m_rootNode = m_profile->rootNode(); + if (exec) + addParentForConsoleStart(exec, startTime); +} + +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) +{ + AddParentForConsoleStartFunctor functor(exec, m_rootNode, m_currentNode, startTime); + exec->iterate(functor); + + m_foundConsoleStartParent = functor.foundParent(); +} + +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()); + } + + 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()); +} + +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()); + } + + 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()); + return; + } + + 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); + while (m_currentNode->callerCallFrame() >= handlerCallFrame) { + didExecute(m_currentNode->callerCallFrame(), m_currentNode->callIdentifier()); + ASSERT(m_currentNode); + } +} + +void ProfileGenerator::stopProfiling() +{ + for (ProfileNode* node = m_currentNode.get(); node != m_profile->rootNode(); node = node->parent()) + endCallEntry(node); + + 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(); +} + +// 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()) + currentNode = next; + + if (currentNode->callIdentifier().functionName() != "profile") + return; + + 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()) + currentNode = next; + + if (currentNode->callIdentifier().functionName() != "profileEnd") + return; + + ASSERT(currentNode->callIdentifier() == (currentNode->parent()->children()[currentNode->parent()->children().size() - 1])->callIdentifier()); + currentNode->parent()->removeChild(currentNode); +} + +} // namespace JSC diff --git a/Source/JavaScriptCore/profiler/ProfileGenerator.h b/Source/JavaScriptCore/profiler/ProfileGenerator.h new file mode 100644 index 000000000..387ed5f4a --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfileGenerator.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ProfileGenerator_h +#define ProfileGenerator_h + +#include <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; + + class ProfileGenerator : public RefCounted<ProfileGenerator> { + public: + static Ref<ProfileGenerator> create(ExecState*, const WTF::String& title, unsigned uid, PassRefPtr<Stopwatch>); + + // Members + const WTF::String& title() const; + PassRefPtr<Profile> profile() const { return m_profile; } + JSGlobalObject* origin() const { return m_origin; } + unsigned profileGroup() const { return m_profileGroup; } + + 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 stopProfiling(); + + private: + 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<Stopwatch> m_stopwatch; + RefPtr<ProfileNode> m_rootNode; + RefPtr<ProfileNode> m_currentNode; + bool m_foundConsoleStartParent; + bool m_suspended; + }; + +} // namespace JSC + +#endif // ProfileGenerator_h diff --git a/Source/JavaScriptCore/profiler/ProfileNode.cpp b/Source/JavaScriptCore/profiler/ProfileNode.cpp new file mode 100644 index 000000000..9bcf37586 --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfileNode.cpp @@ -0,0 +1,199 @@ +/* + * 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 + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ProfileNode.h" + +#include "LegacyProfiler.h" +#include <wtf/DateMath.h> +#include <wtf/DataLog.h> +#include <wtf/text/StringHash.h> + +using namespace WTF; + +namespace JSC { + +ProfileNode::ProfileNode(ExecState* callerCallFrame, const CallIdentifier& callIdentifier, ProfileNode* parentNode) + : m_callerCallFrame(callerCallFrame) + , m_callIdentifier(callIdentifier) + , m_parent(parentNode) +#ifndef NDEBUG + , m_nextSibling(nullptr) +#endif +{ +} + +ProfileNode::ProfileNode(ExecState* callerCallFrame, ProfileNode* nodeToCopy) + : m_callerCallFrame(callerCallFrame) + , m_callIdentifier(nodeToCopy->callIdentifier()) + , m_parent(nodeToCopy->parent()) + , m_calls(nodeToCopy->calls()) +#ifndef NDEBUG + , m_nextSibling(nullptr) +#endif +{ +} + +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()); +} + +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 +} + +void ProfileNode::spliceNode(PassRefPtr<ProfileNode> prpNode) +{ + RefPtr<ProfileNode> node = prpNode; + + for (unsigned i = 0; i < m_children.size(); ++i) + node->addChild(m_children[i].release()); + + m_children.clear(); + m_children.append(node.release()); +} + +#ifndef NDEBUG +ProfileNode* ProfileNode::traverseNextNodePostOrder() const +{ + ProfileNode* next = m_nextSibling; + if (!next) + return m_parent; + while (ProfileNode* firstChild = next->firstChild()) + next = firstChild; + return next; +} + +void ProfileNode::debugPrint() +{ + CalculateProfileSubtreeDataFunctor functor; + forEachNodePostorder(functor); + ProfileNode::ProfileSubtreeData data = functor.returnValue(); + + debugPrintRecursively(0, data); +} + +void ProfileNode::debugPrintSampleStyle() +{ + FunctionCallHashCount countedFunctions; + + CalculateProfileSubtreeDataFunctor functor; + forEachNodePostorder(functor); + ProfileNode::ProfileSubtreeData data = functor.returnValue(); + + debugPrintSampleStyleRecursively(0, countedFunctions, data); +} + +void ProfileNode::debugPrintRecursively(int indentLevel, const ProfileSubtreeData& data) +{ + // 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, + 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); +} + +// print the profiled data in a format that matches the tool sample's output. +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 = nodeTotalTime * 1000; + if (indentLevel) { + for (int i = 0; i < indentLevel; ++i) + dataLogF(" "); + + countedFunctions.add(functionName().impl()); + + dataLogF("%.0f %s\n", sampleCount ? sampleCount : 1, name); + } else + dataLogF("%s\n", name); + + ++indentLevel; + + // Print children's names and information + double sumOfChildrensCount = 0.0; + for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild) + sumOfChildrensCount += (*currentChild)->debugPrintSampleStyleRecursively(indentLevel, countedFunctions, data); + + sumOfChildrensCount *= 1000; // + // Print remainder of samples to match sample's output + if (sumOfChildrensCount < sampleCount) { + dataLogF(" "); + while (indentLevel--) + dataLogF(" "); + + dataLogF("%.0f %s\n", sampleCount - sumOfChildrensCount, functionName().utf8().data()); + } + + return nodeTotalTime; +} +#endif + +} // namespace JSC diff --git a/Source/JavaScriptCore/profiler/ProfileNode.h b/Source/JavaScriptCore/profiler/ProfileNode.h new file mode 100644 index 000000000..fcaee0e24 --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfileNode.h @@ -0,0 +1,194 @@ +/* + * 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 + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ProfileNode_h +#define ProfileNode_h + +#include "CallIdentifier.h" +#include <wtf/HashCountedSet.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +namespace JSC { + + class ExecState; + class ProfileNode; + + typedef HashCountedSet<StringImpl*> FunctionCallHashCount; + + class ProfileNode : public RefCounted<ProfileNode> { + public: + static Ref<ProfileNode> create(ExecState* callerCallFrame, const CallIdentifier& callIdentifier, ProfileNode* parentNode) + { + return adoptRef(*new ProfileNode(callerCallFrame, callIdentifier, parentNode)); + } + + static Ref<ProfileNode> create(ExecState* callerCallFrame, ProfileNode* node) + { + return adoptRef(*new ProfileNode(callerCallFrame, 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(); } + + 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(); } + + 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); } + + 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; } + + 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>); + +#ifndef NDEBUG + struct ProfileSubtreeData { + HashMap<ProfileNode*, std::pair<double, double>> selfAndTotalTimes; + double rootTotalTime; + }; + + // Use these functions to dump the subtree rooted at this node. + void debugPrint(); + void debugPrintSampleStyle(); + + // These are used to recursively print entire subtrees using precomputed self and total times. + template <typename Functor> void forEachNodePostorder(Functor&); + + void debugPrintRecursively(int indentLevel, const ProfileSubtreeData&); + double debugPrintSampleStyleRecursively(int indentLevel, FunctionCallHashCount&, const ProfileSubtreeData&); +#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* traverseNextNodePostOrder() const; +#endif + + ExecState* m_callerCallFrame; + CallIdentifier m_callIdentifier; + 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); + } + + 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; + }; +#endif + +} // namespace JSC + +#endif // ProfileNode_h diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecode.cpp b/Source/JavaScriptCore/profiler/ProfilerBytecode.cpp new file mode 100644 index 000000000..6eeeb27b9 --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerBytecode.cpp @@ -0,0 +1,45 @@ +/* + * 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 + * 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 "ProfilerBytecode.h" + +#include "JSGlobalObject.h" +#include "ObjectConstructor.h" +#include "JSCInlines.h" + +namespace JSC { namespace Profiler { + +JSValue Bytecode::toJS(ExecState* exec) const +{ + JSObject* result = constructEmptyObject(exec); + result->putDirect(exec->vm(), exec->propertyNames().bytecodeIndex, jsNumber(m_bytecodeIndex)); + result->putDirect(exec->vm(), exec->propertyNames().opcode, jsString(exec, String::fromUTF8(opcodeNames[m_opcodeID]))); + result->putDirect(exec->vm(), exec->propertyNames().description, jsString(exec, String::fromUTF8(m_description))); + return result; +} + +} } // namespace JSC::Profiler + diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecode.h b/Source/JavaScriptCore/profiler/ProfilerBytecode.h new file mode 100644 index 000000000..8e99c9a09 --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerBytecode.h @@ -0,0 +1,65 @@ +/* + * 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 + * 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 ProfilerBytecode_h +#define ProfilerBytecode_h + +#include "JSCJSValue.h" +#include "Opcode.h" +#include <wtf/text/CString.h> + +namespace JSC { namespace Profiler { + +class Bytecode { +public: + Bytecode() + : m_bytecodeIndex(std::numeric_limits<unsigned>::max()) + { + } + + Bytecode(unsigned bytecodeIndex, OpcodeID opcodeID, const CString& description) + : m_bytecodeIndex(bytecodeIndex) + , m_opcodeID(opcodeID) + , m_description(description) + { + } + + unsigned bytecodeIndex() const { return m_bytecodeIndex; } + OpcodeID opcodeID() const { return m_opcodeID; } + const CString& description() const { return m_description; } + + JSValue toJS(ExecState*) const; +private: + unsigned m_bytecodeIndex; + OpcodeID m_opcodeID; + CString m_description; +}; + +inline unsigned getBytecodeIndexForBytecode(Bytecode* bytecode) { return bytecode->bytecodeIndex(); } + +} } // namespace JSC::Profiler + +#endif // ProfilerBytecode_h + diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp b/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp new file mode 100644 index 000000000..145ee44d1 --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp @@ -0,0 +1,92 @@ +/* + * 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 + * 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 "ProfilerBytecodeSequence.h" + +#include "CodeBlock.h" +#include "JSGlobalObject.h" +#include "Operands.h" +#include "JSCInlines.h" +#include <wtf/StringPrintStream.h> + +namespace JSC { namespace Profiler { + +BytecodeSequence::BytecodeSequence(CodeBlock* codeBlock) +{ + StringPrintStream out; + + for (unsigned i = 0; i < codeBlock->numberOfArgumentValueProfiles(); ++i) { + ConcurrentJITLocker locker(codeBlock->m_lock); + CString description = codeBlock->valueProfileForArgument(i)->briefDescription(locker); + if (!description.length()) + continue; + out.reset(); + out.print("arg", i, ": ", description); + m_header.append(out.toCString()); + } + + StubInfoMap stubInfos; + codeBlock->getStubInfoMap(stubInfos); + + for (unsigned bytecodeIndex = 0; bytecodeIndex < codeBlock->instructions().size();) { + out.reset(); + codeBlock->dumpBytecode(out, bytecodeIndex, stubInfos); + m_sequence.append(Bytecode(bytecodeIndex, codeBlock->vm()->interpreter->getOpcodeID(codeBlock->instructions()[bytecodeIndex].u.opcode), out.toCString())); + bytecodeIndex += opcodeLength( + codeBlock->vm()->interpreter->getOpcodeID( + codeBlock->instructions()[bytecodeIndex].u.opcode)); + } +} + +BytecodeSequence::~BytecodeSequence() +{ +} + +unsigned BytecodeSequence::indexForBytecodeIndex(unsigned bytecodeIndex) const +{ + return binarySearch<Bytecode, unsigned>(m_sequence, m_sequence.size(), bytecodeIndex, getBytecodeIndexForBytecode) - m_sequence.begin(); +} + +const Bytecode& BytecodeSequence::forBytecodeIndex(unsigned bytecodeIndex) const +{ + return at(indexForBytecodeIndex(bytecodeIndex)); +} + +void BytecodeSequence::addSequenceProperties(ExecState* exec, JSObject* result) const +{ + JSArray* header = constructEmptyArray(exec, 0); + for (unsigned i = 0; i < m_header.size(); ++i) + header->putDirectIndex(exec, i, jsString(exec, String::fromUTF8(m_header[i]))); + result->putDirect(exec->vm(), exec->propertyNames().header, header); + + JSArray* sequence = constructEmptyArray(exec, 0); + for (unsigned i = 0; i < m_sequence.size(); ++i) + sequence->putDirectIndex(exec, i, m_sequence[i].toJS(exec)); + result->putDirect(exec->vm(), exec->propertyNames().bytecode, sequence); +} + +} } // namespace JSC::Profiler + diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.h b/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.h new file mode 100644 index 000000000..1d5c82a18 --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.h @@ -0,0 +1,65 @@ +/* + * 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 + * 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 ProfilerBytecodeSequence_h +#define ProfilerBytecodeSequence_h + +#include "JSCJSValue.h" +#include "ProfilerBytecode.h" +#include <wtf/PrintStream.h> +#include <wtf/Vector.h> +#include <wtf/text/CString.h> +#include <wtf/text/WTFString.h> + +namespace JSC { + +class CodeBlock; + +namespace Profiler { + +class BytecodeSequence { +public: + BytecodeSequence(CodeBlock*); + ~BytecodeSequence(); + + // Note that this data structure is not indexed by bytecode index. + unsigned size() const { return m_sequence.size(); } + const Bytecode& at(unsigned i) const { return m_sequence[i]; } + + unsigned indexForBytecodeIndex(unsigned bytecodeIndex) const; + const Bytecode& forBytecodeIndex(unsigned bytecodeIndex) const; + +protected: + void addSequenceProperties(ExecState*, JSObject*) const; + +private: + Vector<CString> m_header; + Vector<Bytecode> m_sequence; +}; + +} } // namespace JSC::Profiler + +#endif // ProfilerBytecodeSequence_h + diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp b/Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp new file mode 100644 index 000000000..74c55abcf --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp @@ -0,0 +1,69 @@ +/* + * 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 + * 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 "ProfilerBytecodes.h" + +#include "CodeBlock.h" +#include "JSGlobalObject.h" +#include "ObjectConstructor.h" +#include "JSCInlines.h" +#include <wtf/StringPrintStream.h> + +namespace JSC { namespace Profiler { + +Bytecodes::Bytecodes(size_t id, CodeBlock* codeBlock) + : BytecodeSequence(codeBlock) + , m_id(id) + , m_inferredName(codeBlock->inferredName()) + , m_sourceCode(codeBlock->sourceCodeForTools()) + , m_hash(codeBlock->hash()) + , m_instructionCount(codeBlock->instructionCount()) +{ +} + +Bytecodes::~Bytecodes() { } + +void Bytecodes::dump(PrintStream& out) const +{ + out.print("#", m_hash, "(", m_id, ")"); +} + +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, 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); + + return result; +} + +} } // namespace JSC::Profiler + diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecodes.h b/Source/JavaScriptCore/profiler/ProfilerBytecodes.h new file mode 100644 index 000000000..e44598019 --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerBytecodes.h @@ -0,0 +1,63 @@ +/* + * 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 + * 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 ProfilerBytecodes_h +#define ProfilerBytecodes_h + +#include "CodeBlockHash.h" +#include "JSCJSValue.h" +#include "ProfilerBytecodeSequence.h" +#include <wtf/PrintStream.h> +#include <wtf/text/WTFString.h> + +namespace JSC { namespace Profiler { + +class Bytecodes : public BytecodeSequence { +public: + Bytecodes(size_t id, CodeBlock*); + ~Bytecodes(); + + size_t id() const { return m_id; } + 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; } + + void dump(PrintStream&) const; + + JSValue toJS(ExecState*) const; + +private: + size_t m_id; + CString m_inferredName; + CString m_sourceCode; + CodeBlockHash m_hash; + unsigned m_instructionCount; +}; + +} } // namespace JSC::Profiler + +#endif // ProfilerBytecodes_h + diff --git a/Source/JavaScriptCore/profiler/ProfilerCompilation.cpp b/Source/JavaScriptCore/profiler/ProfilerCompilation.cpp new file mode 100644 index 000000000..488f563de --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerCompilation.cpp @@ -0,0 +1,156 @@ +/* + * 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 + * 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 "ProfilerCompilation.h" + +#include "JSGlobalObject.h" +#include "ObjectConstructor.h" +#include "JSCInlines.h" +#include "ProfilerDatabase.h" +#include "Watchpoint.h" +#include <wtf/StringPrintStream.h> + +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) +{ +} + +Compilation::~Compilation() { } + +void Compilation::addProfiledBytecodes(Database& database, CodeBlock* profiledBlock) +{ + Bytecodes* bytecodes = database.ensureBytecodesFor(profiledBlock); + + // First make sure that we haven't already added profiled bytecodes for this code + // block. We do this using an O(N) search because I suspect that this list will + // tend to be fairly small, and the additional space costs of having a HashMap/Set + // would be greater than the time cost of occasionally doing this search. + + for (unsigned i = m_profiledBytecodes.size(); i--;) { + if (m_profiledBytecodes[i].bytecodes() == bytecodes) + return; + } + + m_profiledBytecodes.append(ProfiledBytecodes(bytecodes, profiledBlock)); +} + +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; + if (!counter) + counter = std::make_unique<ExecutionCounter>(); + + return counter.get(); +} + +void Compilation::addOSRExitSite(const Vector<const void*>& codeAddresses) +{ + m_osrExitSites.append(OSRExitSite(codeAddresses)); +} + +OSRExit* Compilation::addOSRExit(unsigned id, const OriginStack& originStack, ExitKind exitKind, bool isWatchpoint) +{ + m_osrExits.append(OSRExit(id, originStack, exitKind, isWatchpoint)); + 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); + + result->putDirect(exec->vm(), exec->propertyNames().bytecodesID, jsNumber(m_bytecodes->id())); + result->putDirect(exec->vm(), exec->propertyNames().compilationKind, jsString(exec, String::fromUTF8(toCString(m_kind)))); + + JSArray* profiledBytecodes = constructEmptyArray(exec, 0); + for (unsigned i = 0; i < m_profiledBytecodes.size(); ++i) + profiledBytecodes->putDirectIndex(exec, i, m_profiledBytecodes[i].toJS(exec)); + result->putDirect(exec->vm(), exec->propertyNames().profiledBytecodes, profiledBytecodes); + + JSArray* descriptions = constructEmptyArray(exec, 0); + for (unsigned i = 0; i < m_descriptions.size(); ++i) + descriptions->putDirectIndex(exec, i, m_descriptions[i].toJS(exec)); + result->putDirect(exec->vm(), exec->propertyNames().descriptions, descriptions); + + JSArray* counters = constructEmptyArray(exec, 0); + for (auto it = m_counters.begin(), end = m_counters.end(); it != end; ++it) { + JSObject* counterEntry = constructEmptyObject(exec); + counterEntry->putDirect(exec->vm(), exec->propertyNames().origin, it->key.toJS(exec)); + counterEntry->putDirect(exec->vm(), exec->propertyNames().executionCount, jsNumber(it->value->count())); + counters->push(exec, counterEntry); + } + result->putDirect(exec->vm(), exec->propertyNames().counters, counters); + + JSArray* exitSites = constructEmptyArray(exec, 0); + for (unsigned i = 0; i < m_osrExitSites.size(); ++i) + exitSites->putDirectIndex(exec, i, m_osrExitSites[i].toJS(exec)); + result->putDirect(exec->vm(), exec->propertyNames().osrExitSites, exitSites); + + JSArray* exits = constructEmptyArray(exec, 0); + for (unsigned i = 0; i < m_osrExits.size(); ++i) + exits->putDirectIndex(exec, i, m_osrExits[i].toJS(exec)); + result->putDirect(exec->vm(), exec->propertyNames().osrExits, exits); + + 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; +} + +} } // namespace JSC::Profiler + diff --git a/Source/JavaScriptCore/profiler/ProfilerCompilation.h b/Source/JavaScriptCore/profiler/ProfilerCompilation.h new file mode 100644 index 000000000..b358b659c --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerCompilation.h @@ -0,0 +1,98 @@ +/* + * 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 + * 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 ProfilerCompilation_h +#define ProfilerCompilation_h + +#include "ExitKind.h" +#include "JSCJSValue.h" +#include "ProfilerCompilationKind.h" +#include "ProfilerCompiledBytecode.h" +#include "ProfilerExecutionCounter.h" +#include "ProfilerJettisonReason.h" +#include "ProfilerOSRExit.h" +#include "ProfilerOSRExitSite.h" +#include "ProfilerOriginStack.h" +#include "ProfilerProfiledBytecodes.h" +#include <wtf/RefCounted.h> +#include <wtf/SegmentedVector.h> + +namespace JSC { + +class FireDetail; + +namespace Profiler { + +class Bytecodes; +class Database; + +// Represents the act of executing some bytecodes in some engine, and does +// all of the counting for those executions. + +class Compilation : public RefCounted<Compilation> { +public: + Compilation(Bytecodes*, CompilationKind); + ~Compilation(); + + void addProfiledBytecodes(Database&, CodeBlock*); + unsigned profiledBytecodesSize() const { return m_profiledBytecodes.size(); } + const ProfiledBytecodes& profiledBytecodesAt(unsigned i) const { return m_profiledBytecodes[i]; } + + void noticeInlinedGetById() { m_numInlinedGetByIds++; } + void noticeInlinedPutById() { m_numInlinedPutByIds++; } + void noticeInlinedCall() { m_numInlinedCalls++; } + + Bytecodes* bytecodes() const { return m_bytecodes; } + 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; + Vector<OSRExitSite> m_osrExitSites; + SegmentedVector<OSRExit> m_osrExits; + unsigned m_numInlinedGetByIds; + unsigned m_numInlinedPutByIds; + unsigned m_numInlinedCalls; +}; + +} } // namespace JSC::Profiler + +#endif // ProfilerCompilation_h + diff --git a/Source/JavaScriptCore/profiler/ProfilerCompilationKind.cpp b/Source/JavaScriptCore/profiler/ProfilerCompilationKind.cpp new file mode 100644 index 000000000..3fbe25192 --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerCompilationKind.cpp @@ -0,0 +1,58 @@ +/* + * 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 + * 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 "ProfilerCompilationKind.h" + +#include <wtf/PrintStream.h> + +namespace WTF { + +void printInternal(PrintStream& out, JSC::Profiler::CompilationKind kind) +{ + switch (kind) { + case JSC::Profiler::LLInt: + out.print("LLInt"); + return; + case JSC::Profiler::Baseline: + out.print("Baseline"); + return; + 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; + } +} + +} // namespace WTF + diff --git a/Source/JavaScriptCore/profiler/ProfilerCompilationKind.h b/Source/JavaScriptCore/profiler/ProfilerCompilationKind.h new file mode 100644 index 000000000..575ec2947 --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerCompilationKind.h @@ -0,0 +1,49 @@ +/* + * 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 + * 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 ProfilerCompilationKind_h +#define ProfilerCompilationKind_h + +namespace JSC { namespace Profiler { + +enum CompilationKind { + LLInt, + Baseline, + DFG, + FTL, + FTLForOSREntry +}; + +} } // namespace JSC::Profiler + +namespace WTF { + +class PrintStream; +void printInternal(PrintStream&, JSC::Profiler::CompilationKind); + +} // namespace WTF + +#endif // ProfilerCompilationKind_h + diff --git a/Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.cpp b/Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.cpp new file mode 100644 index 000000000..4891c315c --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.cpp @@ -0,0 +1,56 @@ +/* + * 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 + * 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 "ProfilerCompiledBytecode.h" + +#include "JSGlobalObject.h" +#include "ObjectConstructor.h" +#include "JSCInlines.h" + +namespace JSC { namespace Profiler { + +CompiledBytecode::CompiledBytecode(const OriginStack& origin, const CString& description) + : m_origin(origin) + , m_description(description) +{ +} + +CompiledBytecode::~CompiledBytecode() +{ +} + +JSValue CompiledBytecode::toJS(ExecState* exec) const +{ + JSObject* result = constructEmptyObject(exec); + + result->putDirect(exec->vm(), exec->propertyNames().origin, m_origin.toJS(exec)); + result->putDirect(exec->vm(), exec->propertyNames().description, jsString(exec, String::fromUTF8(m_description))); + + return result; +} + +} } // namespace JSC::Profiler + diff --git a/Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.h b/Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.h new file mode 100644 index 000000000..84044445a --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.h @@ -0,0 +1,55 @@ +/* + * 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 + * 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 ProfilerCompiledBytecode_h +#define ProfilerCompiledBytecode_h + +#include "JSCJSValue.h" +#include "ProfilerOriginStack.h" +#include <wtf/text/CString.h> + +namespace JSC { namespace Profiler { + +class CompiledBytecode { +public: + // It's valid to have an empty OriginStack, which indicates that this is some + // sort of non-bytecode-related machine code. + CompiledBytecode(const OriginStack&, const CString& description); + ~CompiledBytecode(); + + const OriginStack& originStack() const { return m_origin; } + const CString& description() const { return m_description; } + + JSValue toJS(ExecState*) const; + +private: + OriginStack m_origin; + CString m_description; +}; + +} } // namespace JSC::Profiler + +#endif // ProfilerCompiledBytecode_h + diff --git a/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp b/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp new file mode 100644 index 000000000..fc952c0c2 --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp @@ -0,0 +1,183 @@ +/* + * 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 + * 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 "ProfilerDatabase.h" + +#include "CodeBlock.h" +#include "JSONObject.h" +#include "ObjectConstructor.h" +#include "JSCInlines.h" + +namespace JSC { namespace Profiler { + +static std::atomic<int> databaseCounter; + +static StaticLock registrationLock; +static std::atomic<int> didRegisterAtExit; +static Database* firstDatabase; + +Database::Database(VM& vm) + : m_databaseID(++databaseCounter) + , m_vm(vm) + , m_shouldSaveAtExit(false) + , m_nextRegisteredDatabase(0) +{ +} + +Database::~Database() +{ + if (m_shouldSaveAtExit) { + removeDatabaseFromAtExit(); + performAtExitSave(); + } +} + +Bytecodes* Database::ensureBytecodesFor(CodeBlock* codeBlock) +{ + LockHolder locker(m_lock); + + codeBlock = codeBlock->baselineVersion(); + + HashMap<CodeBlock*, Bytecodes*>::iterator iter = m_bytecodesMap.find(codeBlock); + if (iter != m_bytecodesMap.end()) + return iter->value; + + m_bytecodes.append(Bytecodes(m_bytecodes.size(), codeBlock)); + Bytecodes* result = &m_bytecodes.last(); + + m_bytecodesMap.add(codeBlock, result); + + return result; +} + +void Database::notifyDestruction(CodeBlock* codeBlock) +{ + LockHolder locker(m_lock); + + m_bytecodesMap.remove(codeBlock); +} + +void Database::addCompilation(PassRefPtr<Compilation> compilation) +{ + ASSERT(!isCompilationThread()); + + m_compilations.append(compilation); +} + +JSValue Database::toJS(ExecState* exec) const +{ + JSObject* result = constructEmptyObject(exec); + + JSArray* bytecodes = constructEmptyArray(exec, 0); + for (unsigned i = 0; i < m_bytecodes.size(); ++i) + bytecodes->putDirectIndex(exec, i, m_bytecodes[i].toJS(exec)); + result->putDirect(exec->vm(), exec->propertyNames().bytecodes, bytecodes); + + JSArray* compilations = constructEmptyArray(exec, 0); + for (unsigned i = 0; i < m_compilations.size(); ++i) + compilations->putDirectIndex(exec, i, m_compilations[i]->toJS(exec)); + result->putDirect(exec->vm(), exec->propertyNames().compilations, compilations); + + return result; +} + +String Database::toJSON() const +{ + JSGlobalObject* globalObject = JSGlobalObject::create( + m_vm, JSGlobalObject::createStructure(m_vm, jsNull())); + + return JSONStringify(globalObject->globalExec(), toJS(globalObject->globalExec()), 0); +} + +bool Database::save(const char* filename) const +{ + auto out = FilePrintStream::open(filename, "w"); + if (!out) + return false; + + out->print(toJSON()); + return true; +} + +void Database::registerToSaveAtExit(const char* filename) +{ + m_atExitSaveFilename = filename; + + if (m_shouldSaveAtExit) + return; + + addDatabaseToAtExit(); + m_shouldSaveAtExit = true; +} + +void Database::addDatabaseToAtExit() +{ + if (++didRegisterAtExit == 1) + atexit(atExitCallback); + + LockHolder holder(registrationLock); + m_nextRegisteredDatabase = firstDatabase; + firstDatabase = this; +} + +void Database::removeDatabaseFromAtExit() +{ + LockHolder holder(registrationLock); + for (Database** current = &firstDatabase; *current; current = &(*current)->m_nextRegisteredDatabase) { + if (*current != this) + continue; + *current = m_nextRegisteredDatabase; + m_nextRegisteredDatabase = 0; + m_shouldSaveAtExit = false; + break; + } +} + +void Database::performAtExitSave() const +{ + save(m_atExitSaveFilename.data()); +} + +Database* Database::removeFirstAtExitDatabase() +{ + LockHolder holder(registrationLock); + Database* result = firstDatabase; + if (result) { + firstDatabase = result->m_nextRegisteredDatabase; + result->m_nextRegisteredDatabase = 0; + result->m_shouldSaveAtExit = false; + } + return result; +} + +void Database::atExitCallback() +{ + while (Database* database = removeFirstAtExitDatabase()) + database->performAtExitSave(); +} + +} } // namespace JSC::Profiler + diff --git a/Source/JavaScriptCore/profiler/ProfilerDatabase.h b/Source/JavaScriptCore/profiler/ProfilerDatabase.h new file mode 100644 index 000000000..9bb64cf49 --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerDatabase.h @@ -0,0 +1,94 @@ +/* + * 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 + * 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 ProfilerDatabase_h +#define ProfilerDatabase_h + +#include "JSCJSValue.h" +#include "ProfilerBytecodes.h" +#include "ProfilerCompilation.h" +#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> +#include <wtf/ThreadingPrimitives.h> +#include <wtf/text/WTFString.h> + +namespace JSC { namespace Profiler { + +class Database { + WTF_MAKE_FAST_ALLOCATED; WTF_MAKE_NONCOPYABLE(Database); +public: + JS_EXPORT_PRIVATE Database(VM&); + JS_EXPORT_PRIVATE ~Database(); + + int databaseID() const { return m_databaseID; } + + Bytecodes* ensureBytecodesFor(CodeBlock*); + void notifyDestruction(CodeBlock*); + + 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 + // object that is "clean" - i.e. array and object prototypes haven't had strange things + // done to them. And yes, it should be appropriate to just use a globalExec here. + JS_EXPORT_PRIVATE JSValue toJS(ExecState*) const; + + // Converts the database to a JavaScript object using a private temporary global object, + // and then returns the JSON representation of that object. + JS_EXPORT_PRIVATE String toJSON() const; + + // Saves the JSON representation (from toJSON()) to the given file. Returns false if the + // save failed. + JS_EXPORT_PRIVATE bool save(const char* filename) const; + + void registerToSaveAtExit(const char* filename); + +private: + void addDatabaseToAtExit(); + void removeDatabaseFromAtExit(); + void performAtExitSave() const; + static Database* removeFirstAtExitDatabase(); + static void atExitCallback(); + + int m_databaseID; + VM& m_vm; + SegmentedVector<Bytecodes> m_bytecodes; + HashMap<CodeBlock*, Bytecodes*> m_bytecodesMap; + Vector<RefPtr<Compilation>> m_compilations; + bool m_shouldSaveAtExit; + CString m_atExitSaveFilename; + Database* m_nextRegisteredDatabase; + Lock m_lock; +}; + +} } // namespace JSC::Profiler + +#endif // ProfilerDatabase_h + diff --git a/Source/JavaScriptCore/profiler/ProfilerExecutionCounter.h b/Source/JavaScriptCore/profiler/ProfilerExecutionCounter.h new file mode 100644 index 000000000..8989e38b5 --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerExecutionCounter.h @@ -0,0 +1,50 @@ +/* + * 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 + * 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 ProfilerExecutionCounter_h +#define ProfilerExecutionCounter_h + +#include <wtf/FastMalloc.h> +#include <wtf/Noncopyable.h> + +namespace JSC { namespace Profiler { + +class ExecutionCounter { + WTF_MAKE_FAST_ALLOCATED; WTF_MAKE_NONCOPYABLE(ExecutionCounter); +public: + ExecutionCounter() : m_counter(0) { } + + uint64_t* address() { return &m_counter; } + + uint64_t count() const { return m_counter; } + +private: + uint64_t m_counter; +}; + +} } // namespace JSC::Profiler + +#endif // ProfilerExecutionCounter_h + diff --git a/Source/JavaScriptCore/profiler/ProfilerJettisonReason.cpp b/Source/JavaScriptCore/profiler/ProfilerJettisonReason.cpp new file mode 100644 index 000000000..5fad7297f --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerJettisonReason.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2014 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ProfilerJettisonReason.h" + +#include <wtf/PrintStream.h> + +namespace WTF { + +using namespace JSC::Profiler; + +void printInternal(PrintStream& out, JettisonReason reason) +{ + switch (reason) { + case NotJettisoned: + out.print("NotJettisoned"); + return; + case JettisonDueToWeakReference: + out.print("WeakReference"); + return; + case JettisonDueToDebuggerBreakpoint: + out.print("DebuggerBreakpoint"); + return; + case JettisonDueToDebuggerStepping: + out.print("DebuggerStepping"); + return; + case 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 new file mode 100644 index 000000000..0a15ba30e --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerJettisonReason.h @@ -0,0 +1,54 @@ +/* + * 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 new file mode 100644 index 000000000..2a5d5be40 --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerOSRExit.cpp @@ -0,0 +1,60 @@ +/* + * 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 + * 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 "ProfilerOSRExit.h" + +#include "JSGlobalObject.h" +#include "ObjectConstructor.h" +#include "JSCInlines.h" + +namespace JSC { namespace Profiler { + +OSRExit::OSRExit(unsigned id, const OriginStack& origin, ExitKind kind, bool isWatchpoint) + : m_id(id) + , m_origin(origin) + , m_exitKind(kind) + , m_isWatchpoint(isWatchpoint) + , m_counter(0) +{ +} + +OSRExit::~OSRExit() +{ +} + +JSValue OSRExit::toJS(ExecState* exec) const +{ + JSObject* result = constructEmptyObject(exec); + result->putDirect(exec->vm(), exec->propertyNames().id, jsNumber(m_id)); + result->putDirect(exec->vm(), exec->propertyNames().origin, m_origin.toJS(exec)); + result->putDirect(exec->vm(), exec->propertyNames().exitKind, jsString(exec, exitKindToString(m_exitKind))); + result->putDirect(exec->vm(), exec->propertyNames().isWatchpoint, jsBoolean(m_isWatchpoint)); + result->putDirect(exec->vm(), exec->propertyNames().count, jsNumber(m_counter)); + return result; +} + +} } // namespace JSC::Profiler + diff --git a/Source/JavaScriptCore/profiler/ProfilerOSRExit.h b/Source/JavaScriptCore/profiler/ProfilerOSRExit.h new file mode 100644 index 000000000..2a23d0b2c --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerOSRExit.h @@ -0,0 +1,61 @@ +/* + * 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 + * 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 ProfilerOSRExit_h +#define ProfilerOSRExit_h + +#include "ExitKind.h" +#include "JSCJSValue.h" +#include "ProfilerOriginStack.h" + +namespace JSC { namespace Profiler { + +class OSRExit { +public: + OSRExit(unsigned id, const OriginStack&, ExitKind, bool isWatchpoint); + ~OSRExit(); + + unsigned id() const { return m_id; } + const OriginStack& origin() const { return m_origin; } + ExitKind exitKind() const { return m_exitKind; } + bool isWatchpoint() const { return m_isWatchpoint; } + + uint64_t* counterAddress() { return &m_counter; } + uint64_t count() const { return m_counter; } + + JSValue toJS(ExecState*) const; + +private: + unsigned m_id; + OriginStack m_origin; + ExitKind m_exitKind; + bool m_isWatchpoint; + uint64_t m_counter; +}; + +} } // namespace JSC::Profiler + +#endif // ProfilerOSRExit_h + diff --git a/Source/JavaScriptCore/profiler/ProfilerOSRExitSite.cpp b/Source/JavaScriptCore/profiler/ProfilerOSRExitSite.cpp new file mode 100644 index 000000000..b17d57e52 --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerOSRExitSite.cpp @@ -0,0 +1,46 @@ +/* + * 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 + * 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 "ProfilerOSRExitSite.h" + +#include "JSGlobalObject.h" +#include "JSScope.h" +#include "JSString.h" +#include "JSCInlines.h" +#include <wtf/StringPrintStream.h> + +namespace JSC { namespace Profiler { + +JSValue OSRExitSite::toJS(ExecState* exec) const +{ + JSArray* result = constructEmptyArray(exec, 0); + for (unsigned i = 0; i < m_codeAddresses.size(); ++i) + result->putDirectIndex(exec, i, jsString(exec, toString(RawPointer(m_codeAddresses[i])))); + return result; +} + +} } // namespace JSC::Profiler + diff --git a/Source/JavaScriptCore/profiler/ProfilerOSRExitSite.h b/Source/JavaScriptCore/profiler/ProfilerOSRExitSite.h new file mode 100644 index 000000000..fa418e9b8 --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerOSRExitSite.h @@ -0,0 +1,52 @@ +/* + * 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 + * 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 ProfilerOSRExitSite_h +#define ProfilerOSRExitSite_h + +#include "JSCJSValue.h" +#include <wtf/Vector.h> + +namespace JSC { namespace Profiler { + +class OSRExitSite { +public: + explicit OSRExitSite(const Vector<const void*>& codeAddresses) + : m_codeAddresses(codeAddresses) + { + } + + const Vector<const void*>& codeAddress() const { return m_codeAddresses; } + + JSValue toJS(ExecState*) const; + +private: + Vector<const void*> m_codeAddresses; +}; + +} } // namespace JSC::Profiler + +#endif // ProfilerOSRExitSite_h + diff --git a/Source/JavaScriptCore/profiler/ProfilerOrigin.cpp b/Source/JavaScriptCore/profiler/ProfilerOrigin.cpp new file mode 100644 index 000000000..7c28f7ba3 --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerOrigin.cpp @@ -0,0 +1,57 @@ +/* + * 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 + * 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 "ProfilerOrigin.h" + +#include "JSGlobalObject.h" +#include "ObjectConstructor.h" +#include "JSCInlines.h" +#include "ProfilerBytecodes.h" +#include "ProfilerDatabase.h" + +namespace JSC { namespace Profiler { + +Origin::Origin(Database& database, CodeBlock* codeBlock, unsigned bytecodeIndex) + : m_bytecodes(database.ensureBytecodesFor(codeBlock)) + , m_bytecodeIndex(bytecodeIndex) +{ +} + +void Origin::dump(PrintStream& out) const +{ + out.print(*m_bytecodes, ":bc#", m_bytecodeIndex); +} + +JSValue Origin::toJS(ExecState* exec) const +{ + JSObject* result = constructEmptyObject(exec); + result->putDirect(exec->vm(), exec->propertyNames().bytecodesID, jsNumber(m_bytecodes->id())); + result->putDirect(exec->vm(), exec->propertyNames().bytecodeIndex, jsNumber(m_bytecodeIndex)); + return result; +} + +} } // namespace JSC::Profiler + diff --git a/Source/JavaScriptCore/profiler/ProfilerOrigin.h b/Source/JavaScriptCore/profiler/ProfilerOrigin.h new file mode 100644 index 000000000..09b388451 --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerOrigin.h @@ -0,0 +1,120 @@ +/* + * 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 + * 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 ProfilerOrigin_h +#define ProfilerOrigin_h + +#include "CodeBlockHash.h" +#include "JSCJSValue.h" +#include <wtf/HashMap.h> +#include <wtf/PrintStream.h> + +namespace JSC { + +class CodeBlock; + +namespace Profiler { + +class Bytecodes; +class Database; + +class Origin { +public: + Origin() + : m_bytecodeIndex(std::numeric_limits<unsigned>::max()) + { + } + + Origin(WTF::HashTableDeletedValueType) + : m_bytecodeIndex(std::numeric_limits<unsigned>::max() - 1) + { + } + + Origin(Bytecodes* bytecodes, unsigned bytecodeIndex) + : m_bytecodes(bytecodes) + , m_bytecodeIndex(bytecodeIndex) + { + ASSERT(m_bytecodeIndex < std::numeric_limits<unsigned>::max() - 1); + } + + Origin(Database&, CodeBlock*, unsigned bytecodeIndex); + + bool operator!() const { return m_bytecodeIndex == std::numeric_limits<unsigned>::max(); } + + Bytecodes* bytecodes() const { return m_bytecodes; } + unsigned bytecodeIndex() const { return m_bytecodeIndex; } + + bool operator==(const Origin&) const; + bool operator!=(const Origin& other) const { return !(*this == other); } + unsigned hash() const; + + bool isHashTableDeletedValue() const; + + void dump(PrintStream&) const; + JSValue toJS(ExecState*) const; + +private: + Bytecodes* m_bytecodes; + unsigned m_bytecodeIndex; +}; + +inline bool Origin::operator==(const Origin& other) const +{ + return m_bytecodes == other.m_bytecodes + && m_bytecodeIndex == other.m_bytecodeIndex; +} + +inline unsigned Origin::hash() const +{ + return WTF::PtrHash<Bytecodes*>::hash(m_bytecodes) + m_bytecodeIndex; +} + +inline bool Origin::isHashTableDeletedValue() const +{ + return m_bytecodeIndex == std::numeric_limits<unsigned>::max(); +} + +struct OriginHash { + static unsigned hash(const Origin& key) { return key.hash(); } + static bool equal(const Origin& a, const Origin& b) { return a == b; } + static const bool safeToCompareToEmptyOrDeleted = true; +}; + +} } // namespace JSC::Profiler + +namespace WTF { + +template<typename T> struct DefaultHash; +template<> struct DefaultHash<JSC::Profiler::Origin> { + typedef JSC::Profiler::OriginHash Hash; +}; + +template<typename T> struct HashTraits; +template<> struct HashTraits<JSC::Profiler::Origin> : SimpleClassHashTraits<JSC::Profiler::Origin> { }; + +} // namespace WTF + +#endif // ProfilerOrigin_h + diff --git a/Source/JavaScriptCore/profiler/ProfilerOriginStack.cpp b/Source/JavaScriptCore/profiler/ProfilerOriginStack.cpp new file mode 100644 index 000000000..9b61daec1 --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerOriginStack.cpp @@ -0,0 +1,111 @@ +/* + * 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 + * 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 "ProfilerOriginStack.h" + +#include "CodeOrigin.h" +#include "JSGlobalObject.h" +#include "JSCInlines.h" +#include "ProfilerDatabase.h" + +namespace JSC { namespace Profiler { + +OriginStack::OriginStack(WTF::HashTableDeletedValueType) +{ + m_stack.append(Origin(WTF::HashTableDeletedValue)); +} + +OriginStack::OriginStack(const Origin& origin) +{ + m_stack.append(origin); +} + +OriginStack::OriginStack(Database& database, CodeBlock* codeBlock, const CodeOrigin& codeOrigin) +{ + Vector<CodeOrigin> stack = codeOrigin.inlineStack(); + + append(Origin(database, codeBlock, stack[0].bytecodeIndex)); + + for (unsigned i = 1; i < stack.size(); ++i) { + append(Origin( + database.ensureBytecodesFor(stack[i].inlineCallFrame->baselineCodeBlock()), + stack[i].bytecodeIndex)); + } +} + +OriginStack::~OriginStack() { } + +void OriginStack::append(const Origin& origin) +{ + m_stack.append(origin); +} + +bool OriginStack::operator==(const OriginStack& other) const +{ + if (m_stack.size() != other.m_stack.size()) + return false; + + for (unsigned i = m_stack.size(); i--;) { + if (m_stack[i] != other.m_stack[i]) + return false; + } + + return true; +} + +unsigned OriginStack::hash() const +{ + unsigned result = m_stack.size(); + + for (unsigned i = m_stack.size(); i--;) { + result *= 3; + result += m_stack[i].hash(); + } + + return result; +} + +void OriginStack::dump(PrintStream& out) const +{ + for (unsigned i = 0; i < m_stack.size(); ++i) { + if (i) + out.print(" --> "); + out.print(m_stack[i]); + } +} + +JSValue OriginStack::toJS(ExecState* exec) const +{ + JSArray* result = constructEmptyArray(exec, 0); + + for (unsigned i = 0; i < m_stack.size(); ++i) + result->putDirectIndex(exec, i, m_stack[i].toJS(exec)); + + return result; +} + +} } // namespace JSC::Profiler + diff --git a/Source/JavaScriptCore/profiler/ProfilerOriginStack.h b/Source/JavaScriptCore/profiler/ProfilerOriginStack.h new file mode 100644 index 000000000..415e8d9b0 --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerOriginStack.h @@ -0,0 +1,102 @@ +/* + * 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 + * 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 ProfilerOriginStack_h +#define ProfilerOriginStack_h + +#include "JSCJSValue.h" +#include "ProfilerOrigin.h" +#include <wtf/HashMap.h> +#include <wtf/PrintStream.h> +#include <wtf/Vector.h> + +namespace JSC { + +class CodeBlock; +struct CodeOrigin; + +namespace Profiler { + +class Database; + +class OriginStack { +public: + OriginStack() { } + + OriginStack(WTF::HashTableDeletedValueType); + + explicit OriginStack(const Origin&); + + explicit OriginStack(Database&, CodeBlock*, const CodeOrigin&); + + ~OriginStack(); + + void append(const Origin&); + + bool operator!() const { return m_stack.isEmpty(); } + + unsigned size() const { return m_stack.size(); } + const Origin& fromBottom(unsigned i) const { return m_stack[i]; } + const Origin& fromTop(unsigned i) const { return m_stack[m_stack.size() - i - 1]; } + + bool operator==(const OriginStack&) const; + unsigned hash() const; + + bool isHashTableDeletedValue() const; + + void dump(PrintStream&) const; + JSValue toJS(ExecState*) const; + +private: + Vector<Origin, 1> m_stack; +}; + +inline bool OriginStack::isHashTableDeletedValue() const +{ + return m_stack.size() == 1 && m_stack[0].isHashTableDeletedValue(); +} + +struct OriginStackHash { + static unsigned hash(const OriginStack& key) { return key.hash(); } + static bool equal(const OriginStack& a, const OriginStack& b) { return a == b; } + static const bool safeToCompareToEmptyOrDeleted = true; +}; + +} } // namespace JSC::Profiler + +namespace WTF { + +template<typename T> struct DefaultHash; +template<> struct DefaultHash<JSC::Profiler::OriginStack> { + typedef JSC::Profiler::OriginStackHash Hash; +}; + +template<typename T> struct HashTraits; +template<> struct HashTraits<JSC::Profiler::OriginStack> : SimpleClassHashTraits<JSC::Profiler::OriginStack> { }; + +} // namespace WTF + +#endif // ProfilerOriginStack_h + diff --git a/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.cpp b/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.cpp new file mode 100644 index 000000000..fe590ff78 --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.cpp @@ -0,0 +1,56 @@ +/* + * 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 + * 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 "ProfilerProfiledBytecodes.h" + +#include "JSGlobalObject.h" +#include "ObjectConstructor.h" +#include "JSCInlines.h" + +namespace JSC { namespace Profiler { + +ProfiledBytecodes::ProfiledBytecodes(Bytecodes* bytecodes, CodeBlock* profiledBlock) + : BytecodeSequence(profiledBlock) + , m_bytecodes(bytecodes) +{ +} + +ProfiledBytecodes::~ProfiledBytecodes() +{ +} + +JSValue ProfiledBytecodes::toJS(ExecState* exec) const +{ + JSObject* result = constructEmptyObject(exec); + + result->putDirect(exec->vm(), exec->propertyNames().bytecodesID, jsNumber(m_bytecodes->id())); + addSequenceProperties(exec, result); + + return result; +} + +} } // namespace JSC::Profiler + diff --git a/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.h b/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.h new file mode 100644 index 000000000..d7cb6ffa8 --- /dev/null +++ b/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.h @@ -0,0 +1,51 @@ +/* + * 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 + * 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 ProfilerProfiledBytecodes_h +#define ProfilerProfiledBytecodes_h + +#include "ProfilerBytecodeSequence.h" +#include "ProfilerBytecodes.h" +#include "ProfilerOriginStack.h" + +namespace JSC { namespace Profiler { + +class ProfiledBytecodes : public BytecodeSequence { +public: + ProfiledBytecodes(Bytecodes*, CodeBlock*); + ~ProfiledBytecodes(); + + const Bytecodes* bytecodes() const { return m_bytecodes; } + + JSValue toJS(ExecState*) const; + +private: + Bytecodes* m_bytecodes; +}; + +} } // namespace JSC::Profiler + +#endif // ProfilerProfiledBytecodes_h + |
