• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "CommonIdentifiers.h"
33 #include "CallFrame.h"
34 #include "JSFunction.h"
35 #include "JSGlobalObject.h"
36 #include "Nodes.h"
37 #include "Profile.h"
38 #include "ProfileGenerator.h"
39 #include "ProfileNode.h"
40 #include <stdio.h>
41 
42 namespace JSC {
43 
44 static const char* GlobalCodeExecution = "(program)";
45 static const char* AnonymousFunction = "(anonymous function)";
46 static unsigned ProfilesUID = 0;
47 
48 static CallIdentifier createCallIdentifierFromFunctionImp(JSGlobalData*, JSFunction*);
49 
50 Profiler* Profiler::s_sharedProfiler = 0;
51 Profiler* Profiler::s_sharedEnabledProfilerReference = 0;
52 
profiler()53 Profiler* Profiler::profiler()
54 {
55     if (!s_sharedProfiler)
56         s_sharedProfiler = new Profiler();
57     return s_sharedProfiler;
58 }
59 
startProfiling(ExecState * exec,const UString & title)60 void Profiler::startProfiling(ExecState* exec, const UString& title)
61 {
62     ASSERT_ARG(title, !title.isNull());
63 
64     // Check if we currently have a Profile for this global ExecState and title.
65     // If so return early and don't create a new Profile.
66     ExecState* globalExec = exec ? exec->lexicalGlobalObject()->globalExec() : 0;
67 
68     for (size_t i = 0; i < m_currentProfiles.size(); ++i) {
69         ProfileGenerator* profileGenerator = m_currentProfiles[i].get();
70         if (profileGenerator->originatingGlobalExec() == globalExec && profileGenerator->title() == title)
71             return;
72     }
73 
74     s_sharedEnabledProfilerReference = this;
75     RefPtr<ProfileGenerator> profileGenerator = ProfileGenerator::create(title, exec, ++ProfilesUID);
76     m_currentProfiles.append(profileGenerator);
77 }
78 
stopProfiling(ExecState * exec,const UString & title)79 PassRefPtr<Profile> Profiler::stopProfiling(ExecState* exec, const UString& title)
80 {
81     ExecState* globalExec = exec ? exec->lexicalGlobalObject()->globalExec() : 0;
82     for (ptrdiff_t i = m_currentProfiles.size() - 1; i >= 0; --i) {
83         ProfileGenerator* profileGenerator = m_currentProfiles[i].get();
84         if (profileGenerator->originatingGlobalExec() == globalExec && (title.isNull() || profileGenerator->title() == title)) {
85             profileGenerator->stopProfiling();
86             RefPtr<Profile> returnProfile = profileGenerator->profile();
87 
88             m_currentProfiles.remove(i);
89             if (!m_currentProfiles.size())
90                 s_sharedEnabledProfilerReference = 0;
91 
92             return returnProfile;
93         }
94     }
95 
96     return 0;
97 }
98 
dispatchFunctionToProfiles(const Vector<RefPtr<ProfileGenerator>> & profiles,ProfileGenerator::ProfileFunction function,const CallIdentifier & callIdentifier,unsigned currentProfileTargetGroup)99 static inline void dispatchFunctionToProfiles(const Vector<RefPtr<ProfileGenerator> >& profiles, ProfileGenerator::ProfileFunction function, const CallIdentifier& callIdentifier, unsigned currentProfileTargetGroup)
100 {
101     for (size_t i = 0; i < profiles.size(); ++i) {
102         if (profiles[i]->profileGroup() == currentProfileTargetGroup || !profiles[i]->originatingGlobalExec())
103             (profiles[i].get()->*function)(callIdentifier);
104     }
105 }
106 
willExecute(ExecState * exec,JSValue function)107 void Profiler::willExecute(ExecState* exec, JSValue function)
108 {
109     ASSERT(!m_currentProfiles.isEmpty());
110 
111     dispatchFunctionToProfiles(m_currentProfiles, &ProfileGenerator::willExecute, createCallIdentifier(&exec->globalData(), function, "", 0), exec->lexicalGlobalObject()->profileGroup());
112 }
113 
willExecute(ExecState * exec,const UString & sourceURL,int startingLineNumber)114 void Profiler::willExecute(ExecState* exec, const UString& sourceURL, int startingLineNumber)
115 {
116     ASSERT(!m_currentProfiles.isEmpty());
117 
118     CallIdentifier callIdentifier = createCallIdentifier(&exec->globalData(), JSValue(), sourceURL, startingLineNumber);
119 
120     dispatchFunctionToProfiles(m_currentProfiles, &ProfileGenerator::willExecute, callIdentifier, exec->lexicalGlobalObject()->profileGroup());
121 }
122 
didExecute(ExecState * exec,JSValue function)123 void Profiler::didExecute(ExecState* exec, JSValue function)
124 {
125     ASSERT(!m_currentProfiles.isEmpty());
126 
127     dispatchFunctionToProfiles(m_currentProfiles, &ProfileGenerator::didExecute, createCallIdentifier(&exec->globalData(), function, "", 0), exec->lexicalGlobalObject()->profileGroup());
128 }
129 
didExecute(ExecState * exec,const UString & sourceURL,int startingLineNumber)130 void Profiler::didExecute(ExecState* exec, const UString& sourceURL, int startingLineNumber)
131 {
132     ASSERT(!m_currentProfiles.isEmpty());
133 
134     dispatchFunctionToProfiles(m_currentProfiles, &ProfileGenerator::didExecute, createCallIdentifier(&exec->globalData(), JSValue(), sourceURL, startingLineNumber), exec->lexicalGlobalObject()->profileGroup());
135 }
136 
createCallIdentifier(JSGlobalData * globalData,JSValue function,const UString & defaultSourceURL,int defaultLineNumber)137 CallIdentifier Profiler::createCallIdentifier(JSGlobalData* globalData, JSValue function, const UString& defaultSourceURL, int defaultLineNumber)
138 {
139     if (!function)
140         return CallIdentifier(GlobalCodeExecution, defaultSourceURL, defaultLineNumber);
141     if (!function.isObject())
142         return CallIdentifier("(unknown)", defaultSourceURL, defaultLineNumber);
143     if (asObject(function)->inherits(&JSFunction::info)) {
144         JSFunction* func = asFunction(function);
145         if (!func->isHostFunction())
146             return createCallIdentifierFromFunctionImp(globalData, func);
147     }
148     if (asObject(function)->inherits(&InternalFunction::info))
149         return CallIdentifier(static_cast<InternalFunction*>(asObject(function))->name(globalData), defaultSourceURL, defaultLineNumber);
150     return CallIdentifier("(" + asObject(function)->className() + " object)", defaultSourceURL, defaultLineNumber);
151 }
152 
createCallIdentifierFromFunctionImp(JSGlobalData * globalData,JSFunction * function)153 CallIdentifier createCallIdentifierFromFunctionImp(JSGlobalData* globalData, JSFunction* function)
154 {
155     const UString& name = function->calculatedDisplayName(globalData);
156     return CallIdentifier(name.isEmpty() ? AnonymousFunction : name, function->body()->sourceURL(), function->body()->lineNo());
157 }
158 
159 } // namespace JSC
160