Line data Source code
1 : /*
2 : * Copyright (c) 2010-2011 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 "src/inspector/v8-inspector-impl.h"
32 :
33 : #include <vector>
34 :
35 : #include "src/inspector/inspected-context.h"
36 : #include "src/inspector/string-util.h"
37 : #include "src/inspector/v8-console-agent-impl.h"
38 : #include "src/inspector/v8-console-message.h"
39 : #include "src/inspector/v8-console.h"
40 : #include "src/inspector/v8-debugger-agent-impl.h"
41 : #include "src/inspector/v8-debugger.h"
42 : #include "src/inspector/v8-inspector-session-impl.h"
43 : #include "src/inspector/v8-profiler-agent-impl.h"
44 : #include "src/inspector/v8-runtime-agent-impl.h"
45 : #include "src/inspector/v8-stack-trace-impl.h"
46 :
47 : namespace v8_inspector {
48 :
49 3261 : std::unique_ptr<V8Inspector> V8Inspector::create(v8::Isolate* isolate,
50 : V8InspectorClient* client) {
51 6522 : return std::unique_ptr<V8Inspector>(new V8InspectorImpl(isolate, client));
52 : }
53 :
54 3261 : V8InspectorImpl::V8InspectorImpl(v8::Isolate* isolate,
55 : V8InspectorClient* client)
56 : : m_isolate(isolate),
57 : m_client(client),
58 3261 : m_debugger(new V8Debugger(isolate, this)),
59 : m_capturingStackTracesCount(0),
60 : m_lastExceptionId(0),
61 22827 : m_lastContextId(0) {
62 3261 : v8::debug::SetConsoleDelegate(m_isolate, console());
63 3261 : }
64 :
65 6522 : V8InspectorImpl::~V8InspectorImpl() {
66 3261 : v8::debug::SetConsoleDelegate(m_isolate, nullptr);
67 6522 : }
68 :
69 652763 : int V8InspectorImpl::contextGroupId(v8::Local<v8::Context> context) const {
70 1305526 : return contextGroupId(InspectedContext::contextId(context));
71 : }
72 :
73 70385 : int V8InspectorImpl::contextGroupId(int contextId) const {
74 : auto it = m_contextIdToGroupIdMap.find(contextId);
75 725152 : return it != m_contextIdToGroupIdMap.end() ? it->second : 0;
76 : }
77 :
78 3175 : v8::MaybeLocal<v8::Value> V8InspectorImpl::compileAndRunInternalScript(
79 : v8::Local<v8::Context> context, v8::Local<v8::String> source) {
80 : v8::Local<v8::UnboundScript> unboundScript;
81 6350 : if (!v8::debug::CompileInspectorScript(m_isolate, source)
82 3175 : .ToLocal(&unboundScript))
83 0 : return v8::MaybeLocal<v8::Value>();
84 : v8::MicrotasksScope microtasksScope(m_isolate,
85 3175 : v8::MicrotasksScope::kDoNotRunMicrotasks);
86 : v8::Context::Scope contextScope(context);
87 9525 : return unboundScript->BindToCurrentContext()->Run(context);
88 : }
89 :
90 6169 : v8::MaybeLocal<v8::Script> V8InspectorImpl::compileScript(
91 : v8::Local<v8::Context> context, const String16& code,
92 : const String16& fileName) {
93 : v8::ScriptOrigin origin(
94 : toV8String(m_isolate, fileName), v8::Integer::New(m_isolate, 0),
95 : v8::Integer::New(m_isolate, 0),
96 : v8::False(m_isolate), // sharable
97 : v8::Local<v8::Integer>(), toV8String(m_isolate, String16()), // sourceMap
98 24676 : v8::True(m_isolate)); // opaqueresource
99 6169 : v8::ScriptCompiler::Source source(toV8String(m_isolate, code), origin);
100 : return v8::ScriptCompiler::Compile(context, &source,
101 12338 : v8::ScriptCompiler::kNoCompileOptions);
102 : }
103 :
104 600 : void V8InspectorImpl::enableStackCapturingIfNeeded() {
105 600 : if (!m_capturingStackTracesCount)
106 : V8StackTraceImpl::setCaptureStackTraceForUncaughtExceptions(m_isolate,
107 545 : true);
108 600 : ++m_capturingStackTracesCount;
109 600 : }
110 :
111 600 : void V8InspectorImpl::disableStackCapturingIfNeeded() {
112 600 : if (!(--m_capturingStackTracesCount))
113 : V8StackTraceImpl::setCaptureStackTraceForUncaughtExceptions(m_isolate,
114 545 : false);
115 600 : }
116 :
117 617449 : void V8InspectorImpl::muteExceptions(int contextGroupId) {
118 617449 : m_muteExceptionsMap[contextGroupId]++;
119 617449 : }
120 :
121 617449 : void V8InspectorImpl::unmuteExceptions(int contextGroupId) {
122 617449 : m_muteExceptionsMap[contextGroupId]--;
123 617449 : }
124 :
125 7510 : V8ConsoleMessageStorage* V8InspectorImpl::ensureConsoleMessageStorage(
126 : int contextGroupId) {
127 : ConsoleStorageMap::iterator storageIt =
128 : m_consoleStorageMap.find(contextGroupId);
129 7510 : if (storageIt == m_consoleStorageMap.end())
130 : storageIt = m_consoleStorageMap
131 : .insert(std::make_pair(
132 : contextGroupId,
133 : std::unique_ptr<V8ConsoleMessageStorage>(
134 690 : new V8ConsoleMessageStorage(this, contextGroupId))))
135 : .first;
136 7510 : return storageIt->second.get();
137 : }
138 :
139 19885 : bool V8InspectorImpl::hasConsoleMessageStorage(int contextGroupId) {
140 : ConsoleStorageMap::iterator storageIt =
141 : m_consoleStorageMap.find(contextGroupId);
142 19885 : return storageIt != m_consoleStorageMap.end();
143 : }
144 :
145 215 : std::unique_ptr<V8StackTrace> V8InspectorImpl::createStackTrace(
146 : v8::Local<v8::StackTrace> stackTrace) {
147 430 : return m_debugger->createStackTrace(stackTrace);
148 : }
149 :
150 3406 : std::unique_ptr<V8InspectorSession> V8InspectorImpl::connect(
151 : int contextGroupId, V8Inspector::Channel* channel,
152 : const StringView& state) {
153 3406 : int sessionId = ++m_lastSessionId;
154 : std::unique_ptr<V8InspectorSessionImpl> session =
155 : V8InspectorSessionImpl::create(this, contextGroupId, sessionId, channel,
156 3406 : state);
157 6812 : m_sessions[contextGroupId][sessionId] = session.get();
158 3406 : return std::move(session);
159 : }
160 :
161 10163 : void V8InspectorImpl::disconnect(V8InspectorSessionImpl* session) {
162 6812 : auto& map = m_sessions[session->contextGroupId()];
163 6812 : map.erase(session->sessionId());
164 10108 : if (map.empty()) m_sessions.erase(session->contextGroupId());
165 3406 : }
166 :
167 277606 : InspectedContext* V8InspectorImpl::getContext(int groupId,
168 : int contextId) const {
169 277606 : if (!groupId || !contextId) return nullptr;
170 :
171 : ContextsByGroupMap::const_iterator contextGroupIt = m_contexts.find(groupId);
172 277576 : if (contextGroupIt == m_contexts.end()) return nullptr;
173 :
174 : ContextByIdMap::iterator contextIt = contextGroupIt->second->find(contextId);
175 277566 : if (contextIt == contextGroupIt->second->end()) return nullptr;
176 :
177 277556 : return contextIt->second.get();
178 : }
179 :
180 2004 : InspectedContext* V8InspectorImpl::getContext(int contextId) const {
181 2004 : return getContext(contextGroupId(contextId), contextId);
182 : }
183 :
184 3326 : void V8InspectorImpl::contextCreated(const V8ContextInfo& info) {
185 3326 : int contextId = ++m_lastContextId;
186 3326 : InspectedContext* context = new InspectedContext(this, info, contextId);
187 3326 : m_contextIdToGroupIdMap[contextId] = info.contextGroupId;
188 :
189 6652 : ContextsByGroupMap::iterator contextIt = m_contexts.find(info.contextGroupId);
190 3326 : if (contextIt == m_contexts.end())
191 : contextIt = m_contexts
192 : .insert(std::make_pair(
193 : info.contextGroupId,
194 6652 : std::unique_ptr<ContextByIdMap>(new ContextByIdMap())))
195 : .first;
196 : const auto& contextById = contextIt->second;
197 :
198 : DCHECK(contextById->find(contextId) == contextById->cend());
199 3326 : (*contextById)[contextId].reset(context);
200 : forEachSession(
201 : info.contextGroupId, [&context](V8InspectorSessionImpl* session) {
202 4946 : session->runtimeAgent()->reportExecutionContextCreated(context);
203 6652 : });
204 3326 : }
205 :
206 15 : void V8InspectorImpl::contextDestroyed(v8::Local<v8::Context> context) {
207 15 : int contextId = InspectedContext::contextId(context);
208 15 : int groupId = contextGroupId(context);
209 15 : contextCollected(groupId, contextId);
210 15 : }
211 :
212 20 : void V8InspectorImpl::contextCollected(int groupId, int contextId) {
213 : m_contextIdToGroupIdMap.erase(contextId);
214 :
215 : ConsoleStorageMap::iterator storageIt = m_consoleStorageMap.find(groupId);
216 20 : if (storageIt != m_consoleStorageMap.end())
217 40 : storageIt->second->contextDestroyed(contextId);
218 :
219 20 : InspectedContext* inspectedContext = getContext(groupId, contextId);
220 20 : if (!inspectedContext) return;
221 :
222 : forEachSession(groupId, [&inspectedContext](V8InspectorSessionImpl* session) {
223 60 : session->runtimeAgent()->reportExecutionContextDestroyed(inspectedContext);
224 40 : });
225 20 : discardInspectedContext(groupId, contextId);
226 : }
227 :
228 0 : void V8InspectorImpl::resetContextGroup(int contextGroupId) {
229 : m_consoleStorageMap.erase(contextGroupId);
230 : m_muteExceptionsMap.erase(contextGroupId);
231 : forEachSession(contextGroupId,
232 0 : [](V8InspectorSessionImpl* session) { session->reset(); });
233 : m_contexts.erase(contextGroupId);
234 : m_debugger->wasmTranslation()->Clear();
235 0 : }
236 :
237 0 : void V8InspectorImpl::idleStarted() {
238 0 : for (auto& it : m_sessions) {
239 0 : for (auto& it2 : it.second) {
240 0 : if (it2.second->profilerAgent()->idleStarted()) return;
241 : }
242 : }
243 : }
244 :
245 0 : void V8InspectorImpl::idleFinished() {
246 0 : for (auto& it : m_sessions) {
247 0 : for (auto& it2 : it.second) {
248 0 : if (it2.second->profilerAgent()->idleFinished()) return;
249 : }
250 : }
251 : }
252 :
253 215 : unsigned V8InspectorImpl::exceptionThrown(
254 : v8::Local<v8::Context> context, const StringView& message,
255 : v8::Local<v8::Value> exception, const StringView& detailedMessage,
256 : const StringView& url, unsigned lineNumber, unsigned columnNumber,
257 : std::unique_ptr<V8StackTrace> stackTrace, int scriptId) {
258 215 : int groupId = contextGroupId(context);
259 430 : if (!groupId || m_muteExceptionsMap[groupId]) return 0;
260 : std::unique_ptr<V8StackTraceImpl> stackTraceImpl(
261 : static_cast<V8StackTraceImpl*>(stackTrace.release()));
262 : unsigned exceptionId = nextExceptionId();
263 : std::unique_ptr<V8ConsoleMessage> consoleMessage =
264 : V8ConsoleMessage::createForException(
265 215 : m_client->currentTimeMS(), toString16(detailedMessage),
266 : toString16(url), lineNumber, columnNumber, std::move(stackTraceImpl),
267 : scriptId, m_isolate, toString16(message),
268 1505 : InspectedContext::contextId(context), exception, exceptionId);
269 430 : ensureConsoleMessageStorage(groupId)->addMessage(std::move(consoleMessage));
270 : return exceptionId;
271 : }
272 :
273 80 : void V8InspectorImpl::exceptionRevoked(v8::Local<v8::Context> context,
274 : unsigned exceptionId,
275 : const StringView& message) {
276 80 : int groupId = contextGroupId(context);
277 80 : if (!groupId) return;
278 :
279 : std::unique_ptr<V8ConsoleMessage> consoleMessage =
280 : V8ConsoleMessage::createForRevokedException(
281 160 : m_client->currentTimeMS(), toString16(message), exceptionId);
282 160 : ensureConsoleMessageStorage(groupId)->addMessage(std::move(consoleMessage));
283 : }
284 :
285 0 : std::unique_ptr<V8StackTrace> V8InspectorImpl::captureStackTrace(
286 : bool fullStack) {
287 0 : return m_debugger->captureStackTrace(fullStack);
288 : }
289 :
290 1385 : void V8InspectorImpl::asyncTaskScheduled(const StringView& taskName, void* task,
291 : bool recurring) {
292 2770 : if (!task) return;
293 2770 : m_debugger->asyncTaskScheduled(taskName, task, recurring);
294 : }
295 :
296 0 : void V8InspectorImpl::asyncTaskCanceled(void* task) {
297 0 : if (!task) return;
298 0 : m_debugger->asyncTaskCanceled(task);
299 : }
300 :
301 1385 : void V8InspectorImpl::asyncTaskStarted(void* task) {
302 2770 : if (!task) return;
303 1385 : m_debugger->asyncTaskStarted(task);
304 : }
305 :
306 1385 : void V8InspectorImpl::asyncTaskFinished(void* task) {
307 2770 : if (!task) return;
308 1385 : m_debugger->asyncTaskFinished(task);
309 : }
310 :
311 0 : void V8InspectorImpl::allAsyncTasksCanceled() {
312 0 : m_debugger->allAsyncTasksCanceled();
313 0 : }
314 :
315 405 : v8::Local<v8::Context> V8InspectorImpl::regexContext() {
316 405 : if (m_regexContext.IsEmpty())
317 102 : m_regexContext.Reset(m_isolate, v8::Context::New(m_isolate));
318 810 : return m_regexContext.Get(m_isolate);
319 : }
320 :
321 20 : void V8InspectorImpl::discardInspectedContext(int contextGroupId,
322 : int contextId) {
323 40 : if (!getContext(contextGroupId, contextId)) return;
324 : m_contexts[contextGroupId]->erase(contextId);
325 20 : if (m_contexts[contextGroupId]->empty()) m_contexts.erase(contextGroupId);
326 : }
327 :
328 100925 : V8InspectorSessionImpl* V8InspectorImpl::sessionById(int contextGroupId,
329 : int sessionId) {
330 : auto it = m_sessions.find(contextGroupId);
331 100925 : if (it == m_sessions.end()) return nullptr;
332 : auto it2 = it->second.find(sessionId);
333 100915 : return it2 == it->second.end() ? nullptr : it2->second;
334 : }
335 :
336 4164 : V8Console* V8InspectorImpl::console() {
337 4164 : if (!m_console) m_console.reset(new V8Console(this));
338 4164 : return m_console.get();
339 : }
340 :
341 45902 : void V8InspectorImpl::forEachContext(
342 : int contextGroupId, std::function<void(InspectedContext*)> callback) {
343 : auto it = m_contexts.find(contextGroupId);
344 45917 : if (it == m_contexts.end()) return;
345 : std::vector<int> ids;
346 45887 : ids.reserve(it->second->size());
347 137661 : for (auto& contextIt : *(it->second)) ids.push_back(contextIt.first);
348 :
349 : // Retrieve by ids each time since |callback| may destroy some contexts.
350 137661 : for (auto& contextId : ids) {
351 : it = m_contexts.find(contextGroupId);
352 45887 : if (it == m_contexts.end()) continue;
353 : auto contextIt = it->second->find(contextId);
354 91774 : if (contextIt != it->second->end()) callback(contextIt->second.get());
355 : }
356 : }
357 :
358 195555 : void V8InspectorImpl::forEachSession(
359 : int contextGroupId, std::function<void(V8InspectorSessionImpl*)> callback) {
360 : auto it = m_sessions.find(contextGroupId);
361 196768 : if (it == m_sessions.end()) return;
362 : std::vector<int> ids;
363 194342 : ids.reserve(it->second.size());
364 583691 : for (auto& sessionIt : it->second) ids.push_back(sessionIt.first);
365 :
366 : // Retrieve by ids each time since |callback| may destroy some contexts.
367 583691 : for (auto& sessionId : ids) {
368 : it = m_sessions.find(contextGroupId);
369 195007 : if (it == m_sessions.end()) continue;
370 : auto sessionIt = it->second.find(sessionId);
371 195007 : if (sessionIt != it->second.end()) callback(sessionIt->second);
372 : }
373 : }
374 :
375 : } // namespace v8_inspector
|