Fixed an ASSERT(m_actualSelfTime <= m_actualTotalTime) when starting
[WebKit-https.git] / JavaScriptCore / profiler / Profiler.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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "Profiler.h"
31
32 #include "ExecState.h"
33 #include "JSFunction.h"
34 #include "ProfileNode.h"
35 #include "JSGlobalObject.h"
36 #include "Profile.h"
37
38 #include <stdio.h>
39
40 namespace KJS {
41
42 static const char* GlobalCodeExecution = "(program)";
43 static const char* AnonymousFunction = "(anonymous function)";
44
45 static CallIdentifier createCallIdentifier(JSObject*);
46 static CallIdentifier createCallIdentifier(const UString& sourceURL, int startingLineNumber);
47 static CallIdentifier createCallIdentifierFromFunctionImp(JSFunction*);
48
49 Profiler* Profiler::s_sharedProfiler = 0;
50 Profiler* Profiler::s_sharedEnabledProfilerReference = 0;
51
52 Profiler* Profiler::profiler()
53 {
54     if (!s_sharedProfiler)
55         s_sharedProfiler = new Profiler();
56     return s_sharedProfiler;
57 }   
58     
59 Profile* Profiler::findProfile(ExecState* exec, const UString& title) const
60 {
61     ExecState* globalExec = exec->lexicalGlobalObject()->globalExec();
62     for (size_t i = 0; i < m_currentProfiles.size(); ++i)
63         if (m_currentProfiles[i]->originatingGlobalExec() == globalExec && (title.isNull() || m_currentProfiles[i]->title() == title))
64             return m_currentProfiles[i].get();
65     return 0;
66 }
67
68 void Profiler::startProfiling(ExecState* exec, const UString& title, ProfilerClient* client)
69 {
70     ASSERT_ARG(exec, exec);
71
72     // Check if we currently have a Profile for this global ExecState and title.
73     // If so return early and don't create a new Profile.
74     ExecState* globalExec = exec->lexicalGlobalObject()->globalExec();
75     for (size_t i = 0; i < m_currentProfiles.size(); ++i)
76         if (m_currentProfiles[i]->originatingGlobalExec() == globalExec && m_currentProfiles[i]->title() == title)
77             return;
78     s_sharedEnabledProfilerReference = this;
79     RefPtr<Profile> profile = Profile::create(title, globalExec, exec->lexicalGlobalObject()->pageGroupIdentifier(), client);
80     m_currentProfiles.append(profile);
81 }
82
83 void Profiler::stopProfiling(ExecState* exec, const UString& title)
84 {
85     ExecState* globalExec = exec->lexicalGlobalObject()->globalExec();
86     for (ptrdiff_t i = m_currentProfiles.size() - 1; i >= 0; --i) {
87         if (m_currentProfiles[i]->originatingGlobalExec() == globalExec && (title.isNull() || m_currentProfiles[i]->title() == title))
88             m_currentProfiles[i]->stopProfiling();
89     }
90 }
91
92 void Profiler::didFinishAllExecution(ExecState* exec)
93 {
94     ExecState* globalExec = exec->lexicalGlobalObject()->globalExec();
95     for (ptrdiff_t i = m_currentProfiles.size() - 1; i >= 0; --i) {
96         if (m_currentProfiles[i]->originatingGlobalExec() == globalExec && m_currentProfiles[i]->didFinishAllExecution()) {
97             PassRefPtr<Profile> prpProfile = m_currentProfiles[i].release();        
98             m_currentProfiles.remove(i);
99
100             if (!m_currentProfiles.size())
101                 s_sharedEnabledProfilerReference = 0;
102
103             if (ProfilerClient* client = prpProfile->client())
104                 client->finishedProfiling(prpProfile);
105         }
106     }
107 }
108
109 static inline void dispatchFunctionToProfiles(const Vector<RefPtr<Profile> >& profiles, Profile::ProfileFunction function, const CallIdentifier& callIdentifier, unsigned currentPageGroupIdentifier)
110 {
111     for (size_t i = 0; i < profiles.size(); ++i)
112         if (profiles[i]->pageGroupIdentifier() == currentPageGroupIdentifier)
113             (profiles[i].get()->*function)(callIdentifier);
114 }
115
116 void Profiler::willExecute(ExecState* exec, JSObject* calledFunction)
117 {
118     ASSERT(!m_currentProfiles.isEmpty());
119
120     dispatchFunctionToProfiles(m_currentProfiles, &Profile::willExecute, createCallIdentifier(calledFunction), exec->lexicalGlobalObject()->pageGroupIdentifier());
121 }
122
123 void Profiler::willExecute(ExecState* exec, const UString& sourceURL, int startingLineNumber)
124 {
125     ASSERT(!m_currentProfiles.isEmpty());
126
127     CallIdentifier callIdentifier = createCallIdentifier(sourceURL, startingLineNumber);
128
129     dispatchFunctionToProfiles(m_currentProfiles, &Profile::willExecute, callIdentifier, exec->lexicalGlobalObject()->pageGroupIdentifier());
130 }
131
132 void Profiler::didExecute(ExecState* exec, JSObject* calledFunction)
133 {
134     ASSERT(!m_currentProfiles.isEmpty());
135
136     dispatchFunctionToProfiles(m_currentProfiles, &Profile::didExecute, createCallIdentifier(calledFunction), exec->lexicalGlobalObject()->pageGroupIdentifier());
137 }
138
139 void Profiler::didExecute(ExecState* exec, const UString& sourceURL, int startingLineNumber)
140 {
141     ASSERT(!m_currentProfiles.isEmpty());
142
143     dispatchFunctionToProfiles(m_currentProfiles, &Profile::didExecute, createCallIdentifier(sourceURL, startingLineNumber), exec->lexicalGlobalObject()->pageGroupIdentifier());
144 }
145
146 CallIdentifier createCallIdentifier(JSObject* calledFunction)
147 {
148     if (calledFunction->inherits(&JSFunction::info))
149         return createCallIdentifierFromFunctionImp(static_cast<JSFunction*>(calledFunction));
150     if (calledFunction->inherits(&InternalFunction::info))
151         return CallIdentifier(static_cast<InternalFunction*>(calledFunction)->functionName().ustring(), "", 0);
152
153     UString name = "(" + calledFunction->className() + " object)";
154     return CallIdentifier(name, 0, 0);
155 }
156
157 CallIdentifier createCallIdentifier(const UString& sourceURL, int startingLineNumber)
158 {
159     return CallIdentifier(GlobalCodeExecution, sourceURL, startingLineNumber);
160 }
161
162 CallIdentifier createCallIdentifierFromFunctionImp(JSFunction* functionImp)
163 {
164     UString name = functionImp->functionName().ustring();
165     if (name.isEmpty())
166         name = AnonymousFunction;
167
168     return CallIdentifier(name, functionImp->body->sourceURL(), functionImp->body->lineNo());
169 }
170
171 }   // namespace KJS