]>
Commit | Line | Data |
---|---|---|
9dae56ea | 1 | /* |
81345200 | 2 | * Copyright (C) 2008, 2012, 2014 Apple Inc. All rights reserved. |
9dae56ea A |
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. | |
81345200 | 13 | * 3. Neither the name of Apple Inc. ("Apple") nor the names of |
9dae56ea A |
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" | |
93a37866 | 30 | #include "LegacyProfiler.h" |
9dae56ea | 31 | |
9dae56ea | 32 | #include "CallFrame.h" |
f9bf01c6 | 33 | #include "CodeBlock.h" |
93a37866 | 34 | #include "CommonIdentifiers.h" |
14957cd0 | 35 | #include "InternalFunction.h" |
9dae56ea A |
36 | #include "JSFunction.h" |
37 | #include "JSGlobalObject.h" | |
ba379fdc | 38 | #include "Nodes.h" |
81345200 | 39 | #include "JSCInlines.h" |
9dae56ea A |
40 | #include "Profile.h" |
41 | #include "ProfileGenerator.h" | |
42 | #include "ProfileNode.h" | |
9dae56ea A |
43 | |
44 | namespace JSC { | |
45 | ||
46 | static const char* GlobalCodeExecution = "(program)"; | |
47 | static const char* AnonymousFunction = "(anonymous function)"; | |
48 | static unsigned ProfilesUID = 0; | |
49 | ||
81345200 | 50 | static CallIdentifier createCallIdentifierFromFunctionImp(ExecState*, JSObject*, const String& defaultSourceURL, unsigned defaultLineNumber, unsigned defaultColumnNumber); |
9dae56ea | 51 | |
ed1e77d3 | 52 | LegacyProfiler* LegacyProfiler::s_sharedLegacyProfiler = nullptr; |
9dae56ea | 53 | |
93a37866 | 54 | LegacyProfiler* LegacyProfiler::profiler() |
9dae56ea | 55 | { |
93a37866 A |
56 | if (!s_sharedLegacyProfiler) |
57 | s_sharedLegacyProfiler = new LegacyProfiler(); | |
58 | return s_sharedLegacyProfiler; | |
ed1e77d3 | 59 | } |
9dae56ea | 60 | |
ed1e77d3 | 61 | void LegacyProfiler::startProfiling(ExecState* exec, const String& title, PassRefPtr<Stopwatch> stopwatch) |
9dae56ea | 62 | { |
93a37866 A |
63 | if (!exec) |
64 | return; | |
65 | ||
9dae56ea A |
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. | |
93a37866 | 68 | JSGlobalObject* origin = exec->lexicalGlobalObject(); |
9dae56ea A |
69 | |
70 | for (size_t i = 0; i < m_currentProfiles.size(); ++i) { | |
71 | ProfileGenerator* profileGenerator = m_currentProfiles[i].get(); | |
14957cd0 | 72 | if (profileGenerator->origin() == origin && profileGenerator->title() == title) |
9dae56ea A |
73 | return; |
74 | } | |
75 | ||
81345200 | 76 | exec->vm().setEnabledProfiler(this); |
ed1e77d3 | 77 | RefPtr<ProfileGenerator> profileGenerator = ProfileGenerator::create(exec, title, ++ProfilesUID, stopwatch); |
9dae56ea A |
78 | m_currentProfiles.append(profileGenerator); |
79 | } | |
80 | ||
ed1e77d3 | 81 | RefPtr<Profile> LegacyProfiler::stopProfiling(ExecState* exec, const String& title) |
9dae56ea | 82 | { |
93a37866 | 83 | if (!exec) |
ed1e77d3 | 84 | return nullptr; |
93a37866 A |
85 | |
86 | JSGlobalObject* origin = exec->lexicalGlobalObject(); | |
9dae56ea A |
87 | for (ptrdiff_t i = m_currentProfiles.size() - 1; i >= 0; --i) { |
88 | ProfileGenerator* profileGenerator = m_currentProfiles[i].get(); | |
14957cd0 | 89 | if (profileGenerator->origin() == origin && (title.isNull() || profileGenerator->title() == title)) { |
9dae56ea A |
90 | profileGenerator->stopProfiling(); |
91 | RefPtr<Profile> returnProfile = profileGenerator->profile(); | |
92 | ||
93 | m_currentProfiles.remove(i); | |
94 | if (!m_currentProfiles.size()) | |
81345200 | 95 | exec->vm().setEnabledProfiler(nullptr); |
ed1e77d3 | 96 | |
9dae56ea A |
97 | return returnProfile; |
98 | } | |
99 | } | |
100 | ||
ed1e77d3 | 101 | return nullptr; |
9dae56ea A |
102 | } |
103 | ||
93a37866 | 104 | void LegacyProfiler::stopProfiling(JSGlobalObject* origin) |
14957cd0 A |
105 | { |
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()) | |
81345200 | 112 | origin->vm().setEnabledProfiler(nullptr); |
14957cd0 A |
113 | } |
114 | } | |
115 | } | |
116 | ||
ed1e77d3 | 117 | static inline void callFunctionForProfilesWithGroup(std::function<void(ProfileGenerator*)> callback, const Vector<RefPtr<ProfileGenerator>>& profiles, unsigned targetProfileGroup) |
9dae56ea | 118 | { |
ed1e77d3 A |
119 | for (const RefPtr<ProfileGenerator>& profile : profiles) { |
120 | if (profile->profileGroup() == targetProfileGroup || !profile->origin()) | |
121 | callback(profile.get()); | |
9dae56ea A |
122 | } |
123 | } | |
124 | ||
ed1e77d3 A |
125 | void LegacyProfiler::suspendProfiling(JSC::ExecState* exec) |
126 | { | |
127 | if (!exec) | |
128 | return; | |
129 | ||
130 | callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::setIsSuspended, std::placeholders::_1, true), m_currentProfiles, exec->lexicalGlobalObject()->profileGroup()); | |
131 | } | |
132 | ||
133 | void LegacyProfiler::unsuspendProfiling(JSC::ExecState* exec) | |
134 | { | |
135 | if (!exec) | |
136 | return; | |
137 | ||
138 | callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::setIsSuspended, std::placeholders::_1, false), m_currentProfiles, exec->lexicalGlobalObject()->profileGroup()); | |
139 | } | |
140 | ||
93a37866 | 141 | void LegacyProfiler::willExecute(ExecState* callerCallFrame, JSValue function) |
9dae56ea A |
142 | { |
143 | ASSERT(!m_currentProfiles.isEmpty()); | |
144 | ||
ed1e77d3 A |
145 | CallIdentifier callIdentifier = createCallIdentifier(callerCallFrame, function, StringImpl::empty(), 0, 0); |
146 | ||
147 | callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::willExecute, std::placeholders::_1, callerCallFrame, callIdentifier), m_currentProfiles, callerCallFrame->lexicalGlobalObject()->profileGroup()); | |
9dae56ea A |
148 | } |
149 | ||
81345200 | 150 | void LegacyProfiler::willExecute(ExecState* callerCallFrame, const String& sourceURL, unsigned startingLineNumber, unsigned startingColumnNumber) |
9dae56ea A |
151 | { |
152 | ASSERT(!m_currentProfiles.isEmpty()); | |
153 | ||
81345200 | 154 | CallIdentifier callIdentifier = createCallIdentifier(callerCallFrame, JSValue(), sourceURL, startingLineNumber, startingColumnNumber); |
14957cd0 | 155 | |
ed1e77d3 | 156 | callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::willExecute, std::placeholders::_1, callerCallFrame, callIdentifier), m_currentProfiles, callerCallFrame->lexicalGlobalObject()->profileGroup()); |
14957cd0 A |
157 | } |
158 | ||
93a37866 | 159 | void LegacyProfiler::didExecute(ExecState* callerCallFrame, JSValue function) |
14957cd0 A |
160 | { |
161 | ASSERT(!m_currentProfiles.isEmpty()); | |
9dae56ea | 162 | |
ed1e77d3 A |
163 | CallIdentifier callIdentifier = createCallIdentifier(callerCallFrame, function, StringImpl::empty(), 0, 0); |
164 | ||
165 | callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::didExecute, std::placeholders::_1, callerCallFrame, callIdentifier), m_currentProfiles, callerCallFrame->lexicalGlobalObject()->profileGroup()); | |
9dae56ea A |
166 | } |
167 | ||
81345200 | 168 | void LegacyProfiler::didExecute(ExecState* callerCallFrame, const String& sourceURL, unsigned startingLineNumber, unsigned startingColumnNumber) |
9dae56ea A |
169 | { |
170 | ASSERT(!m_currentProfiles.isEmpty()); | |
171 | ||
ed1e77d3 A |
172 | CallIdentifier callIdentifier = createCallIdentifier(callerCallFrame, JSValue(), sourceURL, startingLineNumber, startingColumnNumber); |
173 | ||
174 | callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::didExecute, std::placeholders::_1, callerCallFrame, callIdentifier), m_currentProfiles, callerCallFrame->lexicalGlobalObject()->profileGroup()); | |
9dae56ea A |
175 | } |
176 | ||
93a37866 | 177 | void LegacyProfiler::exceptionUnwind(ExecState* handlerCallFrame) |
9dae56ea A |
178 | { |
179 | ASSERT(!m_currentProfiles.isEmpty()); | |
180 | ||
ed1e77d3 A |
181 | CallIdentifier callIdentifier = createCallIdentifier(handlerCallFrame, JSValue(), StringImpl::empty(), 0, 0); |
182 | ||
183 | callFunctionForProfilesWithGroup(std::bind(&ProfileGenerator::exceptionUnwind, std::placeholders::_1, handlerCallFrame, callIdentifier), m_currentProfiles, handlerCallFrame->lexicalGlobalObject()->profileGroup()); | |
9dae56ea A |
184 | } |
185 | ||
81345200 | 186 | CallIdentifier LegacyProfiler::createCallIdentifier(ExecState* exec, JSValue functionValue, const String& defaultSourceURL, unsigned defaultLineNumber, unsigned defaultColumnNumber) |
9dae56ea | 187 | { |
f9bf01c6 | 188 | if (!functionValue) |
81345200 | 189 | return CallIdentifier(ASCIILiteral(GlobalCodeExecution), defaultSourceURL, defaultLineNumber, defaultColumnNumber); |
f9bf01c6 | 190 | if (!functionValue.isObject()) |
81345200 A |
191 | return CallIdentifier(ASCIILiteral("(unknown)"), defaultSourceURL, defaultLineNumber, defaultColumnNumber); |
192 | if (asObject(functionValue)->inherits(JSFunction::info()) || asObject(functionValue)->inherits(InternalFunction::info())) | |
193 | return createCallIdentifierFromFunctionImp(exec, asObject(functionValue), defaultSourceURL, defaultLineNumber, defaultColumnNumber); | |
ed1e77d3 A |
194 | if (asObject(functionValue)->inherits(JSCallee::info())) |
195 | return CallIdentifier(ASCIILiteral(GlobalCodeExecution), defaultSourceURL, defaultLineNumber, defaultColumnNumber); | |
81345200 | 196 | return CallIdentifier(asObject(functionValue)->methodTable()->className(asObject(functionValue)), defaultSourceURL, defaultLineNumber, defaultColumnNumber); |
9dae56ea A |
197 | } |
198 | ||
81345200 | 199 | CallIdentifier createCallIdentifierFromFunctionImp(ExecState* exec, JSObject* function, const String& defaultSourceURL, unsigned defaultLineNumber, unsigned defaultColumnNumber) |
9dae56ea | 200 | { |
93a37866 | 201 | const String& name = getCalculatedDisplayName(exec, function); |
6fe7ccc8 | 202 | JSFunction* jsFunction = jsDynamicCast<JSFunction*>(function); |
81345200 | 203 | if (jsFunction && !jsFunction->isHostOrBuiltinFunction()) |
ed1e77d3 | 204 | return CallIdentifier(name.isEmpty() ? ASCIILiteral(AnonymousFunction) : name, jsFunction->jsExecutable()->sourceURL(), jsFunction->jsExecutable()->firstLine(), jsFunction->jsExecutable()->startColumn()); |
81345200 | 205 | return CallIdentifier(name.isEmpty() ? ASCIILiteral(AnonymousFunction) : name, defaultSourceURL, defaultLineNumber, defaultColumnNumber); |
9dae56ea A |
206 | } |
207 | ||
208 | } // namespace JSC |