OLD | NEW |
| (Empty) |
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/V8InspectorImpl.h" | |
32 | |
33 #include "src/inspector/InspectedContext.h" | |
34 #include "src/inspector/StringUtil.h" | |
35 #include "src/inspector/V8Compat.h" | |
36 #include "src/inspector/V8ConsoleAgentImpl.h" | |
37 #include "src/inspector/V8ConsoleMessage.h" | |
38 #include "src/inspector/V8Debugger.h" | |
39 #include "src/inspector/V8DebuggerAgentImpl.h" | |
40 #include "src/inspector/V8InspectorSessionImpl.h" | |
41 #include "src/inspector/V8RuntimeAgentImpl.h" | |
42 #include "src/inspector/V8StackTraceImpl.h" | |
43 #include "src/inspector/protocol/Protocol.h" | |
44 #include "src/inspector/public/V8InspectorClient.h" | |
45 #include <v8-profiler.h> | |
46 | |
47 namespace v8_inspector { | |
48 | |
49 std::unique_ptr<V8Inspector> V8Inspector::create(v8::Isolate* isolate, V8Inspect
orClient* client) | |
50 { | |
51 return wrapUnique(new V8InspectorImpl(isolate, client)); | |
52 } | |
53 | |
54 V8InspectorImpl::V8InspectorImpl(v8::Isolate* isolate, V8InspectorClient* client
) | |
55 : m_isolate(isolate) | |
56 , m_client(client) | |
57 , m_debugger(new V8Debugger(isolate, this)) | |
58 , m_capturingStackTracesCount(0) | |
59 , m_lastExceptionId(0) | |
60 { | |
61 } | |
62 | |
63 V8InspectorImpl::~V8InspectorImpl() | |
64 { | |
65 } | |
66 | |
67 V8DebuggerAgentImpl* V8InspectorImpl::enabledDebuggerAgentForGroup(int contextGr
oupId) | |
68 { | |
69 V8InspectorSessionImpl* session = sessionForContextGroup(contextGroupId); | |
70 V8DebuggerAgentImpl* agent = session ? session->debuggerAgent() : nullptr; | |
71 return agent && agent->enabled() ? agent : nullptr; | |
72 } | |
73 | |
74 V8RuntimeAgentImpl* V8InspectorImpl::enabledRuntimeAgentForGroup(int contextGrou
pId) | |
75 { | |
76 V8InspectorSessionImpl* session = sessionForContextGroup(contextGroupId); | |
77 V8RuntimeAgentImpl* agent = session ? session->runtimeAgent() : nullptr; | |
78 return agent && agent->enabled() ? agent : nullptr; | |
79 } | |
80 | |
81 v8::MaybeLocal<v8::Value> V8InspectorImpl::runCompiledScript(v8::Local<v8::Conte
xt> context, v8::Local<v8::Script> script) | |
82 { | |
83 v8::MicrotasksScope microtasksScope(m_isolate, v8::MicrotasksScope::kRunMicr
otasks); | |
84 int groupId = V8Debugger::getGroupId(context); | |
85 if (V8DebuggerAgentImpl* agent = enabledDebuggerAgentForGroup(groupId)) | |
86 agent->willExecuteScript(script->GetUnboundScript()->GetId()); | |
87 v8::MaybeLocal<v8::Value> result = script->Run(context); | |
88 // Get agent from the map again, since it could have detached during script
execution. | |
89 if (V8DebuggerAgentImpl* agent = enabledDebuggerAgentForGroup(groupId)) | |
90 agent->didExecuteScript(); | |
91 return result; | |
92 } | |
93 | |
94 v8::MaybeLocal<v8::Value> V8InspectorImpl::callFunction(v8::Local<v8::Function>
function, v8::Local<v8::Context> context, v8::Local<v8::Value> receiver, int arg
c, v8::Local<v8::Value> info[]) | |
95 { | |
96 v8::MicrotasksScope microtasksScope(m_isolate, v8::MicrotasksScope::kRunMicr
otasks); | |
97 int groupId = V8Debugger::getGroupId(context); | |
98 if (V8DebuggerAgentImpl* agent = enabledDebuggerAgentForGroup(groupId)) | |
99 agent->willExecuteScript(function->ScriptId()); | |
100 v8::MaybeLocal<v8::Value> result = function->Call(context, receiver, argc, i
nfo); | |
101 // Get agent from the map again, since it could have detached during script
execution. | |
102 if (V8DebuggerAgentImpl* agent = enabledDebuggerAgentForGroup(groupId)) | |
103 agent->didExecuteScript(); | |
104 return result; | |
105 } | |
106 | |
107 v8::MaybeLocal<v8::Value> V8InspectorImpl::compileAndRunInternalScript(v8::Local
<v8::Context> context, v8::Local<v8::String> source) | |
108 { | |
109 v8::Local<v8::Script> script = compileScript(context, source, String16(), tr
ue); | |
110 if (script.IsEmpty()) | |
111 return v8::MaybeLocal<v8::Value>(); | |
112 v8::MicrotasksScope microtasksScope(m_isolate, v8::MicrotasksScope::kDoNotRu
nMicrotasks); | |
113 return script->Run(context); | |
114 } | |
115 | |
116 v8::Local<v8::Script> V8InspectorImpl::compileScript(v8::Local<v8::Context> cont
ext, v8::Local<v8::String> code, const String16& fileName, bool markAsInternal) | |
117 { | |
118 v8::ScriptOrigin origin( | |
119 toV8String(m_isolate, fileName), | |
120 v8::Integer::New(m_isolate, 0), | |
121 v8::Integer::New(m_isolate, 0), | |
122 v8::False(m_isolate), // sharable | |
123 v8::Local<v8::Integer>(), | |
124 v8::Boolean::New(m_isolate, markAsInternal), // internal | |
125 toV8String(m_isolate, String16()), // sourceMap | |
126 v8::True(m_isolate)); // opaqueresource | |
127 v8::ScriptCompiler::Source source(code, origin); | |
128 v8::Local<v8::Script> script; | |
129 if (!v8::ScriptCompiler::Compile(context, &source, v8::ScriptCompiler::kNoCo
mpileOptions).ToLocal(&script)) | |
130 return v8::Local<v8::Script>(); | |
131 return script; | |
132 } | |
133 | |
134 void V8InspectorImpl::enableStackCapturingIfNeeded() | |
135 { | |
136 if (!m_capturingStackTracesCount) | |
137 V8StackTraceImpl::setCaptureStackTraceForUncaughtExceptions(m_isolate, t
rue); | |
138 ++m_capturingStackTracesCount; | |
139 } | |
140 | |
141 void V8InspectorImpl::disableStackCapturingIfNeeded() | |
142 { | |
143 if (!(--m_capturingStackTracesCount)) | |
144 V8StackTraceImpl::setCaptureStackTraceForUncaughtExceptions(m_isolate, f
alse); | |
145 } | |
146 | |
147 void V8InspectorImpl::muteExceptions(int contextGroupId) | |
148 { | |
149 m_muteExceptionsMap[contextGroupId]++; | |
150 } | |
151 | |
152 void V8InspectorImpl::unmuteExceptions(int contextGroupId) | |
153 { | |
154 m_muteExceptionsMap[contextGroupId]--; | |
155 } | |
156 | |
157 V8ConsoleMessageStorage* V8InspectorImpl::ensureConsoleMessageStorage(int contex
tGroupId) | |
158 { | |
159 ConsoleStorageMap::iterator storageIt = m_consoleStorageMap.find(contextGrou
pId); | |
160 if (storageIt == m_consoleStorageMap.end()) | |
161 storageIt = m_consoleStorageMap.insert(std::make_pair(contextGroupId, wr
apUnique(new V8ConsoleMessageStorage(this, contextGroupId)))).first; | |
162 return storageIt->second.get(); | |
163 } | |
164 | |
165 std::unique_ptr<V8StackTrace> V8InspectorImpl::createStackTrace(v8::Local<v8::St
ackTrace> stackTrace) | |
166 { | |
167 return m_debugger->createStackTrace(stackTrace); | |
168 } | |
169 | |
170 std::unique_ptr<V8InspectorSession> V8InspectorImpl::connect(int contextGroupId,
V8Inspector::Channel* channel, const StringView& state) | |
171 { | |
172 DCHECK(m_sessions.find(contextGroupId) == m_sessions.cend()); | |
173 std::unique_ptr<V8InspectorSessionImpl> session = V8InspectorSessionImpl::cr
eate(this, contextGroupId, channel, state); | |
174 m_sessions[contextGroupId] = session.get(); | |
175 return std::move(session); | |
176 } | |
177 | |
178 void V8InspectorImpl::disconnect(V8InspectorSessionImpl* session) | |
179 { | |
180 DCHECK(m_sessions.find(session->contextGroupId()) != m_sessions.end()); | |
181 m_sessions.erase(session->contextGroupId()); | |
182 } | |
183 | |
184 InspectedContext* V8InspectorImpl::getContext(int groupId, int contextId) const | |
185 { | |
186 if (!groupId || !contextId) | |
187 return nullptr; | |
188 | |
189 ContextsByGroupMap::const_iterator contextGroupIt = m_contexts.find(groupId)
; | |
190 if (contextGroupIt == m_contexts.end()) | |
191 return nullptr; | |
192 | |
193 ContextByIdMap::iterator contextIt = contextGroupIt->second->find(contextId)
; | |
194 if (contextIt == contextGroupIt->second->end()) | |
195 return nullptr; | |
196 | |
197 return contextIt->second.get(); | |
198 } | |
199 | |
200 void V8InspectorImpl::contextCreated(const V8ContextInfo& info) | |
201 { | |
202 int contextId = m_debugger->markContext(info); | |
203 | |
204 ContextsByGroupMap::iterator contextIt = m_contexts.find(info.contextGroupId
); | |
205 if (contextIt == m_contexts.end()) | |
206 contextIt = m_contexts.insert(std::make_pair(info.contextGroupId, wrapUn
ique(new ContextByIdMap()))).first; | |
207 | |
208 const auto& contextById = contextIt->second; | |
209 | |
210 DCHECK(contextById->find(contextId) == contextById->cend()); | |
211 InspectedContext* context = new InspectedContext(this, info, contextId); | |
212 (*contextById)[contextId] = wrapUnique(context); | |
213 SessionMap::iterator sessionIt = m_sessions.find(info.contextGroupId); | |
214 if (sessionIt != m_sessions.end()) | |
215 sessionIt->second->runtimeAgent()->reportExecutionContextCreated(context
); | |
216 } | |
217 | |
218 void V8InspectorImpl::contextDestroyed(v8::Local<v8::Context> context) | |
219 { | |
220 int contextId = V8Debugger::contextId(context); | |
221 int contextGroupId = V8Debugger::getGroupId(context); | |
222 | |
223 ConsoleStorageMap::iterator storageIt = m_consoleStorageMap.find(contextGrou
pId); | |
224 if (storageIt != m_consoleStorageMap.end()) | |
225 storageIt->second->contextDestroyed(contextId); | |
226 | |
227 InspectedContext* inspectedContext = getContext(contextGroupId, contextId); | |
228 if (!inspectedContext) | |
229 return; | |
230 | |
231 SessionMap::iterator iter = m_sessions.find(contextGroupId); | |
232 if (iter != m_sessions.end()) | |
233 iter->second->runtimeAgent()->reportExecutionContextDestroyed(inspectedC
ontext); | |
234 discardInspectedContext(contextGroupId, contextId); | |
235 } | |
236 | |
237 void V8InspectorImpl::resetContextGroup(int contextGroupId) | |
238 { | |
239 m_consoleStorageMap.erase(contextGroupId); | |
240 m_muteExceptionsMap.erase(contextGroupId); | |
241 SessionMap::iterator session = m_sessions.find(contextGroupId); | |
242 if (session != m_sessions.end()) | |
243 session->second->reset(); | |
244 m_contexts.erase(contextGroupId); | |
245 } | |
246 | |
247 void V8InspectorImpl::willExecuteScript(v8::Local<v8::Context> context, int scri
ptId) | |
248 { | |
249 if (V8DebuggerAgentImpl* agent = enabledDebuggerAgentForGroup(V8Debugger::ge
tGroupId(context))) | |
250 agent->willExecuteScript(scriptId); | |
251 } | |
252 | |
253 void V8InspectorImpl::didExecuteScript(v8::Local<v8::Context> context) | |
254 { | |
255 if (V8DebuggerAgentImpl* agent = enabledDebuggerAgentForGroup(V8Debugger::ge
tGroupId(context))) | |
256 agent->didExecuteScript(); | |
257 } | |
258 | |
259 void V8InspectorImpl::idleStarted() | |
260 { | |
261 m_isolate->GetCpuProfiler()->SetIdle(true); | |
262 } | |
263 | |
264 void V8InspectorImpl::idleFinished() | |
265 { | |
266 m_isolate->GetCpuProfiler()->SetIdle(false); | |
267 } | |
268 | |
269 unsigned V8InspectorImpl::exceptionThrown(v8::Local<v8::Context> context, const
StringView& message, v8::Local<v8::Value> exception, const StringView& detailedM
essage, const StringView& url, unsigned lineNumber, unsigned columnNumber, std::
unique_ptr<V8StackTrace> stackTrace, int scriptId) | |
270 { | |
271 int contextGroupId = V8Debugger::getGroupId(context); | |
272 if (!contextGroupId || m_muteExceptionsMap[contextGroupId]) | |
273 return 0; | |
274 std::unique_ptr<V8StackTraceImpl> stackTraceImpl = wrapUnique(static_cast<V8
StackTraceImpl*>(stackTrace.release())); | |
275 unsigned exceptionId = nextExceptionId(); | |
276 std::unique_ptr<V8ConsoleMessage> consoleMessage = V8ConsoleMessage::createF
orException(m_client->currentTimeMS(), toString16(detailedMessage), toString16(u
rl), lineNumber, columnNumber, std::move(stackTraceImpl), scriptId, m_isolate, t
oString16(message), V8Debugger::contextId(context), exception, exceptionId); | |
277 ensureConsoleMessageStorage(contextGroupId)->addMessage(std::move(consoleMes
sage)); | |
278 return exceptionId; | |
279 } | |
280 | |
281 void V8InspectorImpl::exceptionRevoked(v8::Local<v8::Context> context, unsigned
exceptionId, const StringView& message) | |
282 { | |
283 int contextGroupId = V8Debugger::getGroupId(context); | |
284 if (!contextGroupId) | |
285 return; | |
286 | |
287 std::unique_ptr<V8ConsoleMessage> consoleMessage = V8ConsoleMessage::createF
orRevokedException(m_client->currentTimeMS(), toString16(message), exceptionId); | |
288 ensureConsoleMessageStorage(contextGroupId)->addMessage(std::move(consoleMes
sage)); | |
289 } | |
290 | |
291 std::unique_ptr<V8StackTrace> V8InspectorImpl::captureStackTrace(bool fullStack) | |
292 { | |
293 return m_debugger->captureStackTrace(fullStack); | |
294 } | |
295 | |
296 void V8InspectorImpl::asyncTaskScheduled(const StringView& taskName, void* task,
bool recurring) | |
297 { | |
298 m_debugger->asyncTaskScheduled(taskName, task, recurring); | |
299 } | |
300 | |
301 void V8InspectorImpl::asyncTaskCanceled(void* task) | |
302 { | |
303 m_debugger->asyncTaskCanceled(task); | |
304 } | |
305 | |
306 void V8InspectorImpl::asyncTaskStarted(void* task) | |
307 { | |
308 m_debugger->asyncTaskStarted(task); | |
309 } | |
310 | |
311 void V8InspectorImpl::asyncTaskFinished(void* task) | |
312 { | |
313 m_debugger->asyncTaskFinished(task); | |
314 } | |
315 | |
316 void V8InspectorImpl::allAsyncTasksCanceled() | |
317 { | |
318 m_debugger->allAsyncTasksCanceled(); | |
319 } | |
320 | |
321 v8::Local<v8::Context> V8InspectorImpl::regexContext() | |
322 { | |
323 if (m_regexContext.IsEmpty()) | |
324 m_regexContext.Reset(m_isolate, v8::Context::New(m_isolate)); | |
325 return m_regexContext.Get(m_isolate); | |
326 } | |
327 | |
328 void V8InspectorImpl::discardInspectedContext(int contextGroupId, int contextId) | |
329 { | |
330 if (!getContext(contextGroupId, contextId)) | |
331 return; | |
332 m_contexts[contextGroupId]->erase(contextId); | |
333 if (m_contexts[contextGroupId]->empty()) | |
334 m_contexts.erase(contextGroupId); | |
335 } | |
336 | |
337 const V8InspectorImpl::ContextByIdMap* V8InspectorImpl::contextGroup(int context
GroupId) | |
338 { | |
339 ContextsByGroupMap::iterator iter = m_contexts.find(contextGroupId); | |
340 return iter == m_contexts.end() ? nullptr : iter->second.get(); | |
341 } | |
342 | |
343 V8InspectorSessionImpl* V8InspectorImpl::sessionForContextGroup(int contextGroup
Id) | |
344 { | |
345 if (!contextGroupId) | |
346 return nullptr; | |
347 SessionMap::iterator iter = m_sessions.find(contextGroupId); | |
348 return iter == m_sessions.end() ? nullptr : iter->second; | |
349 } | |
350 | |
351 } // namespace v8_inspector | |
OLD | NEW |