Web Inspector: Include Garbage Collection Event in Timeline
[WebKit-https.git] / Source / JavaScriptCore / inspector / agents / InspectorHeapAgent.cpp
1 /*
2  * Copyright (C) 2015 Apple 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
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "InspectorHeapAgent.h"
28
29 #include "InspectorEnvironment.h"
30 #include "VM.h"
31 #include <wtf/RunLoop.h>
32 #include <wtf/Stopwatch.h>
33
34 using namespace JSC;
35
36 namespace Inspector {
37
38 InspectorHeapAgent::InspectorHeapAgent(AgentContext& context)
39     : InspectorAgentBase(ASCIILiteral("Heap"))
40     , m_frontendDispatcher(std::make_unique<HeapFrontendDispatcher>(context.frontendRouter))
41     , m_backendDispatcher(HeapBackendDispatcher::create(context.backendDispatcher, this))
42     , m_environment(context.environment)
43     , m_weakPtrFactory(this)
44 {
45 }
46
47 InspectorHeapAgent::~InspectorHeapAgent()
48 {
49 }
50
51 void InspectorHeapAgent::didCreateFrontendAndBackend(FrontendRouter*, BackendDispatcher*)
52 {
53 }
54
55 void InspectorHeapAgent::willDestroyFrontendAndBackend(DisconnectReason)
56 {
57     ErrorString ignored;
58     disable(ignored);
59 }
60
61 void InspectorHeapAgent::enable(ErrorString&)
62 {
63     if (m_enabled)
64         return;
65
66     m_enabled = true;
67
68     m_environment.vm().heap.addObserver(this);
69 }
70
71 void InspectorHeapAgent::disable(ErrorString&)
72 {
73     if (!m_enabled)
74         return;
75
76     m_enabled = false;
77
78     m_environment.vm().heap.removeObserver(this);
79 }
80
81 void InspectorHeapAgent::gc(ErrorString&)
82 {
83     VM& vm = m_environment.vm();
84     JSLockHolder lock(vm);
85     sanitizeStackForVM(&vm);
86     vm.heap.collectAllGarbage();
87 }
88
89 static Inspector::Protocol::Heap::GarbageCollection::Type protocolTypeForHeapOperation(HeapOperation operation)
90 {
91     switch (operation) {
92     case FullCollection:
93         return Inspector::Protocol::Heap::GarbageCollection::Type::Full;
94     case EdenCollection:
95         return Inspector::Protocol::Heap::GarbageCollection::Type::Partial;
96     default:
97         ASSERT_NOT_REACHED();
98         return Inspector::Protocol::Heap::GarbageCollection::Type::Full;
99     }
100 }
101
102 void InspectorHeapAgent::willGarbageCollect()
103 {
104     ASSERT(m_enabled);
105     ASSERT(std::isnan(m_gcStartTime));
106
107     m_gcStartTime = m_environment.executionStopwatch()->elapsedTime();
108 }
109
110 void InspectorHeapAgent::didGarbageCollect(HeapOperation operation)
111 {
112     ASSERT(m_enabled);
113     ASSERT(!std::isnan(m_gcStartTime));
114
115     // FIXME: Include number of bytes freed by collection.
116
117     double startTime = m_gcStartTime;
118     double endTime = m_environment.executionStopwatch()->elapsedTime();
119
120     // Dispatch the event asynchronously because this method may be
121     // called between collection and sweeping and we don't want to
122     // create unexpected JavaScript allocations that the Sweeper does
123     // not expect to encounter. JavaScript allocations could happen
124     // with WebKitLegacy's in process inspector which shares the same
125     // VM as the inspected page.
126
127     auto weakThis = m_weakPtrFactory.createWeakPtr();
128     RunLoop::current().dispatch([weakThis, startTime, endTime, operation]() {
129         if (!weakThis)
130             return;
131
132         auto collection = Inspector::Protocol::Heap::GarbageCollection::create()
133             .setType(protocolTypeForHeapOperation(operation))
134             .setStartTime(startTime)
135             .setEndTime(endTime)
136             .release();
137
138         weakThis->m_frontendDispatcher->garbageCollected(WTF::move(collection));
139     });
140
141     m_gcStartTime = NAN;
142 }
143
144 } // namespace Inspector