]> git.saurik.com Git - apple/javascriptcore.git/blob - profiler/ProfileGenerator.cpp
JavaScriptCore-521.tar.gz
[apple/javascriptcore.git] / profiler / ProfileGenerator.cpp
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
38 namespace JSC {
39
40 static const char* NonJSExecution = "(idle)";
41
42 PassRefPtr<ProfileGenerator> ProfileGenerator::create(const UString& title, ExecState* originatingExec, unsigned uid)
43 {
44 return adoptRef(new ProfileGenerator(title, originatingExec, uid));
45 }
46
47 ProfileGenerator::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
57 void 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
69 const UString& ProfileGenerator::title() const
70 {
71 return m_profile->title();
72 }
73
74 void 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
89 void 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
112 void 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.
138 void 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.
153 void 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