2 * Copyright (C) 2008, 2012 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
30 #include "LegacyProfiler.h"
32 #include "CallFrame.h"
33 #include "CodeBlock.h"
34 #include "CommonIdentifiers.h"
35 #include "InternalFunction.h"
36 #include "JSFunction.h"
37 #include "JSGlobalObject.h"
39 #include "Operations.h"
41 #include "ProfileGenerator.h"
42 #include "ProfileNode.h"
47 static const char* GlobalCodeExecution
= "(program)";
48 static const char* AnonymousFunction
= "(anonymous function)";
49 static unsigned ProfilesUID
= 0;
51 static CallIdentifier
createCallIdentifierFromFunctionImp(ExecState
*, JSObject
*, const String
& defaultSourceURL
, int defaultLineNumber
);
53 LegacyProfiler
* LegacyProfiler::s_sharedLegacyProfiler
= 0;
55 LegacyProfiler
* LegacyProfiler::profiler()
57 if (!s_sharedLegacyProfiler
)
58 s_sharedLegacyProfiler
= new LegacyProfiler();
59 return s_sharedLegacyProfiler
;
62 void LegacyProfiler::startProfiling(ExecState
* exec
, const String
& title
)
64 ASSERT_ARG(title
, !title
.isNull());
69 // Check if we currently have a Profile for this global ExecState and title.
70 // If so return early and don't create a new Profile.
71 JSGlobalObject
* origin
= exec
->lexicalGlobalObject();
73 for (size_t i
= 0; i
< m_currentProfiles
.size(); ++i
) {
74 ProfileGenerator
* profileGenerator
= m_currentProfiles
[i
].get();
75 if (profileGenerator
->origin() == origin
&& profileGenerator
->title() == title
)
79 exec
->vm().m_enabledProfiler
= this;
80 RefPtr
<ProfileGenerator
> profileGenerator
= ProfileGenerator::create(exec
, title
, ++ProfilesUID
);
81 m_currentProfiles
.append(profileGenerator
);
84 PassRefPtr
<Profile
> LegacyProfiler::stopProfiling(ExecState
* exec
, const String
& title
)
89 JSGlobalObject
* origin
= exec
->lexicalGlobalObject();
90 for (ptrdiff_t i
= m_currentProfiles
.size() - 1; i
>= 0; --i
) {
91 ProfileGenerator
* profileGenerator
= m_currentProfiles
[i
].get();
92 if (profileGenerator
->origin() == origin
&& (title
.isNull() || profileGenerator
->title() == title
)) {
93 profileGenerator
->stopProfiling();
94 RefPtr
<Profile
> returnProfile
= profileGenerator
->profile();
96 m_currentProfiles
.remove(i
);
97 if (!m_currentProfiles
.size())
98 exec
->vm().m_enabledProfiler
= 0;
100 return returnProfile
;
107 void LegacyProfiler::stopProfiling(JSGlobalObject
* origin
)
109 for (ptrdiff_t i
= m_currentProfiles
.size() - 1; i
>= 0; --i
) {
110 ProfileGenerator
* profileGenerator
= m_currentProfiles
[i
].get();
111 if (profileGenerator
->origin() == origin
) {
112 profileGenerator
->stopProfiling();
113 m_currentProfiles
.remove(i
);
114 if (!m_currentProfiles
.size())
115 origin
->vm().m_enabledProfiler
= 0;
120 static inline void dispatchFunctionToProfiles(ExecState
* callerOrHandlerCallFrame
, const Vector
<RefPtr
<ProfileGenerator
> >& profiles
, ProfileGenerator::ProfileFunction function
, const CallIdentifier
& callIdentifier
, unsigned currentProfileTargetGroup
)
122 for (size_t i
= 0; i
< profiles
.size(); ++i
) {
123 if (profiles
[i
]->profileGroup() == currentProfileTargetGroup
|| !profiles
[i
]->origin())
124 (profiles
[i
].get()->*function
)(callerOrHandlerCallFrame
, callIdentifier
);
128 void LegacyProfiler::willExecute(ExecState
* callerCallFrame
, JSValue function
)
130 ASSERT(!m_currentProfiles
.isEmpty());
132 dispatchFunctionToProfiles(callerCallFrame
, m_currentProfiles
, &ProfileGenerator::willExecute
, createCallIdentifier(callerCallFrame
, function
, "", 0), callerCallFrame
->lexicalGlobalObject()->profileGroup());
135 void LegacyProfiler::willExecute(ExecState
* callerCallFrame
, const String
& sourceURL
, int startingLineNumber
)
137 ASSERT(!m_currentProfiles
.isEmpty());
139 CallIdentifier callIdentifier
= createCallIdentifier(callerCallFrame
, JSValue(), sourceURL
, startingLineNumber
);
141 dispatchFunctionToProfiles(callerCallFrame
, m_currentProfiles
, &ProfileGenerator::willExecute
, callIdentifier
, callerCallFrame
->lexicalGlobalObject()->profileGroup());
144 void LegacyProfiler::didExecute(ExecState
* callerCallFrame
, JSValue function
)
146 ASSERT(!m_currentProfiles
.isEmpty());
148 dispatchFunctionToProfiles(callerCallFrame
, m_currentProfiles
, &ProfileGenerator::didExecute
, createCallIdentifier(callerCallFrame
, function
, "", 0), callerCallFrame
->lexicalGlobalObject()->profileGroup());
151 void LegacyProfiler::didExecute(ExecState
* callerCallFrame
, const String
& sourceURL
, int startingLineNumber
)
153 ASSERT(!m_currentProfiles
.isEmpty());
155 dispatchFunctionToProfiles(callerCallFrame
, m_currentProfiles
, &ProfileGenerator::didExecute
, createCallIdentifier(callerCallFrame
, JSValue(), sourceURL
, startingLineNumber
), callerCallFrame
->lexicalGlobalObject()->profileGroup());
158 void LegacyProfiler::exceptionUnwind(ExecState
* handlerCallFrame
)
160 ASSERT(!m_currentProfiles
.isEmpty());
162 dispatchFunctionToProfiles(handlerCallFrame
, m_currentProfiles
, &ProfileGenerator::exceptionUnwind
, createCallIdentifier(handlerCallFrame
, JSValue(), "", 0), handlerCallFrame
->lexicalGlobalObject()->profileGroup());
165 CallIdentifier
LegacyProfiler::createCallIdentifier(ExecState
* exec
, JSValue functionValue
, const String
& defaultSourceURL
, int defaultLineNumber
)
168 return CallIdentifier(GlobalCodeExecution
, defaultSourceURL
, defaultLineNumber
);
169 if (!functionValue
.isObject())
170 return CallIdentifier("(unknown)", defaultSourceURL
, defaultLineNumber
);
171 if (asObject(functionValue
)->inherits(&JSFunction::s_info
) || asObject(functionValue
)->inherits(&InternalFunction::s_info
))
172 return createCallIdentifierFromFunctionImp(exec
, asObject(functionValue
), defaultSourceURL
, defaultLineNumber
);
173 return CallIdentifier(makeString("(", asObject(functionValue
)->methodTable()->className(asObject(functionValue
)), " object)"), defaultSourceURL
, defaultLineNumber
);
176 CallIdentifier
createCallIdentifierFromFunctionImp(ExecState
* exec
, JSObject
* function
, const String
& defaultSourceURL
, int defaultLineNumber
)
178 const String
& name
= getCalculatedDisplayName(exec
, function
);
179 JSFunction
* jsFunction
= jsDynamicCast
<JSFunction
*>(function
);
180 if (jsFunction
&& !jsFunction
->isHostFunction())
181 return CallIdentifier(name
.isEmpty() ? AnonymousFunction
: name
, jsFunction
->jsExecutable()->sourceURL(), jsFunction
->jsExecutable()->lineNo());
182 return CallIdentifier(name
.isEmpty() ? AnonymousFunction
: name
, defaultSourceURL
, defaultLineNumber
);