summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/profiler
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/profiler')
-rw-r--r--Source/JavaScriptCore/profiler/CallIdentifier.h43
-rw-r--r--Source/JavaScriptCore/profiler/LegacyProfiler.cpp94
-rw-r--r--Source/JavaScriptCore/profiler/LegacyProfiler.h22
-rw-r--r--Source/JavaScriptCore/profiler/Profile.cpp43
-rw-r--r--Source/JavaScriptCore/profiler/Profile.h44
-rw-r--r--Source/JavaScriptCore/profiler/ProfileGenerator.cpp161
-rw-r--r--Source/JavaScriptCore/profiler/ProfileGenerator.h29
-rw-r--r--Source/JavaScriptCore/profiler/ProfileNode.cpp160
-rw-r--r--Source/JavaScriptCore/profiler/ProfileNode.h170
-rw-r--r--Source/JavaScriptCore/profiler/ProfilerBytecode.cpp2
-rw-r--r--Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp11
-rw-r--r--Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp2
-rw-r--r--Source/JavaScriptCore/profiler/ProfilerCompilation.cpp26
-rw-r--r--Source/JavaScriptCore/profiler/ProfilerCompilation.h14
-rw-r--r--Source/JavaScriptCore/profiler/ProfilerCompilationKind.cpp8
-rw-r--r--Source/JavaScriptCore/profiler/ProfilerCompilationKind.h6
-rw-r--r--Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.cpp2
-rw-r--r--Source/JavaScriptCore/profiler/ProfilerDatabase.cpp14
-rw-r--r--Source/JavaScriptCore/profiler/ProfilerDatabase.h16
-rw-r--r--Source/JavaScriptCore/profiler/ProfilerJettisonReason.cpp76
-rw-r--r--Source/JavaScriptCore/profiler/ProfilerJettisonReason.h55
-rw-r--r--Source/JavaScriptCore/profiler/ProfilerOSRExit.cpp2
-rw-r--r--Source/JavaScriptCore/profiler/ProfilerOSRExitSite.cpp2
-rw-r--r--Source/JavaScriptCore/profiler/ProfilerOrigin.cpp2
-rw-r--r--Source/JavaScriptCore/profiler/ProfilerOriginStack.cpp5
-rw-r--r--Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.cpp2
26 files changed, 624 insertions, 387 deletions
diff --git a/Source/JavaScriptCore/profiler/CallIdentifier.h b/Source/JavaScriptCore/profiler/CallIdentifier.h
index bf9f904b0..691fc6250 100644
--- a/Source/JavaScriptCore/profiler/CallIdentifier.h
+++ b/Source/JavaScriptCore/profiler/CallIdentifier.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008, 2014 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -36,32 +36,37 @@ namespace JSC {
struct CallIdentifier {
WTF_MAKE_FAST_ALLOCATED;
public:
- String m_name;
- String m_url;
- unsigned m_lineNumber;
-
CallIdentifier()
: m_lineNumber(0)
+ , m_columnNumber(0)
{
}
- CallIdentifier(const String& name, const String& url, int lineNumber)
- : m_name(name)
+ CallIdentifier(const String& functionName, const String& url, unsigned lineNumber, unsigned columnNumber)
+ : m_functionName(functionName)
, m_url(!url.isNull() ? url : "")
, m_lineNumber(lineNumber)
+ , m_columnNumber(columnNumber)
{
}
- inline bool operator==(const CallIdentifier& ci) const { return ci.m_lineNumber == m_lineNumber && ci.m_name == m_name && ci.m_url == m_url; }
- inline bool operator!=(const CallIdentifier& ci) const { return !(*this == ci); }
+ const String& functionName() const { return m_functionName; }
+
+ const String& url() const { return m_url; }
+ unsigned lineNumber() const { return m_lineNumber; }
+ unsigned columnNumber() const { return m_columnNumber; }
+
+ inline bool operator==(const CallIdentifier& other) const { return other.m_lineNumber == m_lineNumber && other.m_columnNumber == m_columnNumber && other.m_functionName == m_functionName && other.m_url == m_url; }
+ inline bool operator!=(const CallIdentifier& other) const { return !(*this == other); }
struct Hash {
static unsigned hash(const CallIdentifier& key)
{
- unsigned hashCodes[3] = {
- key.m_name.impl()->hash(),
+ unsigned hashCodes[4] = {
+ key.m_functionName.impl()->hash(),
key.m_url.impl()->hash(),
- key.m_lineNumber
+ key.m_lineNumber,
+ key.m_columnNumber
};
return StringHasher::hashMemory<sizeof(hashCodes)>(hashCodes);
}
@@ -74,8 +79,14 @@ namespace JSC {
#ifndef NDEBUG
operator const char*() const { return c_str(); }
- const char* c_str() const { return m_name.utf8().data(); }
+ const char* c_str() const { return m_functionName.utf8().data(); }
#endif
+
+ private:
+ String m_functionName;
+ String m_url;
+ unsigned m_lineNumber;
+ unsigned m_columnNumber;
};
} // namespace JSC
@@ -87,15 +98,15 @@ namespace WTF {
template<> struct HashTraits<JSC::CallIdentifier> : GenericHashTraits<JSC::CallIdentifier> {
static void constructDeletedValue(JSC::CallIdentifier& slot)
{
- new (NotNull, &slot) JSC::CallIdentifier(String(), String(), std::numeric_limits<unsigned>::max());
+ new (NotNull, &slot) JSC::CallIdentifier(String(), String(), std::numeric_limits<unsigned>::max(), std::numeric_limits<unsigned>::max());
}
+
static bool isDeletedValue(const JSC::CallIdentifier& value)
{
- return value.m_name.isNull() && value.m_url.isNull() && value.m_lineNumber == std::numeric_limits<unsigned>::max();
+ return value.functionName().isNull() && value.url().isNull() && value.lineNumber() == std::numeric_limits<unsigned>::max() && value.columnNumber() == std::numeric_limits<unsigned>::max();
}
};
} // namespace WTF
#endif // CallIdentifier_h
-
diff --git a/Source/JavaScriptCore/profiler/LegacyProfiler.cpp b/Source/JavaScriptCore/profiler/LegacyProfiler.cpp
index dd2acd9f0..787d362dc 100644
--- a/Source/JavaScriptCore/profiler/LegacyProfiler.cpp
+++ b/Source/JavaScriptCore/profiler/LegacyProfiler.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2012, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -36,7 +36,7 @@
#include "JSFunction.h"
#include "JSGlobalObject.h"
#include "Nodes.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "Profile.h"
#include "ProfileGenerator.h"
#include "ProfileNode.h"
@@ -47,21 +47,19 @@ static const char* GlobalCodeExecution = "(program)";
static const char* AnonymousFunction = "(anonymous function)";
static unsigned ProfilesUID = 0;
-static CallIdentifier createCallIdentifierFromFunctionImp(ExecState*, JSObject*, const String& defaultSourceURL, int defaultLineNumber);
+static CallIdentifier createCallIdentifierFromFunctionImp(ExecState*, JSObject*, const String& defaultSourceURL, unsigned defaultLineNumber, unsigned defaultColumnNumber);
-LegacyProfiler* LegacyProfiler::s_sharedLegacyProfiler = 0;
+LegacyProfiler* LegacyProfiler::s_sharedLegacyProfiler = nullptr;
LegacyProfiler* LegacyProfiler::profiler()
{
if (!s_sharedLegacyProfiler)
s_sharedLegacyProfiler = new LegacyProfiler();
return s_sharedLegacyProfiler;
-}
+}
-void LegacyProfiler::startProfiling(ExecState* exec, const String& title)
+void LegacyProfiler::startProfiling(ExecState* exec, const String& title, PassRefPtr<Stopwatch> stopwatch)
{
- ASSERT_ARG(title, !title.isNull());
-
if (!exec)
return;
@@ -76,14 +74,14 @@ void LegacyProfiler::startProfiling(ExecState* exec, const String& title)
}
exec->vm().setEnabledProfiler(this);
- RefPtr<ProfileGenerator> profileGenerator = ProfileGenerator::create(exec, title, ++ProfilesUID);
+ RefPtr<ProfileGenerator> profileGenerator = ProfileGenerator::create(exec, title, ++ProfilesUID, stopwatch);
m_currentProfiles.append(profileGenerator);
}
-PassRefPtr<Profile> LegacyProfiler::stopProfiling(ExecState* exec, const String& title)
+RefPtr<Profile> LegacyProfiler::stopProfiling(ExecState* exec, const String& title)
{
if (!exec)
- return 0;
+ return nullptr;
JSGlobalObject* origin = exec->lexicalGlobalObject();
for (ptrdiff_t i = m_currentProfiles.size() - 1; i >= 0; --i) {
@@ -95,12 +93,12 @@ PassRefPtr<Profile> LegacyProfiler::stopProfiling(ExecState* exec, const String&
m_currentProfiles.remove(i);
if (!m_currentProfiles.size())
exec->vm().setEnabledProfiler(nullptr);
-
+
return returnProfile;
}
}
- return 0;
+ return nullptr;
}
void LegacyProfiler::stopProfiling(JSGlobalObject* origin)
@@ -116,69 +114,95 @@ void LegacyProfiler::stopProfiling(JSGlobalObject* origin)
}
}
-static inline void dispatchFunctionToProfiles(ExecState* callerOrHandlerCallFrame, const Vector<RefPtr<ProfileGenerator>>& profiles, ProfileGenerator::ProfileFunction function, const CallIdentifier& callIdentifier, unsigned currentProfileTargetGroup)
+static inline void callFunctionForProfilesWithGroup(std::function<void(ProfileGenerator*)> callback, const Vector<RefPtr<ProfileGenerator>>& profiles, unsigned targetProfileGroup)
{
- for (size_t i = 0; i < profiles.size(); ++i) {
- if (profiles[i]->profileGroup() == currentProfileTargetGroup || !profiles[i]->origin())
- (profiles[i].get()->*function)(callerOrHandlerCallFrame, callIdentifier);
+ for (const RefPtr<ProfileGenerator>& profile : profiles) {
+ if (profile->profileGroup() == targetProfileGroup || !profile->origin())
+ callback(profile.get());
}
}
+void LegacyProfiler::suspendProfiling(JSC::ExecState* exec)
+{
+ if (!exec)
+ return;
+
+ callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::setIsSuspended, std::placeholders::_1, true), m_currentProfiles, exec->lexicalGlobalObject()->profileGroup());
+}
+
+void LegacyProfiler::unsuspendProfiling(JSC::ExecState* exec)
+{
+ if (!exec)
+ return;
+
+ callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::setIsSuspended, std::placeholders::_1, false), m_currentProfiles, exec->lexicalGlobalObject()->profileGroup());
+}
+
void LegacyProfiler::willExecute(ExecState* callerCallFrame, JSValue function)
{
ASSERT(!m_currentProfiles.isEmpty());
- dispatchFunctionToProfiles(callerCallFrame, m_currentProfiles, &ProfileGenerator::willExecute, createCallIdentifier(callerCallFrame, function, "", 0), callerCallFrame->lexicalGlobalObject()->profileGroup());
+ CallIdentifier callIdentifier = createCallIdentifier(callerCallFrame, function, StringImpl::empty(), 0, 0);
+
+ callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::willExecute, std::placeholders::_1, callerCallFrame, callIdentifier), m_currentProfiles, callerCallFrame->lexicalGlobalObject()->profileGroup());
}
-void LegacyProfiler::willExecute(ExecState* callerCallFrame, const String& sourceURL, int startingLineNumber)
+void LegacyProfiler::willExecute(ExecState* callerCallFrame, const String& sourceURL, unsigned startingLineNumber, unsigned startingColumnNumber)
{
ASSERT(!m_currentProfiles.isEmpty());
- CallIdentifier callIdentifier = createCallIdentifier(callerCallFrame, JSValue(), sourceURL, startingLineNumber);
+ CallIdentifier callIdentifier = createCallIdentifier(callerCallFrame, JSValue(), sourceURL, startingLineNumber, startingColumnNumber);
- dispatchFunctionToProfiles(callerCallFrame, m_currentProfiles, &ProfileGenerator::willExecute, callIdentifier, callerCallFrame->lexicalGlobalObject()->profileGroup());
+ callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::willExecute, std::placeholders::_1, callerCallFrame, callIdentifier), m_currentProfiles, callerCallFrame->lexicalGlobalObject()->profileGroup());
}
void LegacyProfiler::didExecute(ExecState* callerCallFrame, JSValue function)
{
ASSERT(!m_currentProfiles.isEmpty());
- dispatchFunctionToProfiles(callerCallFrame, m_currentProfiles, &ProfileGenerator::didExecute, createCallIdentifier(callerCallFrame, function, "", 0), callerCallFrame->lexicalGlobalObject()->profileGroup());
+ CallIdentifier callIdentifier = createCallIdentifier(callerCallFrame, function, StringImpl::empty(), 0, 0);
+
+ callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::didExecute, std::placeholders::_1, callerCallFrame, callIdentifier), m_currentProfiles, callerCallFrame->lexicalGlobalObject()->profileGroup());
}
-void LegacyProfiler::didExecute(ExecState* callerCallFrame, const String& sourceURL, int startingLineNumber)
+void LegacyProfiler::didExecute(ExecState* callerCallFrame, const String& sourceURL, unsigned startingLineNumber, unsigned startingColumnNumber)
{
ASSERT(!m_currentProfiles.isEmpty());
- dispatchFunctionToProfiles(callerCallFrame, m_currentProfiles, &ProfileGenerator::didExecute, createCallIdentifier(callerCallFrame, JSValue(), sourceURL, startingLineNumber), callerCallFrame->lexicalGlobalObject()->profileGroup());
+ CallIdentifier callIdentifier = createCallIdentifier(callerCallFrame, JSValue(), sourceURL, startingLineNumber, startingColumnNumber);
+
+ callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::didExecute, std::placeholders::_1, callerCallFrame, callIdentifier), m_currentProfiles, callerCallFrame->lexicalGlobalObject()->profileGroup());
}
void LegacyProfiler::exceptionUnwind(ExecState* handlerCallFrame)
{
ASSERT(!m_currentProfiles.isEmpty());
- dispatchFunctionToProfiles(handlerCallFrame, m_currentProfiles, &ProfileGenerator::exceptionUnwind, createCallIdentifier(handlerCallFrame, JSValue(), "", 0), handlerCallFrame->lexicalGlobalObject()->profileGroup());
+ CallIdentifier callIdentifier = createCallIdentifier(handlerCallFrame, JSValue(), StringImpl::empty(), 0, 0);
+
+ callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::exceptionUnwind, std::placeholders::_1, handlerCallFrame, callIdentifier), m_currentProfiles, handlerCallFrame->lexicalGlobalObject()->profileGroup());
}
-CallIdentifier LegacyProfiler::createCallIdentifier(ExecState* exec, JSValue functionValue, const String& defaultSourceURL, int defaultLineNumber)
+CallIdentifier LegacyProfiler::createCallIdentifier(ExecState* exec, JSValue functionValue, const String& defaultSourceURL, unsigned defaultLineNumber, unsigned defaultColumnNumber)
{
if (!functionValue)
- return CallIdentifier(GlobalCodeExecution, defaultSourceURL, defaultLineNumber);
+ return CallIdentifier(ASCIILiteral(GlobalCodeExecution), defaultSourceURL, defaultLineNumber, defaultColumnNumber);
if (!functionValue.isObject())
- return CallIdentifier("(unknown)", defaultSourceURL, defaultLineNumber);
+ 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);
- return CallIdentifier(makeString("(", asObject(functionValue)->methodTable()->className(asObject(functionValue)), " object)"), defaultSourceURL, defaultLineNumber);
+ return createCallIdentifierFromFunctionImp(exec, asObject(functionValue), defaultSourceURL, defaultLineNumber, defaultColumnNumber);
+ if (asObject(functionValue)->inherits(JSCallee::info()))
+ return CallIdentifier(ASCIILiteral(GlobalCodeExecution), defaultSourceURL, defaultLineNumber, defaultColumnNumber);
+ return CallIdentifier(asObject(functionValue)->methodTable()->className(asObject(functionValue)), defaultSourceURL, defaultLineNumber, defaultColumnNumber);
}
-CallIdentifier createCallIdentifierFromFunctionImp(ExecState* exec, JSObject* function, const String& defaultSourceURL, int defaultLineNumber)
+CallIdentifier createCallIdentifierFromFunctionImp(ExecState* exec, JSObject* function, const String& defaultSourceURL, unsigned defaultLineNumber, unsigned defaultColumnNumber)
{
const String& name = getCalculatedDisplayName(exec, function);
JSFunction* jsFunction = jsDynamicCast<JSFunction*>(function);
- if (jsFunction && !jsFunction->isHostFunction())
- return CallIdentifier(name.isEmpty() ? AnonymousFunction : name, jsFunction->jsExecutable()->sourceURL(), jsFunction->jsExecutable()->lineNo());
- return CallIdentifier(name.isEmpty() ? AnonymousFunction : name, defaultSourceURL, defaultLineNumber);
+ if (jsFunction && !jsFunction->isHostOrBuiltinFunction())
+ return CallIdentifier(name.isEmpty() ? ASCIILiteral(AnonymousFunction) : name, jsFunction->jsExecutable()->sourceURL(), jsFunction->jsExecutable()->firstLine(), jsFunction->jsExecutable()->startColumn());
+ return CallIdentifier(name.isEmpty() ? ASCIILiteral(AnonymousFunction) : name, defaultSourceURL, defaultLineNumber, defaultColumnNumber);
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/profiler/LegacyProfiler.h b/Source/JavaScriptCore/profiler/LegacyProfiler.h
index 607ddec9d..af0ab41e2 100644
--- a/Source/JavaScriptCore/profiler/LegacyProfiler.h
+++ b/Source/JavaScriptCore/profiler/LegacyProfiler.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2012, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -32,12 +32,12 @@
#include "Profile.h"
#include <wtf/PassRefPtr.h>
#include <wtf/RefPtr.h>
+#include <wtf/Stopwatch.h>
#include <wtf/Vector.h>
namespace JSC {
class ExecState;
-class VM;
class JSGlobalObject;
class JSObject;
class JSValue;
@@ -47,17 +47,21 @@ struct CallIdentifier;
class LegacyProfiler {
WTF_MAKE_FAST_ALLOCATED;
public:
- JS_EXPORT_PRIVATE static LegacyProfiler* profiler();
- static CallIdentifier createCallIdentifier(ExecState*, JSValue, const WTF::String& sourceURL, int lineNumber);
+ JS_EXPORT_PRIVATE static LegacyProfiler* profiler();
+ static CallIdentifier createCallIdentifier(ExecState*, JSValue, const WTF::String& sourceURL, unsigned defaultLineNumber, unsigned defaultColumnNumber);
- JS_EXPORT_PRIVATE void startProfiling(ExecState*, const WTF::String& title);
- JS_EXPORT_PRIVATE PassRefPtr<Profile> stopProfiling(ExecState*, const WTF::String& title);
+ JS_EXPORT_PRIVATE void startProfiling(ExecState*, const WTF::String& title, PassRefPtr<Stopwatch>);
+ JS_EXPORT_PRIVATE RefPtr<Profile> stopProfiling(ExecState*, const WTF::String& title);
void stopProfiling(JSGlobalObject*);
+ // Used to ignore profile node subtrees rooted at InjectedScript calls.
+ JS_EXPORT_PRIVATE void suspendProfiling(ExecState*);
+ JS_EXPORT_PRIVATE void unsuspendProfiling(ExecState*);
+
void willExecute(ExecState* callerCallFrame, JSValue function);
- void willExecute(ExecState* callerCallFrame, const WTF::String& sourceURL, int startingLineNumber);
+ void willExecute(ExecState* callerCallFrame, const WTF::String& sourceURL, unsigned startingLineNumber, unsigned startingColumnNumber);
void didExecute(ExecState* callerCallFrame, JSValue function);
- void didExecute(ExecState* callerCallFrame, const WTF::String& sourceURL, int startingLineNumber);
+ void didExecute(ExecState* callerCallFrame, const WTF::String& sourceURL, unsigned startingLineNumber, unsigned startingColumnNumber);
void exceptionUnwind(ExecState* handlerCallFrame);
diff --git a/Source/JavaScriptCore/profiler/Profile.cpp b/Source/JavaScriptCore/profiler/Profile.cpp
index ed21e7879..f3d450ab2 100644
--- a/Source/JavaScriptCore/profiler/Profile.cpp
+++ b/Source/JavaScriptCore/profiler/Profile.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008, 2014 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -31,45 +31,34 @@
namespace JSC {
-PassRefPtr<Profile> Profile::create(const String& title, unsigned uid)
+Ref<Profile> Profile::create(const String& title, unsigned uid, double startTime)
{
- return adoptRef(new Profile(title, uid));
+ return adoptRef(*new Profile(title, uid, startTime));
}
-Profile::Profile(const String& title, unsigned uid)
+Profile::Profile(const String& title, unsigned uid, double startTime)
: m_title(title)
, m_uid(uid)
{
// FIXME: When multi-threading is supported this will be a vector and calls
// into the profiler will need to know which thread it is executing on.
- m_head = ProfileNode::create(0, CallIdentifier("Thread_1", String(), 0), 0, 0);
+ m_rootNode = ProfileNode::create(nullptr, CallIdentifier(ASCIILiteral("Thread_1"), String(), 0, 0), nullptr);
+ m_rootNode->appendCall(ProfileNode::Call(startTime));
}
Profile::~Profile()
{
}
-void Profile::forEach(void (ProfileNode::*function)())
-{
- ProfileNode* currentNode = m_head->firstChild();
- for (ProfileNode* nextNode = currentNode; nextNode; nextNode = nextNode->firstChild())
- currentNode = nextNode;
-
- if (!currentNode)
- currentNode = m_head.get();
-
- ProfileNode* endNode = m_head->traverseNextNodePostOrder();
- while (currentNode && currentNode != endNode) {
- (currentNode->*function)();
- currentNode = currentNode->traverseNextNodePostOrder();
- }
-}
-
#ifndef NDEBUG
-void Profile::debugPrintData() const
+void Profile::debugPrint()
{
+ CalculateProfileSubtreeDataFunctor functor;
+ m_rootNode->forEachNodePostorder(functor);
+ ProfileNode::ProfileSubtreeData data = functor.returnValue();
+
dataLogF("Call graph:\n");
- m_head->debugPrintData(0);
+ m_rootNode->debugPrintRecursively(0, data);
}
typedef WTF::KeyValuePair<FunctionCallHashCount::ValueType, unsigned> NameCountPair;
@@ -79,13 +68,17 @@ static inline bool functionNameCountPairComparator(const NameCountPair& a, const
return a.value > b.value;
}
-void Profile::debugPrintDataSampleStyle() const
+void Profile::debugPrintSampleStyle()
{
typedef Vector<NameCountPair> NameCountPairVector;
+ CalculateProfileSubtreeDataFunctor functor;
+ m_rootNode->forEachNodePostorder(functor);
+ ProfileNode::ProfileSubtreeData data = functor.returnValue();
+
FunctionCallHashCount countedFunctions;
dataLogF("Call graph:\n");
- m_head->debugPrintDataSampleStyle(0, countedFunctions);
+ m_rootNode->debugPrintSampleStyleRecursively(0, countedFunctions, data);
dataLogF("\nTotal number in stack:\n");
NameCountPairVector sortedFunctions(countedFunctions.size());
diff --git a/Source/JavaScriptCore/profiler/Profile.h b/Source/JavaScriptCore/profiler/Profile.h
index b1f093d69..41cb670ca 100644
--- a/Source/JavaScriptCore/profiler/Profile.h
+++ b/Source/JavaScriptCore/profiler/Profile.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008, 2014 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -33,35 +33,33 @@
namespace JSC {
- class Profile : public RefCounted<Profile> {
- public:
- static PassRefPtr<Profile> create(const String& title, unsigned uid);
- virtual ~Profile();
+class JS_EXPORT_PRIVATE Profile : public RefCounted<Profile> {
+public:
+ static Ref<Profile> create(const String& title, unsigned uid, double);
+ virtual ~Profile();
- const String& title() const { return m_title; }
- ProfileNode* head() const { return m_head.get(); }
- void setHead(PassRefPtr<ProfileNode> head) { m_head = head; }
- double totalTime() const { return m_head->totalTime(); }
- unsigned int uid() const { return m_uid; }
+ const String& title() const { return m_title; }
+ unsigned uid() const { return m_uid; }
- void forEach(void (ProfileNode::*)());
+ ProfileNode* rootNode() const { return m_rootNode.get(); }
+ void setRootNode(PassRefPtr<ProfileNode> rootNode) { m_rootNode = rootNode; }
#ifndef NDEBUG
- void debugPrintData() const;
- void debugPrintDataSampleStyle() const;
+ void debugPrint();
+ void debugPrintSampleStyle();
#endif
- protected:
- Profile(const String& title, unsigned uid);
+protected:
+ Profile(const String& title, unsigned uid, double startTime);
- private:
- void removeProfileStart();
- void removeProfileEnd();
-
- String m_title;
- RefPtr<ProfileNode> m_head;
- unsigned int m_uid;
- };
+private:
+ void removeProfileStart();
+ void removeProfileEnd();
+
+ String m_title;
+ RefPtr<ProfileNode> m_rootNode;
+ unsigned m_uid;
+};
} // namespace JSC
diff --git a/Source/JavaScriptCore/profiler/ProfileGenerator.cpp b/Source/JavaScriptCore/profiler/ProfileGenerator.cpp
index 9361caf70..f70e4a3f6 100644
--- a/Source/JavaScriptCore/profiler/ProfileGenerator.cpp
+++ b/Source/JavaScriptCore/profiler/ProfileGenerator.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008, 2014 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,44 +27,46 @@
#include "ProfileGenerator.h"
#include "CallFrame.h"
-#include "CallFrameInlines.h"
#include "CodeBlock.h"
#include "JSGlobalObject.h"
#include "JSStringRef.h"
#include "JSFunction.h"
#include "LegacyProfiler.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "Profile.h"
#include "StackVisitor.h"
#include "Tracing.h"
namespace JSC {
-static const char* NonJSExecution = "(idle)";
-
-PassRefPtr<ProfileGenerator> ProfileGenerator::create(ExecState* exec, const String& title, unsigned uid)
+Ref<ProfileGenerator> ProfileGenerator::create(ExecState* exec, const String& title, unsigned uid, PassRefPtr<Stopwatch> stopwatch)
{
- return adoptRef(new ProfileGenerator(exec, title, uid));
+ return adoptRef(*new ProfileGenerator(exec, title, uid, stopwatch));
}
-ProfileGenerator::ProfileGenerator(ExecState* exec, const String& title, unsigned uid)
- : m_origin(exec ? exec->lexicalGlobalObject() : 0)
+ProfileGenerator::ProfileGenerator(ExecState* exec, const String& title, unsigned uid, PassRefPtr<Stopwatch> stopwatch)
+ : m_origin(exec ? exec->lexicalGlobalObject() : nullptr)
, m_profileGroup(exec ? exec->lexicalGlobalObject()->profileGroup() : 0)
+ , m_stopwatch(stopwatch)
+ , m_foundConsoleStartParent(false)
+ , m_suspended(false)
{
- m_profile = Profile::create(title, uid);
- m_currentNode = m_head = m_profile->head();
+ double startTime = m_stopwatch->elapsedTime();
+ m_profile = Profile::create(title, uid, startTime);
+ m_currentNode = m_rootNode = m_profile->rootNode();
if (exec)
- addParentForConsoleStart(exec);
+ addParentForConsoleStart(exec, startTime);
}
class AddParentForConsoleStartFunctor {
public:
- AddParentForConsoleStartFunctor(ExecState* exec, RefPtr<ProfileNode>& head, RefPtr<ProfileNode>& currentNode)
+ AddParentForConsoleStartFunctor(ExecState* exec, RefPtr<ProfileNode>& rootNode, RefPtr<ProfileNode>& currentNode, double startTime)
: m_exec(exec)
, m_hasSkippedFirstFrame(false)
, m_foundParent(false)
- , m_head(head)
+ , m_rootNode(rootNode)
, m_currentNode(currentNode)
+ , m_startTime(startTime)
{
}
@@ -78,10 +80,11 @@ public:
}
unsigned line = 0;
- unsigned unusedColumn = 0;
- visitor->computeLineAndColumn(line, unusedColumn);
- m_currentNode = ProfileNode::create(m_exec, LegacyProfiler::createCallIdentifier(m_exec, visitor->callee(), visitor->sourceURL(), line), m_head.get(), m_head.get());
- m_head->insertNode(m_currentNode.get());
+ 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;
@@ -90,20 +93,18 @@ public:
private:
ExecState* m_exec;
bool m_hasSkippedFirstFrame;
- bool m_foundParent;
- RefPtr<ProfileNode>& m_head;
+ bool m_foundParent;
+ RefPtr<ProfileNode>& m_rootNode;
RefPtr<ProfileNode>& m_currentNode;
+ double m_startTime;
};
-void ProfileGenerator::addParentForConsoleStart(ExecState* exec)
+void ProfileGenerator::addParentForConsoleStart(ExecState* exec, double startTime)
{
- AddParentForConsoleStartFunctor functor(exec, m_head, m_currentNode);
+ AddParentForConsoleStartFunctor functor(exec, m_rootNode, m_currentNode, startTime);
exec->iterate(functor);
- if (!functor.foundParent()) {
- m_currentNode = ProfileNode::create(exec, LegacyProfiler::createCallIdentifier(exec, JSValue(), String(), 0), m_head.get(), m_head.get());
- m_head->insertNode(m_currentNode.get());
- }
+ m_foundConsoleStartParent = functor.foundParent();
}
const String& ProfileGenerator::title() const
@@ -111,46 +112,92 @@ const String& ProfileGenerator::title() const
return m_profile->title();
}
+void ProfileGenerator::beginCallEntry(ProfileNode* node, double startTime)
+{
+ ASSERT_ARG(node, node);
+
+ if (std::isnan(startTime))
+ startTime = m_stopwatch->elapsedTime();
+
+ node->appendCall(ProfileNode::Call(startTime));
+}
+
+void ProfileGenerator::endCallEntry(ProfileNode* node)
+{
+ ASSERT_ARG(node, node);
+
+ ProfileNode::Call& last = node->lastCall();
+
+ double previousElapsedTime = std::isnan(last.elapsedTime()) ? 0.0 : last.elapsedTime();
+ double newlyElapsedTime = m_stopwatch->elapsedTime() - last.startTime();
+ last.setElapsedTime(previousElapsedTime + newlyElapsedTime);
+}
+
void ProfileGenerator::willExecute(ExecState* callerCallFrame, const CallIdentifier& callIdentifier)
{
if (JAVASCRIPTCORE_PROFILE_WILL_EXECUTE_ENABLED()) {
- CString name = callIdentifier.m_name.utf8();
- CString url = callIdentifier.m_url.utf8();
- JAVASCRIPTCORE_PROFILE_WILL_EXECUTE(m_profileGroup, const_cast<char*>(name.data()), const_cast<char*>(url.data()), callIdentifier.m_lineNumber);
+ CString name = callIdentifier.functionName().utf8();
+ CString url = callIdentifier.url().utf8();
+ JAVASCRIPTCORE_PROFILE_WILL_EXECUTE(m_profileGroup, const_cast<char*>(name.data()), const_cast<char*>(url.data()), callIdentifier.lineNumber(), callIdentifier.columnNumber());
}
if (!m_origin)
return;
- ASSERT(m_currentNode);
- m_currentNode = m_currentNode->willExecute(callerCallFrame, callIdentifier);
+ if (m_suspended)
+ return;
+
+ RefPtr<ProfileNode> calleeNode = nullptr;
+
+ // Find or create a node for the callee call frame.
+ for (const RefPtr<ProfileNode>& child : m_currentNode->children()) {
+ if (child->callIdentifier() == callIdentifier)
+ calleeNode = child;
+ }
+
+ if (!calleeNode) {
+ calleeNode = ProfileNode::create(callerCallFrame, callIdentifier, m_currentNode.get());
+ m_currentNode->addChild(calleeNode);
+ }
+
+ m_currentNode = calleeNode;
+ beginCallEntry(calleeNode.get(), m_stopwatch->elapsedTime());
}
void ProfileGenerator::didExecute(ExecState* callerCallFrame, const CallIdentifier& callIdentifier)
{
if (JAVASCRIPTCORE_PROFILE_DID_EXECUTE_ENABLED()) {
- CString name = callIdentifier.m_name.utf8();
- CString url = callIdentifier.m_url.utf8();
- JAVASCRIPTCORE_PROFILE_DID_EXECUTE(m_profileGroup, const_cast<char*>(name.data()), const_cast<char*>(url.data()), callIdentifier.m_lineNumber);
+ CString name = callIdentifier.functionName().utf8();
+ CString url = callIdentifier.url().utf8();
+ JAVASCRIPTCORE_PROFILE_DID_EXECUTE(m_profileGroup, const_cast<char*>(name.data()), const_cast<char*>(url.data()), callIdentifier.lineNumber(), callIdentifier.columnNumber());
}
if (!m_origin)
return;
+ if (m_suspended)
+ return;
+
+ // Make a new node if the caller node has never seen this callee call frame before.
+ // This can happen if |console.profile()| is called several frames deep in the call stack.
ASSERT(m_currentNode);
if (m_currentNode->callIdentifier() != callIdentifier) {
- RefPtr<ProfileNode> returningNode = ProfileNode::create(callerCallFrame, callIdentifier, m_head.get(), m_currentNode.get());
- returningNode->setStartTime(m_currentNode->startTime());
- returningNode->didExecute();
- m_currentNode->insertNode(returningNode.release());
+ RefPtr<ProfileNode> calleeNode = ProfileNode::create(callerCallFrame, callIdentifier, m_currentNode.get());
+ beginCallEntry(calleeNode.get(), m_currentNode->lastCall().startTime());
+ endCallEntry(calleeNode.get());
+ m_currentNode->spliceNode(calleeNode.release());
return;
}
- m_currentNode = m_currentNode->didExecute();
+ endCallEntry(m_currentNode.get());
+ m_currentNode = m_currentNode->parent();
}
void ProfileGenerator::exceptionUnwind(ExecState* handlerCallFrame, const CallIdentifier&)
{
+ if (m_suspended)
+ return;
+
// If the current node was called by the handler (==) or any
// more nested function (>) the we have exited early from it.
ASSERT(m_currentNode);
@@ -162,56 +209,44 @@ void ProfileGenerator::exceptionUnwind(ExecState* handlerCallFrame, const CallId
void ProfileGenerator::stopProfiling()
{
- m_profile->forEach(&ProfileNode::stopProfiling);
+ for (ProfileNode* node = m_currentNode.get(); node != m_profile->rootNode(); node = node->parent())
+ endCallEntry(node);
- removeProfileStart();
- removeProfileEnd();
+ if (m_foundConsoleStartParent) {
+ removeProfileStart();
+ removeProfileEnd();
+ }
ASSERT(m_currentNode);
// Set the current node to the parent, because we are in a call that
// will not get didExecute call.
m_currentNode = m_currentNode->parent();
-
- if (double headSelfTime = m_head->selfTime()) {
- RefPtr<ProfileNode> idleNode = ProfileNode::create(0, CallIdentifier(NonJSExecution, String(), 0), m_head.get(), m_head.get());
-
- idleNode->setTotalTime(headSelfTime);
- idleNode->setSelfTime(headSelfTime);
-
- m_head->setSelfTime(0.0);
- m_head->addChild(idleNode.release());
- }
}
// The console.profile that started this ProfileGenerator will be the first child.
void ProfileGenerator::removeProfileStart()
{
- ProfileNode* currentNode = 0;
- for (ProfileNode* next = m_head.get(); next; next = next->firstChild())
+ ProfileNode* currentNode = nullptr;
+ for (ProfileNode* next = m_rootNode.get(); next; next = next->firstChild())
currentNode = next;
- if (currentNode->callIdentifier().m_name != "profile")
+ if (currentNode->callIdentifier().functionName() != "profile")
return;
- // Attribute the time of the node aobut to be removed to the self time of its parent
- currentNode->parent()->setSelfTime(currentNode->parent()->selfTime() + currentNode->totalTime());
currentNode->parent()->removeChild(currentNode);
}
// The console.profileEnd that stopped this ProfileGenerator will be the last child.
void ProfileGenerator::removeProfileEnd()
{
- ProfileNode* currentNode = 0;
- for (ProfileNode* next = m_head.get(); next; next = next->lastChild())
+ ProfileNode* currentNode = nullptr;
+ for (ProfileNode* next = m_rootNode.get(); next; next = next->lastChild())
currentNode = next;
- if (currentNode->callIdentifier().m_name != "profileEnd")
+ if (currentNode->callIdentifier().functionName() != "profileEnd")
return;
- // Attribute the time of the node aobut to be removed to the self time of its parent
- currentNode->parent()->setSelfTime(currentNode->parent()->selfTime() + currentNode->totalTime());
-
ASSERT(currentNode->callIdentifier() == (currentNode->parent()->children()[currentNode->parent()->children().size() - 1])->callIdentifier());
currentNode->parent()->removeChild(currentNode);
}
diff --git a/Source/JavaScriptCore/profiler/ProfileGenerator.h b/Source/JavaScriptCore/profiler/ProfileGenerator.h
index 40cc8de01..387ed5f4a 100644
--- a/Source/JavaScriptCore/profiler/ProfileGenerator.h
+++ b/Source/JavaScriptCore/profiler/ProfileGenerator.h
@@ -22,26 +22,28 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
+
#ifndef ProfileGenerator_h
#define ProfileGenerator_h
-#include "Profile.h"
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
+#include <wtf/Stopwatch.h>
+#include <wtf/text/WTFString.h>
namespace JSC {
+ class DebuggerCallFrame;
class ExecState;
class JSGlobalObject;
class Profile;
class ProfileNode;
- struct CallIdentifier;
+ struct CallIdentifier;
class ProfileGenerator : public RefCounted<ProfileGenerator> {
public:
- static PassRefPtr<ProfileGenerator> create(ExecState*, const WTF::String& title, unsigned uid);
+ static Ref<ProfileGenerator> create(ExecState*, const WTF::String& title, unsigned uid, PassRefPtr<Stopwatch>);
// Members
const WTF::String& title() const;
@@ -49,29 +51,32 @@ namespace JSC {
JSGlobalObject* origin() const { return m_origin; }
unsigned profileGroup() const { return m_profileGroup; }
- // Collecting
void willExecute(ExecState* callerCallFrame, const CallIdentifier&);
void didExecute(ExecState* callerCallFrame, const CallIdentifier&);
-
void exceptionUnwind(ExecState* handlerCallFrame, const CallIdentifier&);
- // Stopping Profiling
- void stopProfiling();
+ void setIsSuspended(bool suspended) { ASSERT(m_suspended != suspended); m_suspended = suspended; }
- typedef void (ProfileGenerator::*ProfileFunction)(ExecState* callerOrHandlerCallFrame, const CallIdentifier& callIdentifier);
+ void stopProfiling();
private:
- ProfileGenerator(ExecState*, const WTF::String& title, unsigned uid);
- void addParentForConsoleStart(ExecState*);
+ ProfileGenerator(ExecState*, const WTF::String& title, unsigned uid, PassRefPtr<Stopwatch>);
+ void addParentForConsoleStart(ExecState*, double);
void removeProfileStart();
void removeProfileEnd();
+ void beginCallEntry(ProfileNode*, double startTime);
+ void endCallEntry(ProfileNode*);
+
RefPtr<Profile> m_profile;
JSGlobalObject* m_origin;
unsigned m_profileGroup;
- RefPtr<ProfileNode> m_head;
+ RefPtr<Stopwatch> m_stopwatch;
+ RefPtr<ProfileNode> m_rootNode;
RefPtr<ProfileNode> m_currentNode;
+ bool m_foundConsoleStartParent;
+ bool m_suspended;
};
} // namespace JSC
diff --git a/Source/JavaScriptCore/profiler/ProfileNode.cpp b/Source/JavaScriptCore/profiler/ProfileNode.cpp
index fe2342ea4..9bcf37586 100644
--- a/Source/JavaScriptCore/profiler/ProfileNode.cpp
+++ b/Source/JavaScriptCore/profiler/ProfileNode.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -34,83 +34,39 @@
#include <wtf/DataLog.h>
#include <wtf/text/StringHash.h>
-#if OS(WINDOWS)
-#include <windows.h>
-#endif
-
using namespace WTF;
namespace JSC {
-static double getCount()
-{
-#if OS(WINDOWS)
- static LARGE_INTEGER frequency;
- if (!frequency.QuadPart)
- QueryPerformanceFrequency(&frequency);
- LARGE_INTEGER counter;
- QueryPerformanceCounter(&counter);
- return static_cast<double>(counter.QuadPart) / frequency.QuadPart;
-#else
- return currentTimeMS();
-#endif
-}
-
-ProfileNode::ProfileNode(ExecState* callerCallFrame, const CallIdentifier& callIdentifier, ProfileNode* headNode, ProfileNode* parentNode)
+ProfileNode::ProfileNode(ExecState* callerCallFrame, const CallIdentifier& callIdentifier, ProfileNode* parentNode)
: m_callerCallFrame(callerCallFrame)
, m_callIdentifier(callIdentifier)
- , m_head(headNode)
, m_parent(parentNode)
- , m_nextSibling(0)
- , m_startTime(0.0)
- , m_totalTime(0.0)
- , m_selfTime(0.0)
- , m_numberOfCalls(0)
+#ifndef NDEBUG
+ , m_nextSibling(nullptr)
+#endif
{
- startTimer();
}
-ProfileNode::ProfileNode(ExecState* callerCallFrame, ProfileNode* headNode, ProfileNode* nodeToCopy)
+ProfileNode::ProfileNode(ExecState* callerCallFrame, ProfileNode* nodeToCopy)
: m_callerCallFrame(callerCallFrame)
, m_callIdentifier(nodeToCopy->callIdentifier())
- , m_head(headNode)
, m_parent(nodeToCopy->parent())
- , m_nextSibling(0)
- , m_startTime(0.0)
- , m_totalTime(nodeToCopy->totalTime())
- , m_selfTime(nodeToCopy->selfTime())
- , m_numberOfCalls(nodeToCopy->numberOfCalls())
-{
-}
-
-ProfileNode* ProfileNode::willExecute(ExecState* callerCallFrame, const CallIdentifier& callIdentifier)
-{
- for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild) {
- if ((*currentChild)->callIdentifier() == callIdentifier) {
- (*currentChild)->startTimer();
- return (*currentChild).get();
- }
- }
-
- RefPtr<ProfileNode> newChild = ProfileNode::create(callerCallFrame, callIdentifier, m_head ? m_head : this, this); // If this ProfileNode has no head it is the head.
- if (m_children.size())
- m_children.last()->setNextSibling(newChild.get());
- m_children.append(newChild.release());
- return m_children.last().get();
-}
-
-ProfileNode* ProfileNode::didExecute()
+ , m_calls(nodeToCopy->calls())
+#ifndef NDEBUG
+ , m_nextSibling(nullptr)
+#endif
{
- endAndRecordCall();
- return m_parent;
}
void ProfileNode::addChild(PassRefPtr<ProfileNode> prpChild)
{
RefPtr<ProfileNode> child = prpChild;
child->setParent(this);
+#ifndef NDEBUG
if (m_children.size())
m_children.last()->setNextSibling(child.get());
+#endif
m_children.append(child.release());
}
@@ -119,17 +75,18 @@ void ProfileNode::removeChild(ProfileNode* node)
if (!node)
return;
- for (size_t i = 0; i < m_children.size(); ++i) {
- if (*node == m_children[i].get()) {
- m_children.remove(i);
- break;
- }
- }
-
- resetChildrensSiblings();
+ m_children.removeFirstMatching([node] (const RefPtr<ProfileNode>& current) {
+ return *node == current.get();
+ });
+
+#ifndef NDEBUG
+ size_t size = m_children.size();
+ for (size_t i = 0; i < size; ++i)
+ m_children[i]->setNextSibling(i + 1 == size ? nullptr : m_children[i + 1].get());
+#endif
}
-void ProfileNode::insertNode(PassRefPtr<ProfileNode> prpNode)
+void ProfileNode::spliceNode(PassRefPtr<ProfileNode> prpNode)
{
RefPtr<ProfileNode> node = prpNode;
@@ -140,21 +97,7 @@ void ProfileNode::insertNode(PassRefPtr<ProfileNode> prpNode)
m_children.append(node.release());
}
-void ProfileNode::stopProfiling()
-{
- if (m_startTime)
- endAndRecordCall();
-
- ASSERT(m_selfTime == 0.0 && m_startTime == 0.0);
-
- // Because we iterate in post order all of our children have been stopped before us.
- for (unsigned i = 0; i < m_children.size(); ++i)
- m_selfTime += m_children[i]->totalTime();
-
- ASSERT(m_selfTime <= m_totalTime);
- m_selfTime = m_totalTime - m_selfTime;
-}
-
+#ifndef NDEBUG
ProfileNode* ProfileNode::traverseNextNodePostOrder() const
{
ProfileNode* next = m_nextSibling;
@@ -165,54 +108,63 @@ ProfileNode* ProfileNode::traverseNextNodePostOrder() const
return next;
}
-void ProfileNode::endAndRecordCall()
+void ProfileNode::debugPrint()
{
- m_totalTime += m_startTime ? getCount() - m_startTime : 0.0;
- m_startTime = 0.0;
+ CalculateProfileSubtreeDataFunctor functor;
+ forEachNodePostorder(functor);
+ ProfileNode::ProfileSubtreeData data = functor.returnValue();
- ++m_numberOfCalls;
+ debugPrintRecursively(0, data);
}
-void ProfileNode::startTimer()
+void ProfileNode::debugPrintSampleStyle()
{
- if (!m_startTime)
- m_startTime = getCount();
-}
+ FunctionCallHashCount countedFunctions;
-void ProfileNode::resetChildrensSiblings()
-{
- unsigned size = m_children.size();
- for (unsigned i = 0; i < size; ++i)
- m_children[i]->setNextSibling(i + 1 == size ? 0 : m_children[i + 1].get());
+ CalculateProfileSubtreeDataFunctor functor;
+ forEachNodePostorder(functor);
+ ProfileNode::ProfileSubtreeData data = functor.returnValue();
+
+ debugPrintSampleStyleRecursively(0, countedFunctions, data);
}
-#ifndef NDEBUG
-void ProfileNode::debugPrintData(int indentLevel) const
+void ProfileNode::debugPrintRecursively(int indentLevel, const ProfileSubtreeData& data)
{
// Print function names
for (int i = 0; i < indentLevel; ++i)
dataLogF(" ");
- dataLogF("Function Name %s %d SelfTime %.3fms/%.3f%% TotalTime %.3fms/%.3f%% Next Sibling %s\n",
- functionName().utf8().data(),
- m_numberOfCalls, m_selfTime, selfPercent(), m_totalTime, totalPercent(),
+ auto it = data.selfAndTotalTimes.find(this);
+ ASSERT(it != data.selfAndTotalTimes.end());
+
+ double nodeSelfTime = it->value.first;
+ double nodeTotalTime = it->value.second;
+ double rootTotalTime = data.rootTotalTime;
+
+ dataLogF("Function Name %s %zu SelfTime %.3fms/%.3f%% TotalTime %.3fms/%.3f%% Next Sibling %s\n",
+ functionName().utf8().data(),
+ m_calls.size(), nodeSelfTime, nodeSelfTime / rootTotalTime * 100.0, nodeTotalTime, nodeTotalTime / rootTotalTime * 100.0,
m_nextSibling ? m_nextSibling->functionName().utf8().data() : "");
++indentLevel;
// Print children's names and information
for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild)
- (*currentChild)->debugPrintData(indentLevel);
+ (*currentChild)->debugPrintRecursively(indentLevel, data);
}
// print the profiled data in a format that matches the tool sample's output.
-double ProfileNode::debugPrintDataSampleStyle(int indentLevel, FunctionCallHashCount& countedFunctions) const
+double ProfileNode::debugPrintSampleStyleRecursively(int indentLevel, FunctionCallHashCount& countedFunctions, const ProfileSubtreeData& data)
{
dataLogF(" ");
+ auto it = data.selfAndTotalTimes.find(this);
+ ASSERT(it != data.selfAndTotalTimes.end());
+ double nodeTotalTime = it->value.second;
+
// Print function names
const char* name = functionName().utf8().data();
- double sampleCount = m_totalTime * 1000;
+ double sampleCount = nodeTotalTime * 1000;
if (indentLevel) {
for (int i = 0; i < indentLevel; ++i)
dataLogF(" ");
@@ -228,7 +180,7 @@ double ProfileNode::debugPrintDataSampleStyle(int indentLevel, FunctionCallHashC
// Print children's names and information
double sumOfChildrensCount = 0.0;
for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild)
- sumOfChildrensCount += (*currentChild)->debugPrintDataSampleStyle(indentLevel, countedFunctions);
+ sumOfChildrensCount += (*currentChild)->debugPrintSampleStyleRecursively(indentLevel, countedFunctions, data);
sumOfChildrensCount *= 1000; //
// Print remainder of samples to match sample's output
@@ -240,7 +192,7 @@ double ProfileNode::debugPrintDataSampleStyle(int indentLevel, FunctionCallHashC
dataLogF("%.0f %s\n", sampleCount - sumOfChildrensCount, functionName().utf8().data());
}
- return m_totalTime;
+ return nodeTotalTime;
}
#endif
diff --git a/Source/JavaScriptCore/profiler/ProfileNode.h b/Source/JavaScriptCore/profiler/ProfileNode.h
index e21b42282..7ad149e17 100644
--- a/Source/JavaScriptCore/profiler/ProfileNode.h
+++ b/Source/JavaScriptCore/profiler/ProfileNode.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,7 +10,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
@@ -44,96 +44,150 @@ namespace JSC {
class ProfileNode : public RefCounted<ProfileNode> {
public:
- static PassRefPtr<ProfileNode> create(ExecState* callerCallFrame, const CallIdentifier& callIdentifier, ProfileNode* headNode, ProfileNode* parentNode)
+ static Ref<ProfileNode> create(ExecState* callerCallFrame, const CallIdentifier& callIdentifier, ProfileNode* parentNode)
{
- return adoptRef(new ProfileNode(callerCallFrame, callIdentifier, headNode, parentNode));
+ return adoptRef(*new ProfileNode(callerCallFrame, callIdentifier, parentNode));
}
- static PassRefPtr<ProfileNode> create(ExecState* callerCallFrame, ProfileNode* headNode, ProfileNode* node)
+ static Ref<ProfileNode> create(ExecState* callerCallFrame, ProfileNode* node)
{
- return adoptRef(new ProfileNode(callerCallFrame, headNode, node));
+ return adoptRef(*new ProfileNode(callerCallFrame, node));
}
- bool operator==(ProfileNode* node) { return m_callIdentifier == node->callIdentifier(); }
-
- ProfileNode* willExecute(ExecState* callerCallFrame, const CallIdentifier&);
- ProfileNode* didExecute();
+ struct Call {
+ public:
+ Call(double startTime, double elapsedTime = NAN)
+ : m_startTime(startTime)
+ , m_elapsedTime(elapsedTime)
+ {
+ }
+
+ double startTime() const { return m_startTime; }
+ void setStartTime(double time)
+ {
+ ASSERT_ARG(time, time >= 0.0 || std::isnan(time));
+ m_startTime = time;
+ }
+
+ double elapsedTime() const { return m_elapsedTime; }
+ void setElapsedTime(double time)
+ {
+ ASSERT_ARG(time, time >= 0.0 || std::isnan(time));
+ m_elapsedTime = time;
+ }
+
+ private:
+ double m_startTime;
+ double m_elapsedTime;
+ };
- void stopProfiling();
+ bool operator==(ProfileNode* node) { return m_callIdentifier == node->callIdentifier(); }
- // CallIdentifier members
ExecState* callerCallFrame() const { return m_callerCallFrame; }
const CallIdentifier& callIdentifier() const { return m_callIdentifier; }
- unsigned long callUID() const { return m_callIdentifier.hash(); };
- const String& functionName() const { return m_callIdentifier.m_name; }
- const String& url() const { return m_callIdentifier.m_url; }
- unsigned lineNumber() const { return m_callIdentifier.m_lineNumber; }
-
- // Relationships
- ProfileNode* head() const { return m_head; }
- void setHead(ProfileNode* head) { m_head = head; }
+ unsigned id() const { return m_callIdentifier.hash(); }
+ const String& functionName() const { return m_callIdentifier.functionName(); }
+ const String& url() const { return m_callIdentifier.url(); }
+ unsigned lineNumber() const { return m_callIdentifier.lineNumber(); }
+ unsigned columnNumber() const { return m_callIdentifier.columnNumber(); }
ProfileNode* parent() const { return m_parent; }
void setParent(ProfileNode* parent) { m_parent = parent; }
- ProfileNode* nextSibling() const { return m_nextSibling; }
- void setNextSibling(ProfileNode* nextSibling) { m_nextSibling = nextSibling; }
-
- // Time members
- double startTime() const { return m_startTime; }
- void setStartTime(double startTime) { m_startTime = startTime; }
-
- double totalTime() const { return m_totalTime; }
- void setTotalTime(double time) { m_totalTime = time; }
-
- double selfTime() const { return m_selfTime; }
- void setSelfTime(double time) { m_selfTime = time; }
+ 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); }
- double totalPercent() const { return (m_totalTime / (m_head ? m_head->totalTime() : totalTime())) * 100.0; }
- double selfPercent() const { return (m_selfTime / (m_head ? m_head->totalTime() : totalTime())) * 100.0; }
-
- unsigned numberOfCalls() const { return m_numberOfCalls; }
-
- // Children members
const Vector<RefPtr<ProfileNode>>& children() const { return m_children; }
- ProfileNode* firstChild() const { return m_children.size() ? m_children.first().get() : 0; }
- ProfileNode* lastChild() const { return m_children.size() ? m_children.last().get() : 0; }
+ 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> prpChild);
- void insertNode(PassRefPtr<ProfileNode> prpNode);
+ void addChild(PassRefPtr<ProfileNode>);
+ // Reparent our child nodes to the passed node, and make it a child node of |this|.
+ void spliceNode(PassRefPtr<ProfileNode>);
- ProfileNode* traverseNextNodePostOrder() const;
+#ifndef NDEBUG
+ struct ProfileSubtreeData {
+ HashMap<ProfileNode*, std::pair<double, double>> selfAndTotalTimes;
+ double rootTotalTime;
+ };
- void endAndRecordCall();
+ // Use these functions to dump the subtree rooted at this node.
+ void debugPrint();
+ void debugPrintSampleStyle();
-#ifndef NDEBUG
- const char* c_str() const { return m_callIdentifier; }
- void debugPrintData(int indentLevel) const;
- double debugPrintDataSampleStyle(int indentLevel, FunctionCallHashCount&) const;
+ // 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* headNode, ProfileNode* parentNode);
- ProfileNode(ExecState* callerCallFrame, ProfileNode* headNode, ProfileNode* nodeToCopy);
+ 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; }
- void startTimer();
- void resetChildrensSiblings();
+ ProfileNode* traverseNextNodePostOrder() const;
+#endif
ExecState* m_callerCallFrame;
CallIdentifier m_callIdentifier;
- ProfileNode* m_head;
ProfileNode* m_parent;
+ Vector<Call> m_calls;
+ Vector<RefPtr<ProfileNode>> m_children;
+
+#ifndef NDEBUG
ProfileNode* m_nextSibling;
+#endif
+ };
- double m_startTime;
- double m_totalTime;
- double m_selfTime;
- unsigned m_numberOfCalls;
+#ifndef NDEBUG
+ template <typename Functor> inline void ProfileNode::forEachNodePostorder(Functor& functor)
+ {
+ ProfileNode* currentNode = this;
+ // Go down to the first node of the traversal, and slowly walk back up.
+ for (ProfileNode* nextNode = currentNode; nextNode; nextNode = nextNode->firstChild())
+ currentNode = nextNode;
+
+ ProfileNode* endNode = this;
+ while (currentNode && currentNode != endNode) {
+ functor(currentNode);
+ currentNode = currentNode->traverseNextNodePostOrder();
+ }
- Vector<RefPtr<ProfileNode>> m_children;
+ 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 WTFMove(m_data); }
+
+ ProfileNode::ProfileSubtreeData m_data;
};
+#endif
} // namespace JSC
diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecode.cpp b/Source/JavaScriptCore/profiler/ProfilerBytecode.cpp
index ca602e42f..6eeeb27b9 100644
--- a/Source/JavaScriptCore/profiler/ProfilerBytecode.cpp
+++ b/Source/JavaScriptCore/profiler/ProfilerBytecode.cpp
@@ -28,7 +28,7 @@
#include "JSGlobalObject.h"
#include "ObjectConstructor.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC { namespace Profiler {
diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp b/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp
index 838153bea..145ee44d1 100644
--- a/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp
+++ b/Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,7 +29,7 @@
#include "CodeBlock.h"
#include "JSGlobalObject.h"
#include "Operands.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include <wtf/StringPrintStream.h>
namespace JSC { namespace Profiler {
@@ -44,13 +44,16 @@ BytecodeSequence::BytecodeSequence(CodeBlock* codeBlock)
if (!description.length())
continue;
out.reset();
- out.print("arg", i, " (r", virtualRegisterForArgument(i).offset(), "): ", description);
+ out.print("arg", i, ": ", description);
m_header.append(out.toCString());
}
+ StubInfoMap stubInfos;
+ codeBlock->getStubInfoMap(stubInfos);
+
for (unsigned bytecodeIndex = 0; bytecodeIndex < codeBlock->instructions().size();) {
out.reset();
- codeBlock->dumpBytecode(out, bytecodeIndex);
+ codeBlock->dumpBytecode(out, bytecodeIndex, stubInfos);
m_sequence.append(Bytecode(bytecodeIndex, codeBlock->vm()->interpreter->getOpcodeID(codeBlock->instructions()[bytecodeIndex].u.opcode), out.toCString()));
bytecodeIndex += opcodeLength(
codeBlock->vm()->interpreter->getOpcodeID(
diff --git a/Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp b/Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp
index aa5a6d9c9..74c55abcf 100644
--- a/Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp
+++ b/Source/JavaScriptCore/profiler/ProfilerBytecodes.cpp
@@ -29,7 +29,7 @@
#include "CodeBlock.h"
#include "JSGlobalObject.h"
#include "ObjectConstructor.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include <wtf/StringPrintStream.h>
namespace JSC { namespace Profiler {
diff --git a/Source/JavaScriptCore/profiler/ProfilerCompilation.cpp b/Source/JavaScriptCore/profiler/ProfilerCompilation.cpp
index 55766ce5c..488f563de 100644
--- a/Source/JavaScriptCore/profiler/ProfilerCompilation.cpp
+++ b/Source/JavaScriptCore/profiler/ProfilerCompilation.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,8 +28,9 @@
#include "JSGlobalObject.h"
#include "ObjectConstructor.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "ProfilerDatabase.h"
+#include "Watchpoint.h"
#include <wtf/StringPrintStream.h>
namespace JSC { namespace Profiler {
@@ -37,6 +38,7 @@ namespace JSC { namespace Profiler {
Compilation::Compilation(Bytecodes* bytecodes, CompilationKind kind)
: m_bytecodes(bytecodes)
, m_kind(kind)
+ , m_jettisonReason(NotJettisoned)
, m_numInlinedGetByIds(0)
, m_numInlinedPutByIds(0)
, m_numInlinedCalls(0)
@@ -67,6 +69,11 @@ void Compilation::addDescription(const CompiledBytecode& compiledBytecode)
m_descriptions.append(compiledBytecode);
}
+void Compilation::addDescription(const OriginStack& stack, const CString& description)
+{
+ addDescription(CompiledBytecode(stack, description));
+}
+
ExecutionCounter* Compilation::executionCounterFor(const OriginStack& origin)
{
std::unique_ptr<ExecutionCounter>& counter = m_counters.add(origin, nullptr).iterator->value;
@@ -87,6 +94,18 @@ OSRExit* Compilation::addOSRExit(unsigned id, const OriginStack& originStack, Ex
return &m_osrExits.last();
}
+void Compilation::setJettisonReason(JettisonReason jettisonReason, const FireDetail* detail)
+{
+ if (m_jettisonReason != NotJettisoned)
+ return; // We only care about the original jettison reason.
+
+ m_jettisonReason = jettisonReason;
+ if (detail)
+ m_additionalJettisonReason = toCString(*detail);
+ else
+ m_additionalJettisonReason = CString();
+}
+
JSValue Compilation::toJS(ExecState* exec) const
{
JSObject* result = constructEmptyObject(exec);
@@ -126,6 +145,9 @@ JSValue Compilation::toJS(ExecState* exec) const
result->putDirect(exec->vm(), exec->propertyNames().numInlinedGetByIds, jsNumber(m_numInlinedGetByIds));
result->putDirect(exec->vm(), exec->propertyNames().numInlinedPutByIds, jsNumber(m_numInlinedPutByIds));
result->putDirect(exec->vm(), exec->propertyNames().numInlinedCalls, jsNumber(m_numInlinedCalls));
+ result->putDirect(exec->vm(), exec->propertyNames().jettisonReason, jsString(exec, String::fromUTF8(toCString(m_jettisonReason))));
+ if (!m_additionalJettisonReason.isNull())
+ result->putDirect(exec->vm(), exec->propertyNames().additionalJettisonReason, jsString(exec, String::fromUTF8(m_additionalJettisonReason)));
return result;
}
diff --git a/Source/JavaScriptCore/profiler/ProfilerCompilation.h b/Source/JavaScriptCore/profiler/ProfilerCompilation.h
index dc2810525..b358b659c 100644
--- a/Source/JavaScriptCore/profiler/ProfilerCompilation.h
+++ b/Source/JavaScriptCore/profiler/ProfilerCompilation.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -31,6 +31,7 @@
#include "ProfilerCompilationKind.h"
#include "ProfilerCompiledBytecode.h"
#include "ProfilerExecutionCounter.h"
+#include "ProfilerJettisonReason.h"
#include "ProfilerOSRExit.h"
#include "ProfilerOSRExitSite.h"
#include "ProfilerOriginStack.h"
@@ -38,7 +39,11 @@
#include <wtf/RefCounted.h>
#include <wtf/SegmentedVector.h>
-namespace JSC { namespace Profiler {
+namespace JSC {
+
+class FireDetail;
+
+namespace Profiler {
class Bytecodes;
class Database;
@@ -63,15 +68,20 @@ public:
CompilationKind kind() const { return m_kind; }
void addDescription(const CompiledBytecode&);
+ void addDescription(const OriginStack&, const CString& description);
ExecutionCounter* executionCounterFor(const OriginStack&);
void addOSRExitSite(const Vector<const void*>& codeAddresses);
OSRExit* addOSRExit(unsigned id, const OriginStack&, ExitKind, bool isWatchpoint);
+ void setJettisonReason(JettisonReason, const FireDetail*);
+
JSValue toJS(ExecState*) const;
private:
Bytecodes* m_bytecodes;
CompilationKind m_kind;
+ JettisonReason m_jettisonReason;
+ CString m_additionalJettisonReason;
Vector<ProfiledBytecodes> m_profiledBytecodes;
Vector<CompiledBytecode> m_descriptions;
HashMap<OriginStack, std::unique_ptr<ExecutionCounter>> m_counters;
diff --git a/Source/JavaScriptCore/profiler/ProfilerCompilationKind.cpp b/Source/JavaScriptCore/profiler/ProfilerCompilationKind.cpp
index 78ce70586..3fbe25192 100644
--- a/Source/JavaScriptCore/profiler/ProfilerCompilationKind.cpp
+++ b/Source/JavaScriptCore/profiler/ProfilerCompilationKind.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -42,6 +42,12 @@ void printInternal(PrintStream& out, JSC::Profiler::CompilationKind kind)
case JSC::Profiler::DFG:
out.print("DFG");
return;
+ case JSC::Profiler::FTL:
+ out.print("FTL");
+ return;
+ case JSC::Profiler::FTLForOSREntry:
+ out.print("FTLForOSREntry");
+ return;
default:
CRASH();
return;
diff --git a/Source/JavaScriptCore/profiler/ProfilerCompilationKind.h b/Source/JavaScriptCore/profiler/ProfilerCompilationKind.h
index 4806d39b9..575ec2947 100644
--- a/Source/JavaScriptCore/profiler/ProfilerCompilationKind.h
+++ b/Source/JavaScriptCore/profiler/ProfilerCompilationKind.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -31,7 +31,9 @@ namespace JSC { namespace Profiler {
enum CompilationKind {
LLInt,
Baseline,
- DFG
+ DFG,
+ FTL,
+ FTLForOSREntry
};
} } // namespace JSC::Profiler
diff --git a/Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.cpp b/Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.cpp
index 455a48ed9..4891c315c 100644
--- a/Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.cpp
+++ b/Source/JavaScriptCore/profiler/ProfilerCompiledBytecode.cpp
@@ -28,7 +28,7 @@
#include "JSGlobalObject.h"
#include "ObjectConstructor.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC { namespace Profiler {
diff --git a/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp b/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp
index f83652dda..fc952c0c2 100644
--- a/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp
+++ b/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp
@@ -29,13 +29,13 @@
#include "CodeBlock.h"
#include "JSONObject.h"
#include "ObjectConstructor.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC { namespace Profiler {
static std::atomic<int> databaseCounter;
-static SpinLock registrationLock = SPINLOCK_INITIALIZER;
+static StaticLock registrationLock;
static std::atomic<int> didRegisterAtExit;
static Database* firstDatabase;
@@ -57,7 +57,7 @@ Database::~Database()
Bytecodes* Database::ensureBytecodesFor(CodeBlock* codeBlock)
{
- Locker locker(m_lock);
+ LockHolder locker(m_lock);
codeBlock = codeBlock->baselineVersion();
@@ -75,7 +75,7 @@ Bytecodes* Database::ensureBytecodesFor(CodeBlock* codeBlock)
void Database::notifyDestruction(CodeBlock* codeBlock)
{
- Locker locker(m_lock);
+ LockHolder locker(m_lock);
m_bytecodesMap.remove(codeBlock);
}
@@ -138,14 +138,14 @@ void Database::addDatabaseToAtExit()
if (++didRegisterAtExit == 1)
atexit(atExitCallback);
- TCMalloc_SpinLockHolder holder(&registrationLock);
+ LockHolder holder(registrationLock);
m_nextRegisteredDatabase = firstDatabase;
firstDatabase = this;
}
void Database::removeDatabaseFromAtExit()
{
- TCMalloc_SpinLockHolder holder(&registrationLock);
+ LockHolder holder(registrationLock);
for (Database** current = &firstDatabase; *current; current = &(*current)->m_nextRegisteredDatabase) {
if (*current != this)
continue;
@@ -163,7 +163,7 @@ void Database::performAtExitSave() const
Database* Database::removeFirstAtExitDatabase()
{
- TCMalloc_SpinLockHolder holder(&registrationLock);
+ LockHolder holder(registrationLock);
Database* result = firstDatabase;
if (result) {
firstDatabase = result->m_nextRegisteredDatabase;
diff --git a/Source/JavaScriptCore/profiler/ProfilerDatabase.h b/Source/JavaScriptCore/profiler/ProfilerDatabase.h
index 7d4f3cf2c..9bb64cf49 100644
--- a/Source/JavaScriptCore/profiler/ProfilerDatabase.h
+++ b/Source/JavaScriptCore/profiler/ProfilerDatabase.h
@@ -32,6 +32,7 @@
#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>
@@ -70,21 +71,6 @@ public:
void registerToSaveAtExit(const char* filename);
private:
- // Use a full-blown adaptive mutex because:
- // - There is only one ProfilerDatabase per VM. The size overhead of the system's
- // mutex is negligible if you only have one of them.
- // - It's locked infrequently - once per bytecode generation, compilation, and
- // code block collection - so the fact that the fast path still requires a
- // function call is neglible.
- // - It tends to be held for a while. Currently, we hold it while generating
- // Profiler::Bytecodes for a CodeBlock. That's uncommon and shouldn't affect
- // performance, but if we did have contention, we would want a sensible,
- // power-aware backoff. An adaptive mutex will do this as a matter of course,
- // but a spinlock won't.
- typedef Mutex Lock;
- typedef MutexLocker Locker;
-
-
void addDatabaseToAtExit();
void removeDatabaseFromAtExit();
void performAtExitSave() const;
diff --git a/Source/JavaScriptCore/profiler/ProfilerJettisonReason.cpp b/Source/JavaScriptCore/profiler/ProfilerJettisonReason.cpp
new file mode 100644
index 000000000..3068ff34c
--- /dev/null
+++ b/Source/JavaScriptCore/profiler/ProfilerJettisonReason.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ProfilerJettisonReason.h"
+
+#include <wtf/PrintStream.h>
+
+namespace WTF {
+
+using namespace JSC::Profiler;
+
+void printInternal(PrintStream& out, JettisonReason reason)
+{
+ switch (reason) {
+ case NotJettisoned:
+ out.print("NotJettisoned");
+ return;
+ case JettisonDueToWeakReference:
+ out.print("WeakReference");
+ return;
+ case JettisonDueToDebuggerBreakpoint:
+ out.print("DebuggerBreakpoint");
+ return;
+ case JettisonDueToDebuggerStepping:
+ out.print("DebuggerStepping");
+ return;
+ case JettisonDueToLegacyProfiler:
+ out.print("LegacyProfiler");
+ return;
+ case JettisonDueToBaselineLoopReoptimizationTrigger:
+ out.print("BaselineLoopReoptimizationTrigger");
+ return;
+ case JettisonDueToBaselineLoopReoptimizationTriggerOnOSREntryFail:
+ out.print("BaselineLoopReoptimizationTriggerOnOSREntryFail");
+ return;
+ case JettisonDueToOSRExit:
+ out.print("OSRExit");
+ return;
+ case JettisonDueToProfiledWatchpoint:
+ out.print("ProfiledWatchpoint");
+ return;
+ case JettisonDueToUnprofiledWatchpoint:
+ out.print("UnprofiledWatchpoint");
+ return;
+ case JettisonDueToOldAge:
+ out.print("JettisonDueToOldAge");
+ return;
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+} // namespace WTF
+
diff --git a/Source/JavaScriptCore/profiler/ProfilerJettisonReason.h b/Source/JavaScriptCore/profiler/ProfilerJettisonReason.h
new file mode 100644
index 000000000..6a7932604
--- /dev/null
+++ b/Source/JavaScriptCore/profiler/ProfilerJettisonReason.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ProfilerJettisonReason_h
+#define ProfilerJettisonReason_h
+
+namespace JSC { namespace Profiler {
+
+enum JettisonReason {
+ NotJettisoned,
+ JettisonDueToWeakReference,
+ JettisonDueToDebuggerBreakpoint,
+ JettisonDueToDebuggerStepping,
+ JettisonDueToLegacyProfiler,
+ JettisonDueToBaselineLoopReoptimizationTrigger,
+ JettisonDueToBaselineLoopReoptimizationTriggerOnOSREntryFail,
+ JettisonDueToOSRExit,
+ JettisonDueToProfiledWatchpoint,
+ JettisonDueToUnprofiledWatchpoint,
+ JettisonDueToOldAge
+};
+
+} } // namespace JSC::Profiler
+
+namespace WTF {
+
+class PrintStream;
+void printInternal(PrintStream&, JSC::Profiler::JettisonReason);
+
+} // namespace WTF
+
+#endif // ProfilerJettisonReason_h
+
diff --git a/Source/JavaScriptCore/profiler/ProfilerOSRExit.cpp b/Source/JavaScriptCore/profiler/ProfilerOSRExit.cpp
index 0024791b4..2a5d5be40 100644
--- a/Source/JavaScriptCore/profiler/ProfilerOSRExit.cpp
+++ b/Source/JavaScriptCore/profiler/ProfilerOSRExit.cpp
@@ -28,7 +28,7 @@
#include "JSGlobalObject.h"
#include "ObjectConstructor.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC { namespace Profiler {
diff --git a/Source/JavaScriptCore/profiler/ProfilerOSRExitSite.cpp b/Source/JavaScriptCore/profiler/ProfilerOSRExitSite.cpp
index d54f7a275..b17d57e52 100644
--- a/Source/JavaScriptCore/profiler/ProfilerOSRExitSite.cpp
+++ b/Source/JavaScriptCore/profiler/ProfilerOSRExitSite.cpp
@@ -29,7 +29,7 @@
#include "JSGlobalObject.h"
#include "JSScope.h"
#include "JSString.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include <wtf/StringPrintStream.h>
namespace JSC { namespace Profiler {
diff --git a/Source/JavaScriptCore/profiler/ProfilerOrigin.cpp b/Source/JavaScriptCore/profiler/ProfilerOrigin.cpp
index 1ac29d1cc..7c28f7ba3 100644
--- a/Source/JavaScriptCore/profiler/ProfilerOrigin.cpp
+++ b/Source/JavaScriptCore/profiler/ProfilerOrigin.cpp
@@ -28,7 +28,7 @@
#include "JSGlobalObject.h"
#include "ObjectConstructor.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "ProfilerBytecodes.h"
#include "ProfilerDatabase.h"
diff --git a/Source/JavaScriptCore/profiler/ProfilerOriginStack.cpp b/Source/JavaScriptCore/profiler/ProfilerOriginStack.cpp
index 018ceeb8c..b8eecdd60 100644
--- a/Source/JavaScriptCore/profiler/ProfilerOriginStack.cpp
+++ b/Source/JavaScriptCore/profiler/ProfilerOriginStack.cpp
@@ -27,8 +27,9 @@
#include "ProfilerOriginStack.h"
#include "CodeOrigin.h"
+#include "InlineCallFrame.h"
#include "JSGlobalObject.h"
-#include "Operations.h"
+#include "JSCInlines.h"
#include "ProfilerDatabase.h"
namespace JSC { namespace Profiler {
@@ -51,7 +52,7 @@ OriginStack::OriginStack(Database& database, CodeBlock* codeBlock, const CodeOri
for (unsigned i = 1; i < stack.size(); ++i) {
append(Origin(
- database.ensureBytecodesFor(stack[i].inlineCallFrame->baselineCodeBlock()),
+ database.ensureBytecodesFor(stack[i].inlineCallFrame->baselineCodeBlock.get()),
stack[i].bytecodeIndex));
}
}
diff --git a/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.cpp b/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.cpp
index 6ca6c9f15..fe590ff78 100644
--- a/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.cpp
+++ b/Source/JavaScriptCore/profiler/ProfilerProfiledBytecodes.cpp
@@ -28,7 +28,7 @@
#include "JSGlobalObject.h"
#include "ObjectConstructor.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC { namespace Profiler {