1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "config.h"
6 #include "core/inspector/InspectorTraceEvents.h"
7
8 #include "bindings/core/v8/ScriptCallStackFactory.h"
9 #include "bindings/core/v8/ScriptGCEvent.h"
10 #include "bindings/core/v8/ScriptSourceCode.h"
11 #include "core/events/Event.h"
12 #include "core/frame/FrameView.h"
13 #include "core/frame/LocalFrame.h"
14 #include "core/inspector/IdentifiersFactory.h"
15 #include "core/inspector/InspectorNodeIds.h"
16 #include "core/inspector/ScriptCallStack.h"
17 #include "core/page/Page.h"
18 #include "core/rendering/RenderImage.h"
19 #include "core/rendering/RenderLayer.h"
20 #include "core/rendering/RenderObject.h"
21 #include "core/workers/WorkerThread.h"
22 #include "core/xml/XMLHttpRequest.h"
23 #include "platform/JSONValues.h"
24 #include "platform/TracedValue.h"
25 #include "platform/graphics/GraphicsLayer.h"
26 #include "platform/network/ResourceRequest.h"
27 #include "platform/network/ResourceResponse.h"
28 #include "platform/weborigin/KURL.h"
29 #include "wtf/Vector.h"
30 #include <inttypes.h>
31
32 namespace blink {
33
34 static const unsigned maxInvalidationTrackingCallstackSize = 5;
35
36 namespace {
37
38 class JSCallStack : public TraceEvent::ConvertableToTraceFormat {
39 public:
JSCallStack(PassRefPtrWillBeRawPtr<ScriptCallStack> callstack)40 explicit JSCallStack(PassRefPtrWillBeRawPtr<ScriptCallStack> callstack)
41 {
42 m_serialized = callstack ? callstack->buildInspectorArray()->toJSONString() : "[]";
43 ASSERT(m_serialized.isSafeToSendToAnotherThread());
44 }
asTraceFormat() const45 virtual String asTraceFormat() const
46 {
47 return m_serialized;
48 }
49
50 private:
51 String m_serialized;
52 };
53
toHexString(const void * p)54 String toHexString(const void* p)
55 {
56 return String::format("0x%" PRIx64, static_cast<uint64>(reinterpret_cast<intptr_t>(p)));
57 }
58
59 }
60
beginData(FrameView * frameView)61 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorLayoutEvent::beginData(FrameView* frameView)
62 {
63 bool isPartial;
64 unsigned needsLayoutObjects;
65 unsigned totalObjects;
66 LocalFrame& frame = frameView->frame();
67 frame.countObjectsNeedingLayout(needsLayoutObjects, totalObjects, isPartial);
68
69 RefPtr<TracedValue> value = TracedValue::create();
70 value->setInteger("dirtyObjects", needsLayoutObjects);
71 value->setInteger("totalObjects", totalObjects);
72 value->setBoolean("partialLayout", isPartial);
73 value->setString("frame", toHexString(&frame));
74 return value;
75 }
76
createQuad(TracedValue * value,const char * name,const FloatQuad & quad)77 static void createQuad(TracedValue* value, const char* name, const FloatQuad& quad)
78 {
79 value->beginArray(name);
80 value->pushDouble(quad.p1().x());
81 value->pushDouble(quad.p1().y());
82 value->pushDouble(quad.p2().x());
83 value->pushDouble(quad.p2().y());
84 value->pushDouble(quad.p3().x());
85 value->pushDouble(quad.p3().y());
86 value->pushDouble(quad.p4().x());
87 value->pushDouble(quad.p4().y());
88 value->endArray();
89 }
90
setGeneratingNodeInfo(TracedValue * value,const RenderObject * renderer,const char * idFieldName,const char * nameFieldName=0)91 static void setGeneratingNodeInfo(TracedValue* value, const RenderObject* renderer, const char* idFieldName, const char* nameFieldName = 0)
92 {
93 Node* node = 0;
94 for (; renderer && !node; renderer = renderer->parent())
95 node = renderer->generatingNode();
96 if (!node)
97 return;
98 value->setInteger(idFieldName, InspectorNodeIds::idForNode(node));
99 if (nameFieldName)
100 value->setString(nameFieldName, node->debugName());
101 }
102
endData(RenderObject * rootForThisLayout)103 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorLayoutEvent::endData(RenderObject* rootForThisLayout)
104 {
105 Vector<FloatQuad> quads;
106 rootForThisLayout->absoluteQuads(quads);
107
108 RefPtr<TracedValue> value = TracedValue::create();
109 if (quads.size() >= 1) {
110 createQuad(value.get(), "root", quads[0]);
111 setGeneratingNodeInfo(value.get(), rootForThisLayout, "rootNode");
112 } else {
113 ASSERT_NOT_REACHED();
114 }
115 return value;
116 }
117
data(const RenderObject * renderer)118 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorLayoutInvalidationTrackingEvent::data(const RenderObject* renderer)
119 {
120 ASSERT(renderer);
121 RefPtr<TracedValue> value = TracedValue::create();
122 value->setString("frame", toHexString(renderer->frame()));
123 setGeneratingNodeInfo(value.get(), renderer, "nodeId", "nodeName");
124 RefPtrWillBeRawPtr<ScriptCallStack> callstack = createScriptCallStack(maxInvalidationTrackingCallstackSize, true);
125 value->setString("callstack", callstack ? callstack->buildInspectorArray()->toJSONString() : "[]");
126 return value;
127 }
128
data(const RenderObject * renderer,const RenderObject * paintContainer)129 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorPaintInvalidationTrackingEvent::data(const RenderObject* renderer, const RenderObject* paintContainer)
130 {
131 ASSERT(renderer);
132 RefPtr<TracedValue> value = TracedValue::create();
133 value->setString("frame", toHexString(renderer->frame()));
134 setGeneratingNodeInfo(value.get(), paintContainer, "paintId");
135 setGeneratingNodeInfo(value.get(), renderer, "nodeId", "nodeName");
136 return value;
137 }
138
data(unsigned long identifier,LocalFrame * frame,const ResourceRequest & request)139 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorSendRequestEvent::data(unsigned long identifier, LocalFrame* frame, const ResourceRequest& request)
140 {
141 String requestId = IdentifiersFactory::requestId(identifier);
142
143 RefPtr<TracedValue> value = TracedValue::create();
144 value->setString("requestId", requestId);
145 value->setString("frame", toHexString(frame));
146 value->setString("url", request.url().string());
147 value->setString("requestMethod", request.httpMethod());
148 return value;
149 }
150
data(unsigned long identifier,LocalFrame * frame,const ResourceResponse & response)151 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorReceiveResponseEvent::data(unsigned long identifier, LocalFrame* frame, const ResourceResponse& response)
152 {
153 String requestId = IdentifiersFactory::requestId(identifier);
154
155 RefPtr<TracedValue> value = TracedValue::create();
156 value->setString("requestId", requestId);
157 value->setString("frame", toHexString(frame));
158 value->setInteger("statusCode", response.httpStatusCode());
159 value->setString("mimeType", response.mimeType().string().isolatedCopy());
160 return value;
161 }
162
data(unsigned long identifier,LocalFrame * frame,int encodedDataLength)163 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorReceiveDataEvent::data(unsigned long identifier, LocalFrame* frame, int encodedDataLength)
164 {
165 String requestId = IdentifiersFactory::requestId(identifier);
166
167 RefPtr<TracedValue> value = TracedValue::create();
168 value->setString("requestId", requestId);
169 value->setString("frame", toHexString(frame));
170 value->setInteger("encodedDataLength", encodedDataLength);
171 return value;
172 }
173
data(unsigned long identifier,double finishTime,bool didFail)174 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorResourceFinishEvent::data(unsigned long identifier, double finishTime, bool didFail)
175 {
176 String requestId = IdentifiersFactory::requestId(identifier);
177
178 RefPtr<TracedValue> value = TracedValue::create();
179 value->setString("requestId", requestId);
180 value->setBoolean("didFail", didFail);
181 if (finishTime)
182 value->setDouble("networkTime", finishTime);
183 return value;
184 }
185
frameForExecutionContext(ExecutionContext * context)186 static LocalFrame* frameForExecutionContext(ExecutionContext* context)
187 {
188 LocalFrame* frame = 0;
189 if (context->isDocument())
190 frame = toDocument(context)->frame();
191 return frame;
192 }
193
genericTimerData(ExecutionContext * context,int timerId)194 static PassRefPtr<TracedValue> genericTimerData(ExecutionContext* context, int timerId)
195 {
196 RefPtr<TracedValue> value = TracedValue::create();
197 value->setInteger("timerId", timerId);
198 if (LocalFrame* frame = frameForExecutionContext(context))
199 value->setString("frame", toHexString(frame));
200 return value.release();
201 }
202
data(ExecutionContext * context,int timerId,int timeout,bool singleShot)203 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorTimerInstallEvent::data(ExecutionContext* context, int timerId, int timeout, bool singleShot)
204 {
205 RefPtr<TracedValue> value = genericTimerData(context, timerId);
206 value->setInteger("timeout", timeout);
207 value->setBoolean("singleShot", singleShot);
208 return value;
209 }
210
data(ExecutionContext * context,int timerId)211 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorTimerRemoveEvent::data(ExecutionContext* context, int timerId)
212 {
213 return genericTimerData(context, timerId);
214 }
215
data(ExecutionContext * context,int timerId)216 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorTimerFireEvent::data(ExecutionContext* context, int timerId)
217 {
218 return genericTimerData(context, timerId);
219 }
220
data(Document * document,int callbackId)221 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorAnimationFrameEvent::data(Document* document, int callbackId)
222 {
223 RefPtr<TracedValue> value = TracedValue::create();
224 value->setInteger("id", callbackId);
225 value->setString("frame", toHexString(document->frame()));
226 return value;
227 }
228
data(Document * document,unsigned long identifier,const KURL & url,const String & protocol)229 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorWebSocketCreateEvent::data(Document* document, unsigned long identifier, const KURL& url, const String& protocol)
230 {
231 RefPtr<TracedValue> value = TracedValue::create();
232 value->setInteger("identifier", identifier);
233 value->setString("url", url.string());
234 value->setString("frame", toHexString(document->frame()));
235 if (!protocol.isNull())
236 value->setString("webSocketProtocol", protocol);
237 return value;
238 }
239
data(Document * document,unsigned long identifier)240 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorWebSocketEvent::data(Document* document, unsigned long identifier)
241 {
242 RefPtr<TracedValue> value = TracedValue::create();
243 value->setInteger("identifier", identifier);
244 value->setString("frame", toHexString(document->frame()));
245 return value;
246 }
247
beginData(Document * document,unsigned startLine)248 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorParseHtmlEvent::beginData(Document* document, unsigned startLine)
249 {
250 RefPtr<TracedValue> value = TracedValue::create();
251 value->setInteger("startLine", startLine);
252 value->setString("frame", toHexString(document->frame()));
253 return value;
254 }
255
data(ExecutionContext * context,XMLHttpRequest * request)256 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorXhrReadyStateChangeEvent::data(ExecutionContext* context, XMLHttpRequest* request)
257 {
258 RefPtr<TracedValue> value = TracedValue::create();
259 value->setString("url", request->url().string());
260 value->setInteger("readyState", request->readyState());
261 if (LocalFrame* frame = frameForExecutionContext(context))
262 value->setString("frame", toHexString(frame));
263 return value;
264 }
265
data(ExecutionContext * context,XMLHttpRequest * request)266 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorXhrLoadEvent::data(ExecutionContext* context, XMLHttpRequest* request)
267 {
268 RefPtr<TracedValue> value = TracedValue::create();
269 value->setString("url", request->url().string());
270 if (LocalFrame* frame = frameForExecutionContext(context))
271 value->setString("frame", toHexString(frame));
272 return value;
273 }
274
localToPageQuad(const RenderObject & renderer,const LayoutRect & rect,FloatQuad * quad)275 static void localToPageQuad(const RenderObject& renderer, const LayoutRect& rect, FloatQuad* quad)
276 {
277 LocalFrame* frame = renderer.frame();
278 FrameView* view = frame->view();
279 FloatQuad absolute = renderer.localToAbsoluteQuad(FloatQuad(rect));
280 quad->setP1(view->contentsToRootView(roundedIntPoint(absolute.p1())));
281 quad->setP2(view->contentsToRootView(roundedIntPoint(absolute.p2())));
282 quad->setP3(view->contentsToRootView(roundedIntPoint(absolute.p3())));
283 quad->setP4(view->contentsToRootView(roundedIntPoint(absolute.p4())));
284 }
285
286 const char InspectorLayerInvalidationTrackingEvent::SquashingLayerGeometryWasUpdated[] = "Squashing layer geometry was updated.";
287 const char InspectorLayerInvalidationTrackingEvent::AddedToSquashingLayer[] = "The layer may have been added to an already-existing squashing layer.";
288 const char InspectorLayerInvalidationTrackingEvent::RemovedFromSquashingLayer[] = "Removed the layer from a squashing layer.";
289 const char InspectorLayerInvalidationTrackingEvent::ReflectionLayerChanged[] = "Reflection layer change.";
290 const char InspectorLayerInvalidationTrackingEvent::NewCompositedLayer[] = "Assigned a new composited layer.";
291 const char InspectorLayerInvalidationTrackingEvent::AncestorRequiresNewLayer[] = "A new composited layer is needed based on the RenderLayer's compositing ancestor's properties.";
292
data(const RenderLayer * layer,const char * reason)293 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorLayerInvalidationTrackingEvent::data(const RenderLayer* layer, const char* reason)
294 {
295 const RenderObject* paintInvalidationContainer = layer->renderer()->containerForPaintInvalidation();
296
297 RefPtr<TracedValue> value = TracedValue::create();
298 value->setString("frame", toHexString(paintInvalidationContainer->frame()));
299 setGeneratingNodeInfo(value.get(), paintInvalidationContainer, "paintId");
300 value->setString("reason", reason);
301 return value;
302 }
303
data(RenderObject * renderer,const LayoutRect & clipRect,const GraphicsLayer * graphicsLayer)304 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorPaintEvent::data(RenderObject* renderer, const LayoutRect& clipRect, const GraphicsLayer* graphicsLayer)
305 {
306 RefPtr<TracedValue> value = TracedValue::create();
307 value->setString("frame", toHexString(renderer->frame()));
308 FloatQuad quad;
309 localToPageQuad(*renderer, clipRect, &quad);
310 createQuad(value.get(), "clip", quad);
311 setGeneratingNodeInfo(value.get(), renderer, "nodeId");
312 int graphicsLayerId = graphicsLayer ? graphicsLayer->platformLayer()->id() : 0;
313 value->setInteger("layerId", graphicsLayerId);
314 return value;
315 }
316
data(LocalFrame * frame)317 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorMarkLoadEvent::data(LocalFrame* frame)
318 {
319 RefPtr<TracedValue> value = TracedValue::create();
320 value->setString("frame", toHexString(frame));
321 bool isMainFrame = frame && frame->isMainFrame();
322 value->setBoolean("isMainFrame", isMainFrame);
323 return value;
324 }
325
data(RenderObject * renderer)326 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorScrollLayerEvent::data(RenderObject* renderer)
327 {
328 RefPtr<TracedValue> value = TracedValue::create();
329 value->setString("frame", toHexString(renderer->frame()));
330 setGeneratingNodeInfo(value.get(), renderer, "nodeId");
331 return value;
332 }
333
data(LocalFrame * frame,const String & url,int lineNumber)334 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorEvaluateScriptEvent::data(LocalFrame* frame, const String& url, int lineNumber)
335 {
336 RefPtr<TracedValue> value = TracedValue::create();
337 value->setString("frame", toHexString(frame));
338 value->setString("url", url);
339 value->setInteger("lineNumber", lineNumber);
340 return value;
341 }
342
data(ExecutionContext * context,int scriptId,const String & scriptName,int scriptLine)343 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorFunctionCallEvent::data(ExecutionContext* context, int scriptId, const String& scriptName, int scriptLine)
344 {
345 RefPtr<TracedValue> value = TracedValue::create();
346 value->setString("scriptId", String::number(scriptId));
347 value->setString("scriptName", scriptName);
348 value->setInteger("scriptLine", scriptLine);
349 if (LocalFrame* frame = frameForExecutionContext(context))
350 value->setString("frame", toHexString(frame));
351 return value;
352 }
353
data(const RenderImage & renderImage)354 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorPaintImageEvent::data(const RenderImage& renderImage)
355 {
356 RefPtr<TracedValue> value = TracedValue::create();
357 setGeneratingNodeInfo(value.get(), &renderImage, "nodeId");
358 if (const ImageResource* resource = renderImage.cachedImage())
359 value->setString("url", resource->url().string());
360 return value;
361 }
362
usedHeapSize()363 static size_t usedHeapSize()
364 {
365 HeapInfo info;
366 ScriptGCEvent::getHeapSize(info);
367 return info.usedJSHeapSize;
368 }
369
data()370 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorUpdateCountersEvent::data()
371 {
372 RefPtr<TracedValue> value = TracedValue::create();
373 if (isMainThread()) {
374 value->setInteger("documents", InspectorCounters::counterValue(InspectorCounters::DocumentCounter));
375 value->setInteger("nodes", InspectorCounters::counterValue(InspectorCounters::NodeCounter));
376 value->setInteger("jsEventListeners", InspectorCounters::counterValue(InspectorCounters::JSEventListenerCounter));
377 }
378 value->setDouble("jsHeapSizeUsed", static_cast<double>(usedHeapSize()));
379 return value;
380 }
381
currentCallStack()382 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorCallStackEvent::currentCallStack()
383 {
384 return adoptRef(new JSCallStack(createScriptCallStack(ScriptCallStack::maxCallStackSizeToCapture, true)));
385 }
386
data(const Event & event)387 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorEventDispatchEvent::data(const Event& event)
388 {
389 RefPtr<TracedValue> value = TracedValue::create();
390 value->setString("type", event.type());
391 return value;
392 }
393
data(ExecutionContext * context,const String & message)394 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorTimeStampEvent::data(ExecutionContext* context, const String& message)
395 {
396 RefPtr<TracedValue> value = TracedValue::create();
397 value->setString("message", message);
398 if (LocalFrame* frame = frameForExecutionContext(context))
399 value->setString("frame", toHexString(frame));
400 return value;
401 }
402
data(const String & sessionId,WorkerThread * workerThread)403 PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorTracingSessionIdForWorkerEvent::data(const String& sessionId, WorkerThread* workerThread)
404 {
405 RefPtr<TracedValue> value = TracedValue::create();
406 value->setString("sessionId", sessionId);
407 value->setDouble("workerThreadId", workerThread->platformThreadId());
408 return value;
409 }
410
411 }
412