]> git.saurik.com Git - apple/javascriptcore.git/blame - profiler/ProfileGenerator.cpp
JavaScriptCore-525.tar.gz
[apple/javascriptcore.git] / profiler / ProfileGenerator.cpp
CommitLineData
9dae56ea
A
1/*
2 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "ProfileGenerator.h"
28
29#include "CallFrame.h"
30#include "JSGlobalObject.h"
31#include "JSStringRef.h"
32#include "JSFunction.h"
33#include "Interpreter.h"
34#include "Profile.h"
35#include "Profiler.h"
36#include "Tracing.h"
37
38namespace JSC {
39
40static const char* NonJSExecution = "(idle)";
41
42PassRefPtr<ProfileGenerator> ProfileGenerator::create(const UString& title, ExecState* originatingExec, unsigned uid)
43{
44 return adoptRef(new ProfileGenerator(title, originatingExec, uid));
45}
46
47ProfileGenerator::ProfileGenerator(const UString& title, ExecState* originatingExec, unsigned uid)
48 : m_originatingGlobalExec(originatingExec ? originatingExec->lexicalGlobalObject()->globalExec() : 0)
49 , m_profileGroup(originatingExec ? originatingExec->lexicalGlobalObject()->profileGroup() : 0)
50{
51 m_profile = Profile::create(title, uid);
52 m_currentNode = m_head = m_profile->head();
53 if (originatingExec)
54 addParentForConsoleStart(originatingExec);
55}
56
57void ProfileGenerator::addParentForConsoleStart(ExecState* exec)
58{
59 int lineNumber;
60 intptr_t sourceID;
61 UString sourceURL;
62 JSValuePtr function;
63
64 exec->interpreter()->retrieveLastCaller(exec, lineNumber, sourceID, sourceURL, function);
65 m_currentNode = ProfileNode::create(Profiler::createCallIdentifier(&exec->globalData(), function ? function.toThisObject(exec) : 0, sourceURL, lineNumber), m_head.get(), m_head.get());
66 m_head->insertNode(m_currentNode.get());
67}
68
69const UString& ProfileGenerator::title() const
70{
71 return m_profile->title();
72}
73
74void ProfileGenerator::willExecute(const CallIdentifier& callIdentifier)
75{
76 if (JAVASCRIPTCORE_PROFILE_WILL_EXECUTE_ENABLED()) {
77 CString name = callIdentifier.m_name.UTF8String();
78 CString url = callIdentifier.m_url.UTF8String();
79 JAVASCRIPTCORE_PROFILE_WILL_EXECUTE(m_profileGroup, const_cast<char*>(name.c_str()), const_cast<char*>(url.c_str()), callIdentifier.m_lineNumber);
80 }
81
82 if (!m_originatingGlobalExec)
83 return;
84
85 ASSERT_ARG(m_currentNode, m_currentNode);
86 m_currentNode = m_currentNode->willExecute(callIdentifier);
87}
88
89void ProfileGenerator::didExecute(const CallIdentifier& callIdentifier)
90{
91 if (JAVASCRIPTCORE_PROFILE_DID_EXECUTE_ENABLED()) {
92 CString name = callIdentifier.m_name.UTF8String();
93 CString url = callIdentifier.m_url.UTF8String();
94 JAVASCRIPTCORE_PROFILE_DID_EXECUTE(m_profileGroup, const_cast<char*>(name.c_str()), const_cast<char*>(url.c_str()), callIdentifier.m_lineNumber);
95 }
96
97 if (!m_originatingGlobalExec)
98 return;
99
100 ASSERT_ARG(m_currentNode, m_currentNode);
101 if (m_currentNode->callIdentifier() != callIdentifier) {
102 RefPtr<ProfileNode> returningNode = ProfileNode::create(callIdentifier, m_head.get(), m_currentNode.get());
103 returningNode->setStartTime(m_currentNode->startTime());
104 returningNode->didExecute();
105 m_currentNode->insertNode(returningNode.release());
106 return;
107 }
108
109 m_currentNode = m_currentNode->didExecute();
110}
111
112void ProfileGenerator::stopProfiling()
113{
114 m_profile->forEach(&ProfileNode::stopProfiling);
115
116 removeProfileStart();
117 removeProfileEnd();
118
119 ASSERT_ARG(m_currentNode, m_currentNode);
120
121 // Set the current node to the parent, because we are in a call that
122 // will not get didExecute call.
123 m_currentNode = m_currentNode->parent();
124
125 if (double headSelfTime = m_head->selfTime()) {
126 RefPtr<ProfileNode> idleNode = ProfileNode::create(CallIdentifier(NonJSExecution, 0, 0), m_head.get(), m_head.get());
127
128 idleNode->setTotalTime(headSelfTime);
129 idleNode->setSelfTime(headSelfTime);
130 idleNode->setVisible(true);
131
132 m_head->setSelfTime(0.0);
133 m_head->addChild(idleNode.release());
134 }
135}
136
137// The console.ProfileGenerator that started this ProfileGenerator will be the first child.
138void ProfileGenerator::removeProfileStart()
139{
140 ProfileNode* currentNode = 0;
141 for (ProfileNode* next = m_head.get(); next; next = next->firstChild())
142 currentNode = next;
143
144 if (currentNode->callIdentifier().m_name != "profile")
145 return;
146
147 // Attribute the time of the node aobut to be removed to the self time of its parent
148 currentNode->parent()->setSelfTime(currentNode->parent()->selfTime() + currentNode->totalTime());
149 currentNode->parent()->removeChild(currentNode);
150}
151
152// The console.ProfileGeneratorEnd that stopped this ProfileGenerator will be the last child.
153void ProfileGenerator::removeProfileEnd()
154{
155 ProfileNode* currentNode = 0;
156 for (ProfileNode* next = m_head.get(); next; next = next->lastChild())
157 currentNode = next;
158
159 if (currentNode->callIdentifier().m_name != "profileEnd")
160 return;
161
162 // Attribute the time of the node aobut to be removed to the self time of its parent
163 currentNode->parent()->setSelfTime(currentNode->parent()->selfTime() + currentNode->totalTime());
164
165 ASSERT(currentNode->callIdentifier() == (currentNode->parent()->children()[currentNode->parent()->children().size() - 1])->callIdentifier());
166 currentNode->parent()->removeChild(currentNode);
167}
168
169} // namespace JSC