Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(351)

Side by Side Diff: third_party/WebKit/Source/core/inspector/AsyncCallTracker.cpp

Issue 1857713004: DevTools: simplify the async instrumentation harness. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2013 Google 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 are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "core/inspector/AsyncCallTracker.h"
32
33 #include "core/dom/ContextLifecycleObserver.h"
34 #include "core/dom/ExecutionContext.h"
35 #include "core/dom/ExecutionContextTask.h"
36 #include "core/events/Event.h"
37 #include "core/events/EventTarget.h"
38 #include "core/inspector/AsyncOperationMap.h"
39 #include "core/xmlhttprequest/XMLHttpRequest.h"
40 #include "core/xmlhttprequest/XMLHttpRequestUpload.h"
41 #include "platform/ScriptForbiddenScope.h"
42 #include "wtf/text/StringBuilder.h"
43 #include "wtf/text/StringHash.h"
44
45 namespace {
46
47 static const char setTimeoutName[] = "setTimeout";
48 static const char setIntervalName[] = "setInterval";
49 static const char requestAnimationFrameName[] = "requestAnimationFrame";
50 static const char xhrSendName[] = "XMLHttpRequest.send";
51 static const char enqueueMutationRecordName[] = "Mutation";
52
53 }
54
55 namespace blink {
56
57 class AsyncCallTracker::ExecutionContextData final : public GarbageCollectedFina lized<ExecutionContextData>, public ContextLifecycleObserver {
58 USING_GARBAGE_COLLECTED_MIXIN(AsyncCallTracker::ExecutionContextData);
59 public:
60 ExecutionContextData(AsyncCallTracker* tracker, ExecutionContext* executionC ontext)
61 : ContextLifecycleObserver(executionContext)
62 , m_tracker(tracker)
63 , m_timerCallChains(tracker->m_debuggerAgent)
64 , m_animationFrameCallChains(tracker->m_debuggerAgent)
65 , m_eventCallChains(tracker->m_debuggerAgent)
66 , m_xhrCallChains(tracker->m_debuggerAgent)
67 , m_mutationObserverCallChains(tracker->m_debuggerAgent)
68 , m_executionContextTaskCallChains(tracker->m_debuggerAgent)
69 , m_asyncOperations(tracker->m_debuggerAgent)
70 {
71 }
72
73 void contextDestroyed() override
74 {
75 ASSERT(getExecutionContext());
76 RawPtr<ExecutionContextData> self = m_tracker->m_executionContextDataMap .take(getExecutionContext());
77 ASSERT_UNUSED(self, self == this);
78 ContextLifecycleObserver::contextDestroyed();
79 disposeCallChains();
80 }
81
82 void unobserve()
83 {
84 disposeCallChains();
85 ContextLifecycleObserver::clearContext();
86 }
87
88 DEFINE_INLINE_VIRTUAL_TRACE()
89 {
90 visitor->trace(m_tracker);
91 #if ENABLE(OILPAN)
92 visitor->trace(m_timerCallChains);
93 visitor->trace(m_animationFrameCallChains);
94 visitor->trace(m_eventCallChains);
95 visitor->trace(m_xhrCallChains);
96 visitor->trace(m_mutationObserverCallChains);
97 visitor->trace(m_executionContextTaskCallChains);
98 visitor->trace(m_asyncOperations);
99 #endif
100 ContextLifecycleObserver::trace(visitor);
101 }
102
103 Member<AsyncCallTracker> m_tracker;
104 HashSet<int> m_intervalTimerIds;
105 AsyncOperationMap<int> m_timerCallChains;
106 AsyncOperationMap<int> m_animationFrameCallChains;
107 AsyncOperationMap<Member<Event>> m_eventCallChains;
108 AsyncOperationMap<Member<EventTarget>> m_xhrCallChains;
109 AsyncOperationMap<Member<MutationObserver>> m_mutationObserverCallChains;
110 AsyncOperationMap<ExecutionContextTask*> m_executionContextTaskCallChains;
111 AsyncOperationMap<int> m_asyncOperations;
112
113 private:
114 void disposeCallChains()
115 {
116 m_timerCallChains.dispose();
117 m_animationFrameCallChains.dispose();
118 m_eventCallChains.dispose();
119 m_xhrCallChains.dispose();
120 m_mutationObserverCallChains.dispose();
121 m_executionContextTaskCallChains.dispose();
122 m_asyncOperations.dispose();
123 }
124 };
125
126 static XMLHttpRequest* toXmlHttpRequest(EventTarget* eventTarget)
127 {
128 const AtomicString& interfaceName = eventTarget->interfaceName();
129 if (interfaceName == EventTargetNames::XMLHttpRequest)
130 return static_cast<XMLHttpRequest*>(eventTarget);
131 if (interfaceName == EventTargetNames::XMLHttpRequestUpload)
132 return static_cast<XMLHttpRequestUpload*>(eventTarget)->xmlHttpRequest() ;
133 return nullptr;
134 }
135
136 AsyncCallTracker::AsyncCallTracker(V8DebuggerAgent* debuggerAgent, Instrumenting Agents* instrumentingAgents)
137 : m_debuggerAgent(debuggerAgent)
138 , m_instrumentingAgents(instrumentingAgents)
139 {
140 }
141
142 AsyncCallTracker::~AsyncCallTracker()
143 {
144 }
145
146 void AsyncCallTracker::asyncCallTrackingStateChanged(bool tracking)
147 {
148 m_instrumentingAgents->setAsyncCallTracker(tracking ? this : nullptr);
149 }
150
151 void AsyncCallTracker::resetAsyncOperations()
152 {
153 for (auto& it : m_executionContextDataMap)
154 it.value->unobserve();
155 m_executionContextDataMap.clear();
156 }
157
158 void AsyncCallTracker::didInstallTimer(ExecutionContext* context, int timerId, i nt timeout, bool singleShot)
159 {
160 ASSERT(context);
161 ASSERT(m_debuggerAgent->trackingAsyncCalls());
162 int operationId = m_debuggerAgent->traceAsyncOperationStarting(singleShot ? setTimeoutName : setIntervalName);
163 ASSERT(timerId > 0);
164 ExecutionContextData* data = createContextDataIfNeeded(context);
165 data->m_timerCallChains.set(timerId, operationId);
166 if (!singleShot)
167 data->m_intervalTimerIds.add(timerId);
168 }
169
170 void AsyncCallTracker::didRemoveTimer(ExecutionContext* context, int timerId)
171 {
172 ASSERT(context);
173 ASSERT(m_debuggerAgent->trackingAsyncCalls());
174 if (timerId <= 0)
175 return;
176 ExecutionContextData* data = m_executionContextDataMap.get(context);
177 if (!data)
178 return;
179 data->m_intervalTimerIds.remove(timerId);
180 data->m_timerCallChains.remove(timerId);
181 }
182
183 bool AsyncCallTracker::willFireTimer(ExecutionContext* context, int timerId)
184 {
185 ASSERT(context);
186 ASSERT(m_debuggerAgent->trackingAsyncCalls());
187 ASSERT(timerId > 0);
188 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) {
189 willFireAsyncCall(data->m_timerCallChains.get(timerId));
190 if (!data->m_intervalTimerIds.contains(timerId))
191 data->m_timerCallChains.remove(timerId);
192 } else {
193 willFireAsyncCall(V8DebuggerAgent::unknownAsyncOperationId);
194 }
195 return true;
196 }
197
198 void AsyncCallTracker::didRequestAnimationFrame(ExecutionContext* context, int c allbackId)
199 {
200 ASSERT(context);
201 ASSERT(m_debuggerAgent->trackingAsyncCalls());
202 int operationId = m_debuggerAgent->traceAsyncOperationStarting(requestAnimat ionFrameName);
203 ASSERT(callbackId > 0);
204 ExecutionContextData* data = createContextDataIfNeeded(context);
205 data->m_animationFrameCallChains.set(callbackId, operationId);
206 }
207
208 void AsyncCallTracker::didCancelAnimationFrame(ExecutionContext* context, int ca llbackId)
209 {
210 ASSERT(context);
211 ASSERT(m_debuggerAgent->trackingAsyncCalls());
212 if (callbackId <= 0)
213 return;
214 if (ExecutionContextData* data = m_executionContextDataMap.get(context))
215 data->m_animationFrameCallChains.remove(callbackId);
216 }
217
218 bool AsyncCallTracker::willFireAnimationFrame(ExecutionContext* context, int cal lbackId)
219 {
220 ASSERT(context);
221 ASSERT(m_debuggerAgent->trackingAsyncCalls());
222 ASSERT(callbackId > 0);
223 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) {
224 willFireAsyncCall(data->m_animationFrameCallChains.get(callbackId));
225 data->m_animationFrameCallChains.remove(callbackId);
226 } else {
227 willFireAsyncCall(V8DebuggerAgent::unknownAsyncOperationId);
228 }
229 return true;
230 }
231
232 void AsyncCallTracker::didEnqueueEvent(EventTarget* eventTarget, Event* event)
233 {
234 ASSERT(eventTarget->getExecutionContext());
235 ASSERT(m_debuggerAgent->trackingAsyncCalls());
236 ScriptForbiddenScope::AllowUserAgentScript allowScripting;
237 int operationId = m_debuggerAgent->traceAsyncOperationStarting(event->type() );
238 ExecutionContextData* data = createContextDataIfNeeded(eventTarget->getExecu tionContext());
239 data->m_eventCallChains.set(event, operationId);
240 }
241
242 void AsyncCallTracker::didRemoveEvent(EventTarget* eventTarget, Event* event)
243 {
244 ASSERT(eventTarget->getExecutionContext());
245 ASSERT(m_debuggerAgent->trackingAsyncCalls());
246 if (ExecutionContextData* data = m_executionContextDataMap.get(eventTarget-> getExecutionContext()))
247 data->m_eventCallChains.remove(event);
248 }
249
250 void AsyncCallTracker::willHandleEvent(EventTarget* eventTarget, Event* event, E ventListener* listener, bool useCapture)
251 {
252 ASSERT(eventTarget->getExecutionContext());
253 ASSERT(m_debuggerAgent->trackingAsyncCalls());
254 if (XMLHttpRequest* xhr = toXmlHttpRequest(eventTarget)) {
255 willHandleXHREvent(xhr, event);
256 } else {
257 ExecutionContext* context = eventTarget->getExecutionContext();
258 if (ExecutionContextData* data = m_executionContextDataMap.get(context))
259 willFireAsyncCall(data->m_eventCallChains.get(event));
260 else
261 willFireAsyncCall(V8DebuggerAgent::unknownAsyncOperationId);
262 }
263 }
264
265 void AsyncCallTracker::willLoadXHR(XMLHttpRequest* xhr, ThreadableLoaderClient*, const AtomicString&, const KURL&, bool async, PassRefPtr<EncodedFormData>, cons t HTTPHeaderMap&, bool)
266 {
267 ASSERT(xhr->getExecutionContext());
268 ASSERT(m_debuggerAgent->trackingAsyncCalls());
269 if (!async)
270 return;
271 int operationId = m_debuggerAgent->traceAsyncOperationStarting(xhrSendName);
272 ExecutionContextData* data = createContextDataIfNeeded(xhr->getExecutionCont ext());
273 data->m_xhrCallChains.set(xhr, operationId);
274 }
275
276 void AsyncCallTracker::didDispatchXHRLoadendEvent(XMLHttpRequest* xhr)
277 {
278 ASSERT(xhr->getExecutionContext());
279 ASSERT(m_debuggerAgent->trackingAsyncCalls());
280 if (ExecutionContextData* data = m_executionContextDataMap.get(xhr->getExecu tionContext()))
281 data->m_xhrCallChains.remove(xhr);
282 }
283
284 void AsyncCallTracker::willHandleXHREvent(XMLHttpRequest* xhr, Event* event)
285 {
286 ExecutionContext* context = xhr->getExecutionContext();
287 ASSERT(context);
288 ASSERT(m_debuggerAgent->trackingAsyncCalls());
289 if (ExecutionContextData* data = m_executionContextDataMap.get(context))
290 willFireAsyncCall(data->m_xhrCallChains.get(xhr));
291 else
292 willFireAsyncCall(V8DebuggerAgent::unknownAsyncOperationId);
293 }
294
295 void AsyncCallTracker::didEnqueueMutationRecord(ExecutionContext* context, Mutat ionObserver* observer)
296 {
297 ASSERT(context);
298 ASSERT(m_debuggerAgent->trackingAsyncCalls());
299 ExecutionContextData* data = createContextDataIfNeeded(context);
300 if (data->m_mutationObserverCallChains.contains(observer))
301 return;
302 ScriptForbiddenScope::AllowUserAgentScript allowScripting;
303 int operationId = m_debuggerAgent->traceAsyncOperationStarting(enqueueMutati onRecordName);
304 data->m_mutationObserverCallChains.set(observer, operationId);
305 }
306
307 void AsyncCallTracker::didClearAllMutationRecords(ExecutionContext* context, Mut ationObserver* observer)
308 {
309 ASSERT(context);
310 ASSERT(m_debuggerAgent->trackingAsyncCalls());
311 if (ExecutionContextData* data = m_executionContextDataMap.get(context))
312 data->m_mutationObserverCallChains.remove(observer);
313 }
314
315 void AsyncCallTracker::willDeliverMutationRecords(ExecutionContext* context, Mut ationObserver* observer)
316 {
317 ASSERT(context);
318 ASSERT(m_debuggerAgent->trackingAsyncCalls());
319 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) {
320 willFireAsyncCall(data->m_mutationObserverCallChains.get(observer));
321 data->m_mutationObserverCallChains.remove(observer);
322 } else {
323 willFireAsyncCall(V8DebuggerAgent::unknownAsyncOperationId);
324 }
325 }
326
327 void AsyncCallTracker::didPostExecutionContextTask(ExecutionContext* context, Ex ecutionContextTask* task)
328 {
329 ASSERT(context);
330 ASSERT(m_debuggerAgent->trackingAsyncCalls());
331 if (task->taskNameForInstrumentation().isEmpty())
332 return;
333 int operationId = m_debuggerAgent->traceAsyncOperationStarting(task->taskNam eForInstrumentation());
334 ExecutionContextData* data = createContextDataIfNeeded(context);
335 data->m_executionContextTaskCallChains.set(task, operationId);
336 }
337
338 void AsyncCallTracker::didKillAllExecutionContextTasks(ExecutionContext* context )
339 {
340 ASSERT(context);
341 ASSERT(m_debuggerAgent->trackingAsyncCalls());
342 if (ExecutionContextData* data = m_executionContextDataMap.get(context))
343 data->m_executionContextTaskCallChains.clear();
344 }
345
346 void AsyncCallTracker::willPerformExecutionContextTask(ExecutionContext* context , ExecutionContextTask* task)
347 {
348 ASSERT(context);
349 ASSERT(m_debuggerAgent->trackingAsyncCalls());
350 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) {
351 willFireAsyncCall(data->m_executionContextTaskCallChains.get(task));
352 data->m_executionContextTaskCallChains.remove(task);
353 } else {
354 willFireAsyncCall(V8DebuggerAgent::unknownAsyncOperationId);
355 }
356 }
357
358 int AsyncCallTracker::traceAsyncOperationStarting(ExecutionContext* context, con st String& operationName, int prevOperationId)
359 {
360 ScriptForbiddenScope::AllowUserAgentScript allowScripting;
361 ASSERT(context);
362 ASSERT(m_debuggerAgent->trackingAsyncCalls());
363 if (prevOperationId)
364 traceAsyncOperationCompleted(context, prevOperationId);
365 int operationId = m_debuggerAgent->traceAsyncOperationStarting(operationName );
366 ExecutionContextData* data = createContextDataIfNeeded(context);
367 data->m_asyncOperations.set(operationId, operationId);
368 return operationId;
369 }
370
371 void AsyncCallTracker::traceAsyncOperationCompleted(ExecutionContext* context, i nt operationId)
372 {
373 ASSERT(context);
374 ASSERT(m_debuggerAgent->trackingAsyncCalls());
375 if (operationId <= 0)
376 return;
377 if (ExecutionContextData* data = m_executionContextDataMap.get(context))
378 data->m_asyncOperations.remove(operationId);
379 }
380
381 void AsyncCallTracker::traceAsyncOperationCompletedCallbackStarting(ExecutionCon text* context, int operationId)
382 {
383 traceAsyncCallbackStarting(context, operationId);
384 traceAsyncOperationCompleted(context, operationId);
385 }
386
387 bool AsyncCallTracker::isKnownAsyncOperationId(ExecutionContext* context, int op erationId) const
388 {
389 if (operationId <= 0)
390 return false;
391 if (ExecutionContextData* data = m_executionContextDataMap.get(context))
392 return data->m_asyncOperations.contains(operationId);
393 return false;
394 }
395
396 void AsyncCallTracker::traceAsyncCallbackStarting(ExecutionContext* context, int operationId)
397 {
398 ASSERT(context);
399 ASSERT(m_debuggerAgent->trackingAsyncCalls());
400 ASSERT(operationId <= 0 || isKnownAsyncOperationId(context, operationId));
401 willFireAsyncCall(operationId > 0 ? operationId : V8DebuggerAgent::unknownAs yncOperationId);
402 }
403
404 void AsyncCallTracker::didFireAsyncCall()
405 {
406 m_debuggerAgent->traceAsyncCallbackCompleted();
407 }
408
409 void AsyncCallTracker::willFireAsyncCall(int operationId)
410 {
411 m_debuggerAgent->traceAsyncCallbackStarting(operationId);
412 }
413
414 AsyncCallTracker::ExecutionContextData* AsyncCallTracker::createContextDataIfNee ded(ExecutionContext* context)
415 {
416 ExecutionContextData* data = m_executionContextDataMap.get(context);
417 if (!data) {
418 data = m_executionContextDataMap.set(context, new AsyncCallTracker::Exec utionContextData(this, context))
419 .storedValue->value.get();
420 }
421 return data;
422 }
423
424 DEFINE_TRACE(AsyncCallTracker)
425 {
426 #if ENABLE(OILPAN)
427 visitor->trace(m_executionContextDataMap);
428 visitor->trace(m_instrumentingAgents);
429 #endif
430 }
431
432 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698