OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2010 Google Inc. All rights reserved. | 2 * Copyright (C) 2010 Google Inc. All rights reserved. |
3 * Copyright (C) 2012 Intel Inc. All rights reserved. | 3 * Copyright (C) 2012 Intel Inc. All rights reserved. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions are | 6 * modification, are permitted provided that the following conditions are |
7 * met: | 7 * met: |
8 * | 8 * |
9 * * Redistributions of source code must retain the above copyright | 9 * * Redistributions of source code must retain the above copyright |
10 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
(...skipping 17 matching lines...) Expand all Loading... |
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 */ | 30 */ |
31 | 31 |
32 #include "config.h" | 32 #include "config.h" |
33 #include "core/timing/PerformanceBase.h" | 33 #include "core/timing/PerformanceBase.h" |
34 | 34 |
35 #include "core/dom/Document.h" | 35 #include "core/dom/Document.h" |
36 #include "core/events/Event.h" | 36 #include "core/events/Event.h" |
37 #include "core/timing/PerformanceCompositeTiming.h" | 37 #include "core/timing/PerformanceCompositeTiming.h" |
| 38 #include "core/timing/PerformanceObserver.h" |
38 #include "core/timing/PerformanceRenderTiming.h" | 39 #include "core/timing/PerformanceRenderTiming.h" |
39 #include "core/timing/PerformanceResourceTiming.h" | 40 #include "core/timing/PerformanceResourceTiming.h" |
40 #include "core/timing/PerformanceUserTiming.h" | 41 #include "core/timing/PerformanceUserTiming.h" |
41 #include "platform/network/ResourceTimingInfo.h" | 42 #include "platform/network/ResourceTimingInfo.h" |
42 #include "platform/weborigin/SecurityOrigin.h" | 43 #include "platform/weborigin/SecurityOrigin.h" |
43 #include "wtf/CurrentTime.h" | 44 #include "wtf/CurrentTime.h" |
44 | 45 |
45 namespace blink { | 46 namespace blink { |
46 | 47 |
| 48 using PerformanceObserverVector = HeapVector<Member<PerformanceObserver>>; |
| 49 |
47 static const size_t defaultResourceTimingBufferSize = 150; | 50 static const size_t defaultResourceTimingBufferSize = 150; |
48 static const size_t defaultFrameTimingBufferSize = 150; | 51 static const size_t defaultFrameTimingBufferSize = 150; |
49 | 52 |
50 PerformanceBase::PerformanceBase(double timeOrigin) | 53 PerformanceBase::PerformanceBase(double timeOrigin) |
51 : m_frameTimingBufferSize(defaultFrameTimingBufferSize) | 54 : m_frameTimingBufferSize(defaultFrameTimingBufferSize) |
52 , m_resourceTimingBufferSize(defaultResourceTimingBufferSize) | 55 , m_resourceTimingBufferSize(defaultResourceTimingBufferSize) |
53 , m_timeOrigin(timeOrigin) | 56 , m_timeOrigin(timeOrigin) |
54 , m_userTiming(nullptr) | 57 , m_userTiming(nullptr) |
| 58 , m_observerFilterOptions(PerformanceEntry::Invalid) |
| 59 , m_deliverObservationsTimer(this, &PerformanceBase::deliverObservationsTime
rFired) |
55 { | 60 { |
56 } | 61 } |
57 | 62 |
58 PerformanceBase::~PerformanceBase() | 63 PerformanceBase::~PerformanceBase() |
59 { | 64 { |
60 } | 65 } |
61 | 66 |
62 const AtomicString& PerformanceBase::interfaceName() const | 67 const AtomicString& PerformanceBase::interfaceName() const |
63 { | 68 { |
64 return EventTargetNames::Performance; | 69 return EventTargetNames::Performance; |
(...skipping 16 matching lines...) Expand all Loading... |
81 entries.appendVector(m_userTiming->getMeasures()); | 86 entries.appendVector(m_userTiming->getMeasures()); |
82 } | 87 } |
83 | 88 |
84 std::sort(entries.begin(), entries.end(), PerformanceEntry::startTimeCompare
LessThan); | 89 std::sort(entries.begin(), entries.end(), PerformanceEntry::startTimeCompare
LessThan); |
85 return entries; | 90 return entries; |
86 } | 91 } |
87 | 92 |
88 PerformanceEntryVector PerformanceBase::getEntriesByType(const String& entryType
) | 93 PerformanceEntryVector PerformanceBase::getEntriesByType(const String& entryType
) |
89 { | 94 { |
90 PerformanceEntryVector entries; | 95 PerformanceEntryVector entries; |
| 96 PerformanceEntry::EntryType type = PerformanceEntry::toEntryTypeEnum(entryTy
pe); |
91 | 97 |
92 if (equalIgnoringCase(entryType, "resource")) { | 98 if (type == PerformanceEntry::Invalid) |
| 99 return entries; |
| 100 |
| 101 if (type == PerformanceEntry::Resource) { |
93 for (const auto& resource : m_resourceTimingBuffer) | 102 for (const auto& resource : m_resourceTimingBuffer) |
94 entries.append(resource); | 103 entries.append(resource); |
95 } | 104 } |
96 | 105 |
97 if (equalIgnoringCase(entryType, "composite") | 106 if (type == PerformanceEntry::Composite || type == PerformanceEntry::Render)
{ |
98 || equalIgnoringCase(entryType, "render")) { | |
99 for (const auto& frame : m_frameTimingBuffer) { | 107 for (const auto& frame : m_frameTimingBuffer) { |
100 if (equalIgnoringCase(entryType, frame->entryType())) { | 108 if (type == frame->entryTypeEnum()) { |
101 entries.append(frame); | 109 entries.append(frame); |
102 } | 110 } |
103 } | 111 } |
104 } | 112 } |
105 | 113 |
106 if (m_userTiming) { | 114 if (m_userTiming) { |
107 if (equalIgnoringCase(entryType, "mark")) | 115 if (type == PerformanceEntry::Mark) |
108 entries.appendVector(m_userTiming->getMarks()); | 116 entries.appendVector(m_userTiming->getMarks()); |
109 else if (equalIgnoringCase(entryType, "measure")) | 117 else if (type == PerformanceEntry::Measure) |
110 entries.appendVector(m_userTiming->getMeasures()); | 118 entries.appendVector(m_userTiming->getMeasures()); |
111 } | 119 } |
112 | 120 |
113 std::sort(entries.begin(), entries.end(), PerformanceEntry::startTimeCompare
LessThan); | 121 std::sort(entries.begin(), entries.end(), PerformanceEntry::startTimeCompare
LessThan); |
114 return entries; | 122 return entries; |
115 } | 123 } |
116 | 124 |
117 PerformanceEntryVector PerformanceBase::getEntriesByName(const String& name, con
st String& entryType) | 125 PerformanceEntryVector PerformanceBase::getEntriesByName(const String& name, con
st String& entryType) |
118 { | 126 { |
119 PerformanceEntryVector entries; | 127 PerformanceEntryVector entries; |
| 128 PerformanceEntry::EntryType type = PerformanceEntry::toEntryTypeEnum(entryTy
pe); |
120 | 129 |
121 if (entryType.isNull() || equalIgnoringCase(entryType, "resource")) { | 130 if (!entryType.isNull() && type == PerformanceEntry::Invalid) |
| 131 return entries; |
| 132 |
| 133 if (entryType.isNull() || type == PerformanceEntry::Resource) { |
122 for (const auto& resource : m_resourceTimingBuffer) { | 134 for (const auto& resource : m_resourceTimingBuffer) { |
123 if (resource->name() == name) | 135 if (resource->name() == name) |
124 entries.append(resource); | 136 entries.append(resource); |
125 } | 137 } |
126 } | 138 } |
127 | 139 |
128 if (entryType.isNull() || equalIgnoringCase(entryType, "composite") | 140 if (entryType.isNull() || type == PerformanceEntry::Composite || type == Per
formanceEntry::Render) { |
129 || equalIgnoringCase(entryType, "render")) { | |
130 for (const auto& frame : m_frameTimingBuffer) { | 141 for (const auto& frame : m_frameTimingBuffer) { |
131 if (frame->name() == name && (entryType.isNull() | 142 if (frame->name() == name && (entryType.isNull() |
132 || equalIgnoringCase(entryType, frame->entryType()))) { | 143 || equalIgnoringCase(entryType, frame->entryType()))) { |
133 entries.append(frame); | 144 entries.append(frame); |
134 } | 145 } |
135 } | 146 } |
136 } | 147 } |
137 | 148 |
138 if (m_userTiming) { | 149 if (m_userTiming) { |
139 if (entryType.isNull() || equalIgnoringCase(entryType, "mark")) | 150 if (entryType.isNull() || type == PerformanceEntry::Mark) |
140 entries.appendVector(m_userTiming->getMarks(name)); | 151 entries.appendVector(m_userTiming->getMarks(name)); |
141 if (entryType.isNull() || equalIgnoringCase(entryType, "measure")) | 152 if (entryType.isNull() || type == PerformanceEntry::Measure) |
142 entries.appendVector(m_userTiming->getMeasures(name)); | 153 entries.appendVector(m_userTiming->getMeasures(name)); |
143 } | 154 } |
144 | 155 |
145 std::sort(entries.begin(), entries.end(), PerformanceEntry::startTimeCompare
LessThan); | 156 std::sort(entries.begin(), entries.end(), PerformanceEntry::startTimeCompare
LessThan); |
146 return entries; | 157 return entries; |
147 } | 158 } |
148 | 159 |
149 void PerformanceBase::webkitClearResourceTimings() | 160 void PerformanceBase::webkitClearResourceTimings() |
150 { | 161 { |
151 m_resourceTimingBuffer.clear(); | 162 m_resourceTimingBuffer.clear(); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
204 for (const ResourceResponse& response : redirectChain) { | 215 for (const ResourceResponse& response : redirectChain) { |
205 if (!passesTimingAllowCheck(response, initiatorSecurityOrigin, emptyAtom
)) | 216 if (!passesTimingAllowCheck(response, initiatorSecurityOrigin, emptyAtom
)) |
206 return false; | 217 return false; |
207 } | 218 } |
208 | 219 |
209 return true; | 220 return true; |
210 } | 221 } |
211 | 222 |
212 void PerformanceBase::addResourceTiming(const ResourceTimingInfo& info) | 223 void PerformanceBase::addResourceTiming(const ResourceTimingInfo& info) |
213 { | 224 { |
214 if (isResourceTimingBufferFull()) | 225 if (isResourceTimingBufferFull() && !hasObserverFor(PerformanceEntry::Resour
ce)) |
215 return; | 226 return; |
216 SecurityOrigin* securityOrigin = nullptr; | 227 SecurityOrigin* securityOrigin = nullptr; |
217 if (ExecutionContext* context = executionContext()) | 228 if (ExecutionContext* context = executionContext()) |
218 securityOrigin = context->securityOrigin(); | 229 securityOrigin = context->securityOrigin(); |
219 if (!securityOrigin) | 230 if (!securityOrigin) |
220 return; | 231 return; |
221 | 232 |
222 const ResourceResponse& finalResponse = info.finalResponse(); | 233 const ResourceResponse& finalResponse = info.finalResponse(); |
223 bool allowTimingDetails = passesTimingAllowCheck(finalResponse, *securityOri
gin, info.originalTimingAllowOrigin()); | 234 bool allowTimingDetails = passesTimingAllowCheck(finalResponse, *securityOri
gin, info.originalTimingAllowOrigin()); |
224 double startTime = info.initialTime(); | 235 double startTime = info.initialTime(); |
225 | 236 |
226 if (info.redirectChain().isEmpty()) { | 237 if (info.redirectChain().isEmpty()) { |
227 PerformanceEntry* entry = PerformanceResourceTiming::create(info, timeOr
igin(), startTime, allowTimingDetails); | 238 PerformanceEntry* entry = PerformanceResourceTiming::create(info, timeOr
igin(), startTime, allowTimingDetails); |
228 addResourceTimingBuffer(entry); | 239 addResourceTimingBuffer(*entry); |
229 return; | 240 return; |
230 } | 241 } |
231 | 242 |
232 const Vector<ResourceResponse>& redirectChain = info.redirectChain(); | 243 const Vector<ResourceResponse>& redirectChain = info.redirectChain(); |
233 bool allowRedirectDetails = allowsTimingRedirect(redirectChain, finalRespons
e, *securityOrigin); | 244 bool allowRedirectDetails = allowsTimingRedirect(redirectChain, finalRespons
e, *securityOrigin); |
234 | 245 |
235 if (!allowRedirectDetails) { | 246 if (!allowRedirectDetails) { |
236 ResourceLoadTiming* finalTiming = finalResponse.resourceLoadTiming(); | 247 ResourceLoadTiming* finalTiming = finalResponse.resourceLoadTiming(); |
237 ASSERT(finalTiming); | 248 ASSERT(finalTiming); |
238 if (finalTiming) | 249 if (finalTiming) |
239 startTime = finalTiming->requestTime(); | 250 startTime = finalTiming->requestTime(); |
240 } | 251 } |
241 | 252 |
242 ResourceLoadTiming* lastRedirectTiming = redirectChain.last().resourceLoadTi
ming(); | 253 ResourceLoadTiming* lastRedirectTiming = redirectChain.last().resourceLoadTi
ming(); |
243 ASSERT(lastRedirectTiming); | 254 ASSERT(lastRedirectTiming); |
244 double lastRedirectEndTime = lastRedirectTiming->receiveHeadersEnd(); | 255 double lastRedirectEndTime = lastRedirectTiming->receiveHeadersEnd(); |
245 | 256 |
246 PerformanceEntry* entry = PerformanceResourceTiming::create(info, timeOrigin
(), startTime, lastRedirectEndTime, allowTimingDetails, allowRedirectDetails); | 257 PerformanceEntry* entry = PerformanceResourceTiming::create(info, timeOrigin
(), startTime, lastRedirectEndTime, allowTimingDetails, allowRedirectDetails); |
247 addResourceTimingBuffer(entry); | 258 notifyObserversOfEntry(*entry); |
| 259 if (!isResourceTimingBufferFull()) |
| 260 addResourceTimingBuffer(*entry); |
248 } | 261 } |
249 | 262 |
250 void PerformanceBase::addResourceTimingBuffer(PerformanceEntry* entry) | 263 void PerformanceBase::addResourceTimingBuffer(PerformanceEntry& entry) |
251 { | 264 { |
252 m_resourceTimingBuffer.append(entry); | 265 m_resourceTimingBuffer.append(&entry); |
253 | 266 |
254 if (isResourceTimingBufferFull()) | 267 if (isResourceTimingBufferFull()) |
255 dispatchEvent(Event::create(EventTypeNames::webkitresourcetimingbufferfu
ll)); | 268 dispatchEvent(Event::create(EventTypeNames::webkitresourcetimingbufferfu
ll)); |
256 } | 269 } |
257 | 270 |
258 bool PerformanceBase::isResourceTimingBufferFull() | 271 bool PerformanceBase::isResourceTimingBufferFull() |
259 { | 272 { |
260 return m_resourceTimingBuffer.size() >= m_resourceTimingBufferSize; | 273 return m_resourceTimingBuffer.size() >= m_resourceTimingBufferSize; |
261 } | 274 } |
262 | 275 |
263 void PerformanceBase::addRenderTiming(Document* initiatorDocument, unsigned sour
ceFrame, double startTime, double finishTime) | 276 void PerformanceBase::addRenderTiming(Document* initiatorDocument, unsigned sour
ceFrame, double startTime, double finishTime) |
264 { | 277 { |
265 if (isFrameTimingBufferFull()) | 278 if (isFrameTimingBufferFull() && !hasObserverFor(PerformanceEntry::Render)) |
266 return; | 279 return; |
267 | 280 |
268 PerformanceEntry* entry = PerformanceRenderTiming::create(initiatorDocument,
sourceFrame, startTime, finishTime); | 281 PerformanceEntry* entry = PerformanceRenderTiming::create(initiatorDocument,
sourceFrame, startTime, finishTime); |
269 addFrameTimingBuffer(entry); | 282 notifyObserversOfEntry(*entry); |
| 283 if (!isFrameTimingBufferFull()) |
| 284 addFrameTimingBuffer(*entry); |
270 } | 285 } |
271 | 286 |
272 void PerformanceBase::addCompositeTiming(Document* initiatorDocument, unsigned s
ourceFrame, double startTime) | 287 void PerformanceBase::addCompositeTiming(Document* initiatorDocument, unsigned s
ourceFrame, double startTime) |
273 { | 288 { |
274 if (isFrameTimingBufferFull()) | 289 if (isFrameTimingBufferFull() && !hasObserverFor(PerformanceEntry::Composite
)) |
275 return; | 290 return; |
276 | 291 |
277 PerformanceEntry* entry = PerformanceCompositeTiming::create(initiatorDocume
nt, sourceFrame, startTime); | 292 PerformanceEntry* entry = PerformanceCompositeTiming::create(initiatorDocume
nt, sourceFrame, startTime); |
278 addFrameTimingBuffer(entry); | 293 notifyObserversOfEntry(*entry); |
| 294 if (!isFrameTimingBufferFull()) |
| 295 addFrameTimingBuffer(*entry); |
279 } | 296 } |
280 | 297 |
281 void PerformanceBase::addFrameTimingBuffer(PerformanceEntry* entry) | 298 void PerformanceBase::addFrameTimingBuffer(PerformanceEntry& entry) |
282 { | 299 { |
283 m_frameTimingBuffer.append(entry); | 300 m_frameTimingBuffer.append(&entry); |
284 | 301 |
285 if (isFrameTimingBufferFull()) | 302 if (isFrameTimingBufferFull()) |
286 dispatchEvent(Event::create(EventTypeNames::frametimingbufferfull)); | 303 dispatchEvent(Event::create(EventTypeNames::frametimingbufferfull)); |
287 } | 304 } |
288 | 305 |
289 bool PerformanceBase::isFrameTimingBufferFull() | 306 bool PerformanceBase::isFrameTimingBufferFull() |
290 { | 307 { |
291 return m_frameTimingBuffer.size() >= m_frameTimingBufferSize; | 308 return m_frameTimingBuffer.size() >= m_frameTimingBufferSize; |
292 } | 309 } |
293 | 310 |
294 void PerformanceBase::mark(const String& markName, ExceptionState& exceptionStat
e) | 311 void PerformanceBase::mark(const String& markName, ExceptionState& exceptionStat
e) |
295 { | 312 { |
296 if (!m_userTiming) | 313 if (!m_userTiming) |
297 m_userTiming = UserTiming::create(this); | 314 m_userTiming = UserTiming::create(*this); |
298 m_userTiming->mark(markName, exceptionState); | 315 PerformanceEntry* entry = m_userTiming->mark(markName, exceptionState); |
| 316 if (entry) |
| 317 notifyObserversOfEntry(*entry); |
299 } | 318 } |
300 | 319 |
301 void PerformanceBase::clearMarks(const String& markName) | 320 void PerformanceBase::clearMarks(const String& markName) |
302 { | 321 { |
303 if (!m_userTiming) | 322 if (!m_userTiming) |
304 m_userTiming = UserTiming::create(this); | 323 m_userTiming = UserTiming::create(*this); |
305 m_userTiming->clearMarks(markName); | 324 m_userTiming->clearMarks(markName); |
306 } | 325 } |
307 | 326 |
308 void PerformanceBase::measure(const String& measureName, const String& startMark
, const String& endMark, ExceptionState& exceptionState) | 327 void PerformanceBase::measure(const String& measureName, const String& startMark
, const String& endMark, ExceptionState& exceptionState) |
309 { | 328 { |
310 if (!m_userTiming) | 329 if (!m_userTiming) |
311 m_userTiming = UserTiming::create(this); | 330 m_userTiming = UserTiming::create(*this); |
312 m_userTiming->measure(measureName, startMark, endMark, exceptionState); | 331 PerformanceEntry* entry = m_userTiming->measure(measureName, startMark, endM
ark, exceptionState); |
| 332 if (entry) |
| 333 notifyObserversOfEntry(*entry); |
313 } | 334 } |
314 | 335 |
315 void PerformanceBase::clearMeasures(const String& measureName) | 336 void PerformanceBase::clearMeasures(const String& measureName) |
316 { | 337 { |
317 if (!m_userTiming) | 338 if (!m_userTiming) |
318 m_userTiming = UserTiming::create(this); | 339 m_userTiming = UserTiming::create(*this); |
319 m_userTiming->clearMeasures(measureName); | 340 m_userTiming->clearMeasures(measureName); |
320 } | 341 } |
321 | 342 |
| 343 void PerformanceBase::registerPerformanceObserver(PerformanceObserver& observer) |
| 344 { |
| 345 m_observerFilterOptions |= observer.filterOptions(); |
| 346 m_observers.add(&observer); |
| 347 } |
| 348 |
| 349 void PerformanceBase::unregisterPerformanceObserver(PerformanceObserver& oldObse
rver) |
| 350 { |
| 351 m_observers.remove(&oldObserver); |
| 352 m_observerFilterOptions = PerformanceEntry::Invalid; |
| 353 for (const auto& observer : m_observers) { |
| 354 m_observerFilterOptions |= observer->filterOptions(); |
| 355 } |
| 356 } |
| 357 |
| 358 void PerformanceBase::notifyObserversOfEntry(PerformanceEntry& entry) |
| 359 { |
| 360 for (auto& observer : m_observers) { |
| 361 if (observer->filterOptions() & entry.entryTypeEnum()) |
| 362 observer->enqueuePerformanceEntry(entry); |
| 363 } |
| 364 } |
| 365 |
| 366 bool PerformanceBase::hasObserverFor(PerformanceEntry::EntryType filterType) |
| 367 { |
| 368 return m_observerFilterOptions & filterType; |
| 369 } |
| 370 |
| 371 void PerformanceBase::activateObserver(PerformanceObserver& observer) |
| 372 { |
| 373 if (m_activeObservers.isEmpty()) |
| 374 m_deliverObservationsTimer.startOneShot(0, FROM_HERE); |
| 375 |
| 376 m_activeObservers.add(&observer); |
| 377 } |
| 378 |
| 379 void PerformanceBase::resumeSuspendedObservers() |
| 380 { |
| 381 ASSERT(isMainThread()); |
| 382 if (m_suspendedObservers.isEmpty()) |
| 383 return; |
| 384 |
| 385 PerformanceObserverVector suspended; |
| 386 copyToVector(m_suspendedObservers, suspended); |
| 387 for (size_t i = 0; i < suspended.size(); ++i) { |
| 388 if (!suspended[i]->shouldBeSuspended()) { |
| 389 m_suspendedObservers.remove(suspended[i]); |
| 390 activateObserver(*suspended[i]); |
| 391 } |
| 392 } |
| 393 } |
| 394 |
| 395 void PerformanceBase::deliverObservationsTimerFired(Timer<PerformanceBase>*) |
| 396 { |
| 397 ASSERT(isMainThread()); |
| 398 PerformanceObserverVector observers; |
| 399 copyToVector(m_activeObservers, observers); |
| 400 m_activeObservers.clear(); |
| 401 for (size_t i = 0; i < observers.size(); ++i) { |
| 402 if (observers[i]->shouldBeSuspended()) |
| 403 m_suspendedObservers.add(observers[i]); |
| 404 else |
| 405 observers[i]->deliver(); |
| 406 } |
| 407 } |
| 408 |
322 double PerformanceBase::now() const | 409 double PerformanceBase::now() const |
323 { | 410 { |
324 double nowSeconds = monotonicallyIncreasingTime() - m_timeOrigin; | 411 double nowSeconds = monotonicallyIncreasingTime() - m_timeOrigin; |
325 const double resolutionSeconds = 0.000005; | 412 const double resolutionSeconds = 0.000005; |
326 return 1000.0 * floor(nowSeconds / resolutionSeconds) * resolutionSeconds; | 413 return 1000.0 * floor(nowSeconds / resolutionSeconds) * resolutionSeconds; |
327 } | 414 } |
328 | 415 |
329 DEFINE_TRACE(PerformanceBase) | 416 DEFINE_TRACE(PerformanceBase) |
330 { | 417 { |
331 visitor->trace(m_frameTimingBuffer); | 418 visitor->trace(m_frameTimingBuffer); |
332 visitor->trace(m_resourceTimingBuffer); | 419 visitor->trace(m_resourceTimingBuffer); |
333 visitor->trace(m_userTiming); | 420 visitor->trace(m_userTiming); |
| 421 visitor->trace(m_observers); |
| 422 visitor->trace(m_activeObservers); |
| 423 visitor->trace(m_suspendedObservers); |
334 EventTargetWithInlineData::trace(visitor); | 424 EventTargetWithInlineData::trace(visitor); |
335 } | 425 } |
336 | 426 |
337 } // namespace blink | 427 } // namespace blink |
OLD | NEW |