2 * Copyright (C) 2008, 2012, 2014 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 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 "JSCInlines.h"
41 #include "ProfileGenerator.h"
42 #include "ProfileNode.h"
46 static const char* GlobalCodeExecution
= "(program)";
47 static const char* AnonymousFunction
= "(anonymous function)";
48 static unsigned ProfilesUID
= 0;
50 static CallIdentifier
createCallIdentifierFromFunctionImp(ExecState
*, JSObject
*, const String
& defaultSourceURL
, unsigned defaultLineNumber
, unsigned defaultColumnNumber
);
52 LegacyProfiler
* LegacyProfiler::s_sharedLegacyProfiler
= 0;
54 LegacyProfiler
* LegacyProfiler::profiler()
56 if (!s_sharedLegacyProfiler
)
57 s_sharedLegacyProfiler
= new LegacyProfiler();
58 return s_sharedLegacyProfiler
;
61 void LegacyProfiler::startProfiling(ExecState
* exec
, const String
& title
)
66 // Check if we currently have a Profile for this global ExecState and title.
67 // If so return early and don't create a new Profile.
68 JSGlobalObject
* origin
= exec
->lexicalGlobalObject();
70 for (size_t i
= 0; i
< m_currentProfiles
.size(); ++i
) {
71 ProfileGenerator
* profileGenerator
= m_currentProfiles
[i
].get();
72 if (profileGenerator
->origin() == origin
&& profileGenerator
->title() == title
)
76 exec
->vm().setEnabledProfiler(this);
77 RefPtr
<ProfileGenerator
> profileGenerator
= ProfileGenerator::create(exec
, title
, ++ProfilesUID
);
78 m_currentProfiles
.append(profileGenerator
);
81 PassRefPtr
<Profile
> LegacyProfiler::stopProfiling(ExecState
* exec
, const String
& title
)
86 JSGlobalObject
* origin
= exec
->lexicalGlobalObject();
87 for (ptrdiff_t i
= m_currentProfiles
.size() - 1; i
>= 0; --i
) {
88 ProfileGenerator
* profileGenerator
= m_currentProfiles
[i
].get();
89 if (profileGenerator
->origin() == origin
&& (title
.isNull() || profileGenerator
->title() == title
)) {
90 profileGenerator
->stopProfiling();
91 RefPtr
<Profile
> returnProfile
= profileGenerator
->profile();
93 m_currentProfiles
.remove(i
);
94 if (!m_currentProfiles
.size())
95 exec
->vm().setEnabledProfiler(nullptr);
104 void LegacyProfiler::stopProfiling(JSGlobalObject
* origin
)
106 for (ptrdiff_t i
= m_currentProfiles
.size() - 1; i
>= 0; --i
) {
107 ProfileGenerator
* profileGenerator
= m_currentProfiles
[i
].get();
108 if (profileGenerator
->origin() == origin
) {
109 profileGenerator
->stopProfiling();
110 m_currentProfiles
.remove(i
);
111 if (!m_currentProfiles
.size())
112 origin
->vm().setEnabledProfiler(nullptr);
117 static inline void dispatchFunctionToProfiles(ExecState
* callerOrHandlerCallFrame
, const Vector
<RefPtr
<ProfileGenerator
>>& profiles
, ProfileGenerator::ProfileFunction function
, const CallIdentifier
& callIdentifier
, unsigned currentProfileTargetGroup
)
119 for (size_t i
= 0; i
< profiles
.size(); ++i
) {
120 if (profiles
[i
]->profileGroup() == currentProfileTargetGroup
|| !profiles
[i
]->origin())
121 (profiles
[i
].get()->*function
)(callerOrHandlerCallFrame
, callIdentifier
);
125 void LegacyProfiler::willExecute(ExecState
* callerCallFrame
, JSValue function
)
127 ASSERT(!m_currentProfiles
.isEmpty());
129 dispatchFunctionToProfiles(callerCallFrame
, m_currentProfiles
, &ProfileGenerator::willExecute
, createCallIdentifier(callerCallFrame
, function
, StringImpl::empty(), 0, 0), callerCallFrame
->lexicalGlobalObject()->profileGroup());
132 void LegacyProfiler::willExecute(ExecState
* callerCallFrame
, const String
& sourceURL
, unsigned startingLineNumber
, unsigned startingColumnNumber
)
134 ASSERT(!m_currentProfiles
.isEmpty());
136 CallIdentifier callIdentifier
= createCallIdentifier(callerCallFrame
, JSValue(), sourceURL
, startingLineNumber
, startingColumnNumber
);
138 dispatchFunctionToProfiles(callerCallFrame
, m_currentProfiles
, &ProfileGenerator::willExecute
, callIdentifier
, callerCallFrame
->lexicalGlobalObject()->profileGroup());
141 void LegacyProfiler::didExecute(ExecState
* callerCallFrame
, JSValue function
)
143 ASSERT(!m_currentProfiles
.isEmpty());
145 dispatchFunctionToProfiles(callerCallFrame
, m_currentProfiles
, &ProfileGenerator::didExecute
, createCallIdentifier(callerCallFrame
, function
, StringImpl::empty(), 0, 0), callerCallFrame
->lexicalGlobalObject()->profileGroup());
148 void LegacyProfiler::didExecute(ExecState
* callerCallFrame
, const String
& sourceURL
, unsigned startingLineNumber
, unsigned startingColumnNumber
)
150 ASSERT(!m_currentProfiles
.isEmpty());
152 dispatchFunctionToProfiles(callerCallFrame
, m_currentProfiles
, &ProfileGenerator::didExecute
, createCallIdentifier(callerCallFrame
, JSValue(), sourceURL
, startingLineNumber
, startingColumnNumber
), callerCallFrame
->lexicalGlobalObject()->profileGroup());
155 void LegacyProfiler::exceptionUnwind(ExecState
* handlerCallFrame
)
157 ASSERT(!m_currentProfiles
.isEmpty());
159 dispatchFunctionToProfiles(handlerCallFrame
, m_currentProfiles
, &ProfileGenerator::exceptionUnwind
, createCallIdentifier(handlerCallFrame
, JSValue(), StringImpl::empty(), 0, 0), handlerCallFrame
->lexicalGlobalObject()->profileGroup());
162 CallIdentifier
LegacyProfiler::createCallIdentifier(ExecState
* exec
, JSValue functionValue
, const String
& defaultSourceURL
, unsigned defaultLineNumber
, unsigned defaultColumnNumber
)
165 return CallIdentifier(ASCIILiteral(GlobalCodeExecution
), defaultSourceURL
, defaultLineNumber
, defaultColumnNumber
);
166 if (!functionValue
.isObject())
167 return CallIdentifier(ASCIILiteral("(unknown)"), defaultSourceURL
, defaultLineNumber
, defaultColumnNumber
);
168 if (asObject(functionValue
)->inherits(JSFunction::info()) || asObject(functionValue
)->inherits(InternalFunction::info()))
169 return createCallIdentifierFromFunctionImp(exec
, asObject(functionValue
), defaultSourceURL
, defaultLineNumber
, defaultColumnNumber
);
170 return CallIdentifier(asObject(functionValue
)->methodTable()->className(asObject(functionValue
)), defaultSourceURL
, defaultLineNumber
, defaultColumnNumber
);
173 CallIdentifier
createCallIdentifierFromFunctionImp(ExecState
* exec
, JSObject
* function
, const String
& defaultSourceURL
, unsigned defaultLineNumber
, unsigned defaultColumnNumber
)
175 const String
& name
= getCalculatedDisplayName(exec
, function
);
176 JSFunction
* jsFunction
= jsDynamicCast
<JSFunction
*>(function
);
177 if (jsFunction
&& !jsFunction
->isHostOrBuiltinFunction())
178 return CallIdentifier(name
.isEmpty() ? ASCIILiteral(AnonymousFunction
) : name
, jsFunction
->jsExecutable()->sourceURL(), jsFunction
->jsExecutable()->lineNo(), jsFunction
->jsExecutable()->startColumn());
179 return CallIdentifier(name
.isEmpty() ? ASCIILiteral(AnonymousFunction
) : name
, defaultSourceURL
, defaultLineNumber
, defaultColumnNumber
);