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

Side by Side Diff: sky/engine/core/inspector/AsyncCallStackTracker.cpp

Issue 727593004: Wire up the Inspector V8 Debugger (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 6 years, 1 month 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 "config.h"
32 #include "core/inspector/AsyncCallStackTracker.h"
33
34 #include "bindings/core/v8/V8Binding.h"
35 #include "bindings/core/v8/V8RecursionScope.h"
36 #include "core/dom/ExecutionContext.h"
37 // #include "core/dom/ExecutionContextTask.h"
38 #include "core/events/Event.h"
39 #include "core/events/EventTarget.h"
40 #include "wtf/text/StringBuilder.h"
41 #include "wtf/text/StringHash.h"
42 #include <v8.h>
43
44 namespace {
45
46 static const char setTimeoutName[] = "setTimeout";
47 static const char setIntervalName[] = "setInterval";
48 static const char requestAnimationFrameName[] = "requestAnimationFrame";
49 static const char enqueueMutationRecordName[] = "Mutation";
50
51 }
52
53 namespace blink {
54
55 void AsyncCallStackTracker::ExecutionContextData::contextDestroyed()
56 {
57 ASSERT(executionContext());
58 OwnPtr<ExecutionContextData> self = m_tracker->m_executionContextDataMap.tak e(executionContext());
59 ASSERT_UNUSED(self, self == this);
60 ContextLifecycleObserver::contextDestroyed();
61 }
62
63 int AsyncCallStackTracker::ExecutionContextData::circularSequentialID()
64 {
65 ++m_circularSequentialID;
66 if (m_circularSequentialID <= 0)
67 m_circularSequentialID = 1;
68 return m_circularSequentialID;
69 }
70
71 AsyncCallStackTracker::AsyncCallStack::AsyncCallStack(const String& description, const ScriptValue& callFrames)
72 : m_description(description)
73 , m_callFrames(callFrames)
74 {
75 }
76
77 AsyncCallStackTracker::AsyncCallStack::~AsyncCallStack()
78 {
79 }
80
81 AsyncCallStackTracker::AsyncCallStackTracker()
82 : m_maxAsyncCallStackDepth(0)
83 , m_nestedAsyncCallCount(0)
84 {
85 }
86
87 void AsyncCallStackTracker::setAsyncCallStackDepth(int depth)
88 {
89 if (depth <= 0) {
90 m_maxAsyncCallStackDepth = 0;
91 clear();
92 } else {
93 m_maxAsyncCallStackDepth = depth;
94 }
95 }
96
97 const AsyncCallStackTracker::AsyncCallChain* AsyncCallStackTracker::currentAsync CallChain() const
98 {
99 if (m_currentAsyncCallChain)
100 ensureMaxAsyncCallChainDepth(m_currentAsyncCallChain.get(), m_maxAsyncCa llStackDepth);
101 return m_currentAsyncCallChain.get();
102 }
103
104 void AsyncCallStackTracker::didInstallTimer(ExecutionContext* context, int timer Id, bool singleShot, const ScriptValue& callFrames)
105 {
106 ASSERT(context);
107 ASSERT(isEnabled());
108 if (!validateCallFrames(callFrames))
109 return;
110 ASSERT(timerId > 0);
111 ExecutionContextData* data = createContextDataIfNeeded(context);
112 data->m_timerCallChains.set(timerId, createAsyncCallChain(singleShot ? setTi meoutName : setIntervalName, callFrames));
113 if (!singleShot)
114 data->m_intervalTimerIds.add(timerId);
115 }
116
117 void AsyncCallStackTracker::didRemoveTimer(ExecutionContext* context, int timerI d)
118 {
119 ASSERT(context);
120 ASSERT(isEnabled());
121 if (timerId <= 0)
122 return;
123 ExecutionContextData* data = m_executionContextDataMap.get(context);
124 if (!data)
125 return;
126 data->m_intervalTimerIds.remove(timerId);
127 data->m_timerCallChains.remove(timerId);
128 }
129
130 void AsyncCallStackTracker::willFireTimer(ExecutionContext* context, int timerId )
131 {
132 ASSERT(context);
133 ASSERT(isEnabled());
134 ASSERT(timerId > 0);
135 ASSERT(!m_currentAsyncCallChain);
136 if (ExecutionContextData* data = m_executionContextDataMap.get(context)) {
137 if (data->m_intervalTimerIds.contains(timerId))
138 setCurrentAsyncCallChain(context, data->m_timerCallChains.get(timerI d));
139 else
140 setCurrentAsyncCallChain(context, data->m_timerCallChains.take(timer Id));
141 } else {
142 setCurrentAsyncCallChain(context, nullptr);
143 }
144 }
145
146 void AsyncCallStackTracker::didRequestAnimationFrame(ExecutionContext* context, int callbackId, const ScriptValue& callFrames)
147 {
148 ASSERT(context);
149 ASSERT(isEnabled());
150 if (!validateCallFrames(callFrames))
151 return;
152 ASSERT(callbackId > 0);
153 ExecutionContextData* data = createContextDataIfNeeded(context);
154 data->m_animationFrameCallChains.set(callbackId, createAsyncCallChain(reques tAnimationFrameName, callFrames));
155 }
156
157 void AsyncCallStackTracker::didCancelAnimationFrame(ExecutionContext* context, i nt callbackId)
158 {
159 ASSERT(context);
160 ASSERT(isEnabled());
161 if (callbackId <= 0)
162 return;
163 if (ExecutionContextData* data = m_executionContextDataMap.get(context))
164 data->m_animationFrameCallChains.remove(callbackId);
165 }
166
167 void AsyncCallStackTracker::willFireAnimationFrame(ExecutionContext* context, in t callbackId)
168 {
169 ASSERT(context);
170 ASSERT(isEnabled());
171 ASSERT(callbackId > 0);
172 ASSERT(!m_currentAsyncCallChain);
173 if (ExecutionContextData* data = m_executionContextDataMap.get(context))
174 setCurrentAsyncCallChain(context, data->m_animationFrameCallChains.take( callbackId));
175 else
176 setCurrentAsyncCallChain(context, nullptr);
177 }
178
179 void AsyncCallStackTracker::didEnqueueEvent(EventTarget* eventTarget, Event* eve nt, const ScriptValue& callFrames)
180 {
181 ASSERT(eventTarget->executionContext());
182 ASSERT(isEnabled());
183 if (!validateCallFrames(callFrames))
184 return;
185 ExecutionContextData* data = createContextDataIfNeeded(eventTarget->executio nContext());
186 data->m_eventCallChains.set(event, createAsyncCallChain(event->type(), callF rames));
187 }
188
189 void AsyncCallStackTracker::didRemoveEvent(EventTarget* eventTarget, Event* even t)
190 {
191 ASSERT(eventTarget->executionContext());
192 ASSERT(isEnabled());
193 if (ExecutionContextData* data = m_executionContextDataMap.get(eventTarget-> executionContext()))
194 data->m_eventCallChains.remove(event);
195 }
196
197 void AsyncCallStackTracker::willHandleEvent(EventTarget* eventTarget, Event* eve nt, EventListener* listener, bool useCapture)
198 {
199 ASSERT(eventTarget->executionContext());
200 ASSERT(isEnabled());
201 ExecutionContext* context = eventTarget->executionContext();
202 if (ExecutionContextData* data = m_executionContextDataMap.get(context))
203 setCurrentAsyncCallChain(context, data->m_eventCallChains.get(event));
204 else
205 setCurrentAsyncCallChain(context, nullptr);
206 }
207
208 void AsyncCallStackTracker::didEnqueueMutationRecord(ExecutionContext* context, MutationObserver* observer, const ScriptValue& callFrames)
209 {
210 ASSERT(context);
211 ASSERT(isEnabled());
212 if (!validateCallFrames(callFrames))
213 return;
214 ExecutionContextData* data = createContextDataIfNeeded(context);
215 data->m_mutationObserverCallChains.set(observer, createAsyncCallChain(enqueu eMutationRecordName, callFrames));
216 }
217
218 bool AsyncCallStackTracker::hasEnqueuedMutationRecord(ExecutionContext* context, MutationObserver* observer)
219 {
220 ASSERT(context);
221 ASSERT(isEnabled());
222 if (ExecutionContextData* data = m_executionContextDataMap.get(context))
223 return data->m_mutationObserverCallChains.contains(observer);
224 return false;
225 }
226
227 void AsyncCallStackTracker::didClearAllMutationRecords(ExecutionContext* context , MutationObserver* observer)
228 {
229 ASSERT(context);
230 ASSERT(isEnabled());
231 if (ExecutionContextData* data = m_executionContextDataMap.get(context))
232 data->m_mutationObserverCallChains.remove(observer);
233 }
234
235 void AsyncCallStackTracker::willDeliverMutationRecords(ExecutionContext* context , MutationObserver* observer)
236 {
237 ASSERT(context);
238 ASSERT(isEnabled());
239 if (ExecutionContextData* data = m_executionContextDataMap.get(context))
240 setCurrentAsyncCallChain(context, data->m_mutationObserverCallChains.tak e(observer));
241 else
242 setCurrentAsyncCallChain(context, nullptr);
243 }
244
245 // void AsyncCallStackTracker::didPostExecutionContextTask(ExecutionContext* con text, ExecutionContextTask* task, const ScriptValue& callFrames)
yurys 2014/11/14 07:38:31 Why not delete these methods completely if the con
246 // {
247 // ASSERT(context);
248 // ASSERT(isEnabled());
249 // if (!validateCallFrames(callFrames))
250 // return;
251 // ExecutionContextData* data = createContextDataIfNeeded(context);
252 // data->m_executionContextTaskCallChains.set(task, createAsyncCallChain(tas k->taskNameForInstrumentation(), callFrames));
253 // }
254
255 // void AsyncCallStackTracker::didKillAllExecutionContextTasks(ExecutionContext* context)
256 // {
257 // ASSERT(context);
258 // ASSERT(isEnabled());
259 // if (ExecutionContextData* data = m_executionContextDataMap.get(context))
260 // data->m_executionContextTaskCallChains.clear();
261 // }
262
263 // void AsyncCallStackTracker::willPerformExecutionContextTask(ExecutionContext* context, ExecutionContextTask* task)
264 // {
265 // ASSERT(context);
266 // ASSERT(isEnabled());
267 // if (ExecutionContextData* data = m_executionContextDataMap.get(context))
268 // setCurrentAsyncCallChain(context, data->m_executionContextTaskCallCha ins.take(task));
269 // else
270 // setCurrentAsyncCallChain(context, nullptr);
271 // }
272
273 static String makeV8AsyncTaskUniqueId(const String& eventName, int id)
274 {
275 StringBuilder builder;
276 builder.append(eventName);
277 builder.appendNumber(id);
278 return builder.toString();
279 }
280
281 void AsyncCallStackTracker::didEnqueueV8AsyncTask(ExecutionContext* context, con st String& eventName, int id, const ScriptValue& callFrames)
282 {
283 ASSERT(context);
284 ASSERT(isEnabled());
285 if (!validateCallFrames(callFrames))
286 return;
287 ExecutionContextData* data = createContextDataIfNeeded(context);
288 data->m_v8AsyncTaskCallChains.set(makeV8AsyncTaskUniqueId(eventName, id), cr eateAsyncCallChain(eventName, callFrames));
289 }
290
291 void AsyncCallStackTracker::willHandleV8AsyncTask(ExecutionContext* context, con st String& eventName, int id)
292 {
293 ASSERT(context);
294 ASSERT(isEnabled());
295 if (ExecutionContextData* data = m_executionContextDataMap.get(context))
296 setCurrentAsyncCallChain(context, data->m_v8AsyncTaskCallChains.take(mak eV8AsyncTaskUniqueId(eventName, id)));
297 else
298 setCurrentAsyncCallChain(context, nullptr);
299 }
300
301 int AsyncCallStackTracker::traceAsyncOperationStarting(ExecutionContext* context , const String& operationName, const ScriptValue& callFrames)
302 {
303 ASSERT(context);
304 ASSERT(isEnabled());
305 if (!validateCallFrames(callFrames))
306 return 0;
307 ExecutionContextData* data = createContextDataIfNeeded(context);
308 int id = data->circularSequentialID();
309 while (data->m_asyncOperationCallChains.contains(id))
310 id = data->circularSequentialID();
311 data->m_asyncOperationCallChains.set(id, createAsyncCallChain(operationName, callFrames));
312 return id;
313 }
314
315 void AsyncCallStackTracker::traceAsyncOperationCompleted(ExecutionContext* conte xt, int operationId)
316 {
317 ASSERT(context);
318 ASSERT(isEnabled());
319 if (operationId <= 0)
320 return;
321 if (ExecutionContextData* data = m_executionContextDataMap.get(context))
322 data->m_asyncOperationCallChains.remove(operationId);
323 }
324
325 void AsyncCallStackTracker::traceAsyncCallbackStarting(ExecutionContext* context , int operationId)
326 {
327 ASSERT(context);
328 ASSERT(isEnabled());
329 if (ExecutionContextData* data = m_executionContextDataMap.get(context))
330 setCurrentAsyncCallChain(context, operationId > 0 ? data->m_asyncOperati onCallChains.get(operationId) : nullptr);
331 else
332 setCurrentAsyncCallChain(context, nullptr);
333 }
334
335 void AsyncCallStackTracker::didFireAsyncCall()
336 {
337 clearCurrentAsyncCallChain();
338 }
339
340 PassRefPtr<AsyncCallStackTracker::AsyncCallChain> AsyncCallStackTracker::createA syncCallChain(const String& description, const ScriptValue& callFrames)
341 {
342 if (callFrames.isEmpty()) {
343 ASSERT(m_currentAsyncCallChain);
344 return m_currentAsyncCallChain; // Propogate async call stack chain.
345 }
346 RefPtr<AsyncCallChain> chain = adoptRef(m_currentAsyncCallChain ? new AsyncC allStackTracker::AsyncCallChain(*m_currentAsyncCallChain) : new AsyncCallStackTr acker::AsyncCallChain());
347 ensureMaxAsyncCallChainDepth(chain.get(), m_maxAsyncCallStackDepth - 1);
348 chain->m_callStacks.prepend(adoptRef(new AsyncCallStackTracker::AsyncCallSta ck(description, callFrames)));
349 return chain.release();
350 }
351
352 void AsyncCallStackTracker::setCurrentAsyncCallChain(ExecutionContext* context, PassRefPtr<AsyncCallChain> chain)
353 {
354 if (chain && !V8RecursionScope::recursionLevel(toIsolate(context))) {
355 // Current AsyncCallChain corresponds to the bottommost JS call frame.
356 m_currentAsyncCallChain = chain;
357 m_nestedAsyncCallCount = 1;
358 } else {
359 if (m_currentAsyncCallChain)
360 ++m_nestedAsyncCallCount;
361 }
362 }
363
364 void AsyncCallStackTracker::clearCurrentAsyncCallChain()
365 {
366 if (!m_nestedAsyncCallCount)
367 return;
368 --m_nestedAsyncCallCount;
369 if (!m_nestedAsyncCallCount)
370 m_currentAsyncCallChain.clear();
371 }
372
373 void AsyncCallStackTracker::ensureMaxAsyncCallChainDepth(AsyncCallChain* chain, unsigned maxDepth)
374 {
375 while (chain->m_callStacks.size() > maxDepth)
376 chain->m_callStacks.removeLast();
377 }
378
379 bool AsyncCallStackTracker::validateCallFrames(const ScriptValue& callFrames)
380 {
381 return !callFrames.isEmpty() || m_currentAsyncCallChain;
382 }
383
384 AsyncCallStackTracker::ExecutionContextData* AsyncCallStackTracker::createContex tDataIfNeeded(ExecutionContext* context)
385 {
386 ExecutionContextData* data = m_executionContextDataMap.get(context);
387 if (!data) {
388 data = m_executionContextDataMap.set(context, adoptPtr(new AsyncCallStac kTracker::ExecutionContextData(this, context)))
389 .storedValue->value.get();
390 }
391 return data;
392 }
393
394 void AsyncCallStackTracker::clear()
395 {
396 m_currentAsyncCallChain.clear();
397 m_nestedAsyncCallCount = 0;
398 m_executionContextDataMap.clear();
399 }
400
401 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698