Remove excessive headers from JavaScriptCore
[WebKit-https.git] / Source / JavaScriptCore / inspector / agents / InspectorHeapAgent.cpp
1 /*
2  * Copyright (C) 2015-2016 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 "HeapProfiler.h"
30 #include "HeapSnapshot.h"
31 #include "InjectedScript.h"
32 #include "InjectedScriptManager.h"
33 #include "InspectorEnvironment.h"
34 #include "JSCInlines.h"
35 #include "VM.h"
36 #include <wtf/Stopwatch.h>
37
38 using namespace JSC;
39
40 namespace Inspector {
41
42 InspectorHeapAgent::InspectorHeapAgent(AgentContext& context)
43     : InspectorAgentBase(ASCIILiteral("Heap"))
44     , m_injectedScriptManager(context.injectedScriptManager)
45     , m_frontendDispatcher(std::make_unique<HeapFrontendDispatcher>(context.frontendRouter))
46     , m_backendDispatcher(HeapBackendDispatcher::create(context.backendDispatcher, this))
47     , m_environment(context.environment)
48 {
49 }
50
51 InspectorHeapAgent::~InspectorHeapAgent()
52 {
53 }
54
55 void InspectorHeapAgent::didCreateFrontendAndBackend(FrontendRouter*, BackendDispatcher*)
56 {
57 }
58
59 void InspectorHeapAgent::willDestroyFrontendAndBackend(DisconnectReason)
60 {
61     // Stop tracking without taking a snapshot.
62     m_tracking = false;
63
64     ErrorString ignored;
65     disable(ignored);
66 }
67
68 void InspectorHeapAgent::enable(ErrorString&)
69 {
70     if (m_enabled)
71         return;
72
73     m_enabled = true;
74
75     m_environment.vm().heap.addObserver(this);
76 }
77
78 void InspectorHeapAgent::disable(ErrorString&)
79 {
80     if (!m_enabled)
81         return;
82
83     m_enabled = false;
84
85     m_environment.vm().heap.removeObserver(this);
86
87     clearHeapSnapshots();
88 }
89
90 void InspectorHeapAgent::gc(ErrorString&)
91 {
92     VM& vm = m_environment.vm();
93     JSLockHolder lock(vm);
94     sanitizeStackForVM(&vm);
95     vm.heap.collectNow(Sync, CollectionScope::Full);
96 }
97
98 void InspectorHeapAgent::snapshot(ErrorString&, double* timestamp, String* snapshotData)
99 {
100     VM& vm = m_environment.vm();
101     JSLockHolder lock(vm);
102
103     HeapSnapshotBuilder snapshotBuilder(vm.ensureHeapProfiler());
104     snapshotBuilder.buildSnapshot();
105
106     *timestamp = m_environment.executionStopwatch()->elapsedTime();
107     *snapshotData = snapshotBuilder.json([&] (const HeapSnapshotNode& node) {
108         if (Structure* structure = node.cell->structure(vm)) {
109             if (JSGlobalObject* globalObject = structure->globalObject()) {
110                 if (!m_environment.canAccessInspectedScriptState(globalObject->globalExec()))
111                     return false;
112             }
113         }
114         return true;
115     });
116 }
117
118 void InspectorHeapAgent::startTracking(ErrorString& errorString)
119 {
120     if (m_tracking)
121         return;
122
123     m_tracking = true;
124
125     double timestamp;
126     String snapshotData;
127     snapshot(errorString, &timestamp, &snapshotData);
128
129     m_frontendDispatcher->trackingStart(timestamp, snapshotData);
130 }
131
132 void InspectorHeapAgent::stopTracking(ErrorString& errorString)
133 {
134     if (!m_tracking)
135         return;
136
137     m_tracking = false;
138
139     double timestamp;
140     String snapshotData;
141     snapshot(errorString, &timestamp, &snapshotData);
142
143     m_frontendDispatcher->trackingComplete(timestamp, snapshotData);
144 }
145
146 std::optional<HeapSnapshotNode> InspectorHeapAgent::nodeForHeapObjectIdentifier(ErrorString& errorString, unsigned heapObjectIdentifier)
147 {
148     HeapProfiler* heapProfiler = m_environment.vm().heapProfiler();
149     if (!heapProfiler) {
150         errorString = ASCIILiteral("No heap snapshot");
151         return std::nullopt;
152     }
153
154     HeapSnapshot* snapshot = heapProfiler->mostRecentSnapshot();
155     if (!snapshot) {
156         errorString = ASCIILiteral("No heap snapshot");
157         return std::nullopt;
158     }
159
160     const std::optional<HeapSnapshotNode> optionalNode = snapshot->nodeForObjectIdentifier(heapObjectIdentifier);
161     if (!optionalNode) {
162         errorString = ASCIILiteral("No object for identifier, it may have been collected");
163         return std::nullopt;
164     }
165
166     return optionalNode;
167 }
168
169 void InspectorHeapAgent::getPreview(ErrorString& errorString, int heapObjectId, Inspector::Protocol::OptOutput<String>* resultString, RefPtr<Inspector::Protocol::Debugger::FunctionDetails>& functionDetails, RefPtr<Inspector::Protocol::Runtime::ObjectPreview>& objectPreview)
170 {
171     // Prevent the cell from getting collected as we look it up.
172     VM& vm = m_environment.vm();
173     JSLockHolder lock(vm);
174     DeferGC deferGC(vm.heap);
175
176     unsigned heapObjectIdentifier = static_cast<unsigned>(heapObjectId);
177     const std::optional<HeapSnapshotNode> optionalNode = nodeForHeapObjectIdentifier(errorString, heapObjectIdentifier);
178     if (!optionalNode)
179         return;
180
181     // String preview.
182     JSCell* cell = optionalNode->cell;
183     if (cell->isString()) {
184         *resultString = asString(cell)->tryGetValue();
185         return;
186     }
187
188     // FIXME: Provide preview information for Internal Objects? CodeBlock, Executable, etc.
189
190     Structure* structure = cell->structure(vm);
191     if (!structure) {
192         errorString = ASCIILiteral("Unable to get object details - Structure");
193         return;
194     }
195
196     JSGlobalObject* globalObject = structure->globalObject();
197     if (!globalObject) {
198         errorString = ASCIILiteral("Unable to get object details - GlobalObject");
199         return;
200     }
201
202     InjectedScript injectedScript = m_injectedScriptManager.injectedScriptFor(globalObject->globalExec());
203     if (injectedScript.hasNoValue()) {
204         errorString = ASCIILiteral("Unable to get object details - InjectedScript");
205         return;
206     }
207
208     // Function preview.
209     if (cell->inherits(vm, JSFunction::info())) {
210         injectedScript.functionDetails(errorString, cell, &functionDetails);
211         return;
212     }
213
214     // Object preview.
215     objectPreview = injectedScript.previewValue(cell);
216 }
217
218 void InspectorHeapAgent::getRemoteObject(ErrorString& errorString, int heapObjectId, const String* const optionalObjectGroup, RefPtr<Inspector::Protocol::Runtime::RemoteObject>& result)
219 {
220     // Prevent the cell from getting collected as we look it up.
221     VM& vm = m_environment.vm();
222     JSLockHolder lock(vm);
223     DeferGC deferGC(vm.heap);
224
225     unsigned heapObjectIdentifier = static_cast<unsigned>(heapObjectId);
226     const std::optional<HeapSnapshotNode> optionalNode = nodeForHeapObjectIdentifier(errorString, heapObjectIdentifier);
227     if (!optionalNode)
228         return;
229
230     JSCell* cell = optionalNode->cell;
231     Structure* structure = cell->structure(vm);
232     if (!structure) {
233         errorString = ASCIILiteral("Unable to get object details");
234         return;
235     }
236
237     JSGlobalObject* globalObject = structure->globalObject();
238     if (!globalObject) {
239         errorString = ASCIILiteral("Unable to get object details");
240         return;
241     }
242
243     InjectedScript injectedScript = m_injectedScriptManager.injectedScriptFor(globalObject->globalExec());
244     if (injectedScript.hasNoValue()) {
245         errorString = ASCIILiteral("Unable to get object details - InjectedScript");
246         return;
247     }
248
249     String objectGroup = optionalObjectGroup ? *optionalObjectGroup : String();
250     result = injectedScript.wrapObject(cell, objectGroup, true);
251 }
252
253 static Inspector::Protocol::Heap::GarbageCollection::Type protocolTypeForHeapOperation(CollectionScope scope)
254 {
255     switch (scope) {
256     case CollectionScope::Full:
257         return Inspector::Protocol::Heap::GarbageCollection::Type::Full;
258     case CollectionScope::Eden:
259         return Inspector::Protocol::Heap::GarbageCollection::Type::Partial;
260     }
261     ASSERT_NOT_REACHED();
262     return Inspector::Protocol::Heap::GarbageCollection::Type::Full;
263 }
264
265 void InspectorHeapAgent::willGarbageCollect()
266 {
267     if (!m_enabled)
268         return;
269
270     m_gcStartTime = m_environment.executionStopwatch()->elapsedTime();
271 }
272
273 void InspectorHeapAgent::didGarbageCollect(CollectionScope scope)
274 {
275     if (!m_enabled) {
276         m_gcStartTime = NAN;
277         return;
278     }
279
280     if (std::isnan(m_gcStartTime)) {
281         // We were not enabled when the GC began.
282         return;
283     }
284
285     // FIXME: Include number of bytes freed by collection.
286
287     double endTime = m_environment.executionStopwatch()->elapsedTime();
288     dispatchGarbageCollectedEvent(protocolTypeForHeapOperation(scope), m_gcStartTime, endTime);
289
290     m_gcStartTime = NAN;
291 }
292
293 void InspectorHeapAgent::clearHeapSnapshots()
294 {
295     VM& vm = m_environment.vm();
296     JSLockHolder lock(vm);
297
298     if (HeapProfiler* heapProfiler = vm.heapProfiler()) {
299         heapProfiler->clearSnapshots();
300         HeapSnapshotBuilder::resetNextAvailableObjectIdentifier();
301     }
302 }
303
304 void InspectorHeapAgent::dispatchGarbageCollectedEvent(Inspector::Protocol::Heap::GarbageCollection::Type type, double startTime, double endTime)
305 {
306     auto protocolObject = Inspector::Protocol::Heap::GarbageCollection::create()
307         .setType(type)
308         .setStartTime(startTime)
309         .setEndTime(endTime)
310         .release();
311
312     m_frontendDispatcher->garbageCollected(WTFMove(protocolObject));
313 }
314
315 } // namespace Inspector