OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2010-2011 Google Inc. All rights reserved. | 2 * Copyright (c) 2010-2011 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 12 matching lines...) Expand all Loading... |
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 */ | 29 */ |
30 | 30 |
31 #include "platform/v8_inspector/V8InspectorImpl.h" | 31 #include "platform/v8_inspector/V8InspectorImpl.h" |
32 | 32 |
33 #include "platform/inspector_protocol/Values.h" | |
34 #include "platform/v8_inspector/Atomics.h" | |
35 #include "platform/v8_inspector/DebuggerScript.h" | |
36 #include "platform/v8_inspector/InspectedContext.h" | 33 #include "platform/v8_inspector/InspectedContext.h" |
37 #include "platform/v8_inspector/ScriptBreakpoint.h" | |
38 #include "platform/v8_inspector/V8Compat.h" | 34 #include "platform/v8_inspector/V8Compat.h" |
39 #include "platform/v8_inspector/V8ConsoleAgentImpl.h" | 35 #include "platform/v8_inspector/V8ConsoleAgentImpl.h" |
40 #include "platform/v8_inspector/V8ConsoleMessage.h" | 36 #include "platform/v8_inspector/V8ConsoleMessage.h" |
| 37 #include "platform/v8_inspector/V8Debugger.h" |
41 #include "platform/v8_inspector/V8DebuggerAgentImpl.h" | 38 #include "platform/v8_inspector/V8DebuggerAgentImpl.h" |
42 #include "platform/v8_inspector/V8InjectedScriptHost.h" | |
43 #include "platform/v8_inspector/V8InspectorSessionImpl.h" | 39 #include "platform/v8_inspector/V8InspectorSessionImpl.h" |
44 #include "platform/v8_inspector/V8InternalValueType.h" | |
45 #include "platform/v8_inspector/V8RuntimeAgentImpl.h" | 40 #include "platform/v8_inspector/V8RuntimeAgentImpl.h" |
46 #include "platform/v8_inspector/V8StackTraceImpl.h" | 41 #include "platform/v8_inspector/V8StackTraceImpl.h" |
47 #include "platform/v8_inspector/V8StringUtil.h" | 42 #include "platform/v8_inspector/V8StringUtil.h" |
48 #include "platform/v8_inspector/public/V8InspectorClient.h" | 43 #include "platform/v8_inspector/public/V8InspectorClient.h" |
49 #include <v8-profiler.h> | 44 #include <v8-profiler.h> |
50 | 45 |
51 namespace blink { | 46 namespace blink { |
52 | 47 |
53 namespace { | |
54 const char stepIntoV8MethodName[] = "stepIntoStatement"; | |
55 const char stepOutV8MethodName[] = "stepOutOfFunction"; | |
56 volatile int s_lastContextId = 0; | |
57 static const char v8AsyncTaskEventEnqueue[] = "enqueue"; | |
58 static const char v8AsyncTaskEventWillHandle[] = "willHandle"; | |
59 static const char v8AsyncTaskEventDidHandle[] = "didHandle"; | |
60 | |
61 inline v8::Local<v8::Boolean> v8Boolean(bool value, v8::Isolate* isolate) | |
62 { | |
63 return value ? v8::True(isolate) : v8::False(isolate); | |
64 } | |
65 | |
66 } | |
67 | |
68 static bool inLiveEditScope = false; | |
69 | |
70 v8::MaybeLocal<v8::Value> V8InspectorImpl::callDebuggerMethod(const char* functi
onName, int argc, v8::Local<v8::Value> argv[]) | |
71 { | |
72 v8::MicrotasksScope microtasks(m_isolate, v8::MicrotasksScope::kDoNotRunMicr
otasks); | |
73 v8::Local<v8::Object> debuggerScript = m_debuggerScript.Get(m_isolate); | |
74 v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(debuggerScr
ipt->Get(v8InternalizedString(functionName))); | |
75 DCHECK(m_isolate->InContext()); | |
76 return function->Call(m_isolate->GetCurrentContext(), debuggerScript, argc,
argv); | |
77 } | |
78 | |
79 std::unique_ptr<V8Inspector> V8Inspector::create(v8::Isolate* isolate, V8Inspect
orClient* client) | 48 std::unique_ptr<V8Inspector> V8Inspector::create(v8::Isolate* isolate, V8Inspect
orClient* client) |
80 { | 49 { |
81 return wrapUnique(new V8InspectorImpl(isolate, client)); | 50 return wrapUnique(new V8InspectorImpl(isolate, client)); |
82 } | 51 } |
83 | 52 |
84 V8InspectorImpl::V8InspectorImpl(v8::Isolate* isolate, V8InspectorClient* client
) | 53 V8InspectorImpl::V8InspectorImpl(v8::Isolate* isolate, V8InspectorClient* client
) |
85 : m_isolate(isolate) | 54 : m_isolate(isolate) |
86 , m_client(client) | 55 , m_client(client) |
| 56 , m_debugger(new V8Debugger(isolate, this)) |
87 , m_capturingStackTracesCount(0) | 57 , m_capturingStackTracesCount(0) |
88 , m_lastExceptionId(0) | 58 , m_lastExceptionId(0) |
89 , m_enabledAgentsCount(0) | |
90 , m_breakpointsActivated(true) | |
91 , m_runningNestedMessageLoop(false) | |
92 , m_maxAsyncCallStackDepth(0) | |
93 { | 59 { |
94 } | 60 } |
95 | 61 |
96 V8InspectorImpl::~V8InspectorImpl() | 62 V8InspectorImpl::~V8InspectorImpl() |
97 { | 63 { |
98 } | 64 } |
99 | 65 |
100 void V8InspectorImpl::enable() | 66 V8DebuggerAgentImpl* V8InspectorImpl::enabledDebuggerAgentForGroup(int contextGr
oupId) |
101 { | 67 { |
102 DCHECK(!enabled()); | 68 V8InspectorSessionImpl* session = sessionForContextGroup(contextGroupId); |
103 v8::HandleScope scope(m_isolate); | 69 V8DebuggerAgentImpl* agent = session ? session->debuggerAgent() : nullptr; |
104 v8::Debug::SetDebugEventListener(m_isolate, &V8InspectorImpl::v8DebugEventCa
llback, v8::External::New(m_isolate, this)); | 70 return agent && agent->enabled() ? agent : nullptr; |
105 m_debuggerContext.Reset(m_isolate, v8::Debug::GetDebugContext(m_isolate)); | |
106 compileDebuggerScript(); | |
107 } | 71 } |
108 | 72 |
109 void V8InspectorImpl::disable() | 73 V8RuntimeAgentImpl* V8InspectorImpl::enabledRuntimeAgentForGroup(int contextGrou
pId) |
110 { | 74 { |
111 DCHECK(enabled()); | 75 V8InspectorSessionImpl* session = sessionForContextGroup(contextGroupId); |
112 clearBreakpoints(); | 76 V8RuntimeAgentImpl* agent = session ? session->runtimeAgent() : nullptr; |
113 m_debuggerScript.Reset(); | 77 return agent && agent->enabled() ? agent : nullptr; |
114 m_debuggerContext.Reset(); | |
115 allAsyncTasksCanceled(); | |
116 v8::Debug::SetDebugEventListener(m_isolate, nullptr); | |
117 } | |
118 | |
119 bool V8InspectorImpl::enabled() const | |
120 { | |
121 return !m_debuggerScript.IsEmpty(); | |
122 } | |
123 | |
124 // static | |
125 int V8InspectorImpl::contextId(v8::Local<v8::Context> context) | |
126 { | |
127 v8::Local<v8::Value> data = context->GetEmbedderData(static_cast<int>(v8::Co
ntext::kDebugIdIndex)); | |
128 if (data.IsEmpty() || !data->IsString()) | |
129 return 0; | |
130 String16 dataString = toProtocolString(data.As<v8::String>()); | |
131 if (dataString.isEmpty()) | |
132 return 0; | |
133 size_t commaPos = dataString.find(","); | |
134 if (commaPos == kNotFound) | |
135 return 0; | |
136 size_t commaPos2 = dataString.find(",", commaPos + 1); | |
137 if (commaPos2 == kNotFound) | |
138 return 0; | |
139 return dataString.substring(commaPos + 1, commaPos2 - commaPos - 1).toInt(); | |
140 } | |
141 | |
142 // static | |
143 int V8InspectorImpl::getGroupId(v8::Local<v8::Context> context) | |
144 { | |
145 v8::Local<v8::Value> data = context->GetEmbedderData(static_cast<int>(v8::Co
ntext::kDebugIdIndex)); | |
146 if (data.IsEmpty() || !data->IsString()) | |
147 return 0; | |
148 String16 dataString = toProtocolString(data.As<v8::String>()); | |
149 if (dataString.isEmpty()) | |
150 return 0; | |
151 size_t commaPos = dataString.find(","); | |
152 if (commaPos == kNotFound) | |
153 return 0; | |
154 return dataString.substring(0, commaPos).toInt(); | |
155 } | |
156 | |
157 void V8InspectorImpl::debuggerAgentEnabled() | |
158 { | |
159 if (!m_enabledAgentsCount++) | |
160 enable(); | |
161 } | |
162 | |
163 void V8InspectorImpl::debuggerAgentDisabled() | |
164 { | |
165 if (!--m_enabledAgentsCount) | |
166 disable(); | |
167 } | |
168 | |
169 V8DebuggerAgentImpl* V8InspectorImpl::findEnabledDebuggerAgent(int contextGroupI
d) | |
170 { | |
171 if (!contextGroupId) | |
172 return nullptr; | |
173 SessionMap::iterator it = m_sessions.find(contextGroupId); | |
174 if (it == m_sessions.end()) | |
175 return nullptr; | |
176 V8DebuggerAgentImpl* agent = it->second->debuggerAgent(); | |
177 if (!agent->enabled()) | |
178 return nullptr; | |
179 return agent; | |
180 } | |
181 | |
182 V8DebuggerAgentImpl* V8InspectorImpl::findEnabledDebuggerAgent(v8::Local<v8::Con
text> context) | |
183 { | |
184 return findEnabledDebuggerAgent(getGroupId(context)); | |
185 } | |
186 | |
187 void V8InspectorImpl::getCompiledScripts(int contextGroupId, std::vector<std::un
ique_ptr<V8DebuggerScript>>& result) | |
188 { | |
189 v8::HandleScope scope(m_isolate); | |
190 v8::MicrotasksScope microtasks(m_isolate, v8::MicrotasksScope::kDoNotRunMicr
otasks); | |
191 v8::Local<v8::Object> debuggerScript = m_debuggerScript.Get(m_isolate); | |
192 DCHECK(!debuggerScript->IsUndefined()); | |
193 v8::Local<v8::Function> getScriptsFunction = v8::Local<v8::Function>::Cast(d
ebuggerScript->Get(v8InternalizedString("getScripts"))); | |
194 v8::Local<v8::Value> argv[] = { v8::Integer::New(m_isolate, contextGroupId)
}; | |
195 v8::Local<v8::Value> value; | |
196 if (!getScriptsFunction->Call(debuggerContext(), debuggerScript, PROTOCOL_AR
RAY_LENGTH(argv), argv).ToLocal(&value)) | |
197 return; | |
198 DCHECK(value->IsArray()); | |
199 v8::Local<v8::Array> scriptsArray = v8::Local<v8::Array>::Cast(value); | |
200 result.reserve(scriptsArray->Length()); | |
201 for (unsigned i = 0; i < scriptsArray->Length(); ++i) { | |
202 v8::Local<v8::Object> scriptObject = v8::Local<v8::Object>::Cast(scripts
Array->Get(v8::Integer::New(m_isolate, i))); | |
203 result.push_back(wrapUnique(new V8DebuggerScript(m_isolate, scriptObject
, inLiveEditScope))); | |
204 } | |
205 } | |
206 | |
207 String16 V8InspectorImpl::setBreakpoint(const String16& sourceID, const ScriptBr
eakpoint& scriptBreakpoint, int* actualLineNumber, int* actualColumnNumber, bool
interstatementLocation) | |
208 { | |
209 v8::HandleScope scope(m_isolate); | |
210 v8::Context::Scope contextScope(debuggerContext()); | |
211 | |
212 v8::Local<v8::Object> info = v8::Object::New(m_isolate); | |
213 info->Set(v8InternalizedString("sourceID"), toV8String(m_isolate, sourceID))
; | |
214 info->Set(v8InternalizedString("lineNumber"), v8::Integer::New(m_isolate, sc
riptBreakpoint.lineNumber)); | |
215 info->Set(v8InternalizedString("columnNumber"), v8::Integer::New(m_isolate,
scriptBreakpoint.columnNumber)); | |
216 info->Set(v8InternalizedString("interstatementLocation"), v8Boolean(intersta
tementLocation, m_isolate)); | |
217 info->Set(v8InternalizedString("condition"), toV8String(m_isolate, scriptBre
akpoint.condition)); | |
218 | |
219 v8::Local<v8::Function> setBreakpointFunction = v8::Local<v8::Function>::Cas
t(m_debuggerScript.Get(m_isolate)->Get(v8InternalizedString("setBreakpoint"))); | |
220 v8::Local<v8::Value> breakpointId = v8::Debug::Call(debuggerContext(), setBr
eakpointFunction, info).ToLocalChecked(); | |
221 if (!breakpointId->IsString()) | |
222 return ""; | |
223 *actualLineNumber = info->Get(v8InternalizedString("lineNumber"))->Int32Valu
e(); | |
224 *actualColumnNumber = info->Get(v8InternalizedString("columnNumber"))->Int32
Value(); | |
225 return toProtocolString(breakpointId.As<v8::String>()); | |
226 } | |
227 | |
228 void V8InspectorImpl::removeBreakpoint(const String16& breakpointId) | |
229 { | |
230 v8::HandleScope scope(m_isolate); | |
231 v8::Context::Scope contextScope(debuggerContext()); | |
232 | |
233 v8::Local<v8::Object> info = v8::Object::New(m_isolate); | |
234 info->Set(v8InternalizedString("breakpointId"), toV8String(m_isolate, breakp
ointId)); | |
235 | |
236 v8::Local<v8::Function> removeBreakpointFunction = v8::Local<v8::Function>::
Cast(m_debuggerScript.Get(m_isolate)->Get(v8InternalizedString("removeBreakpoint
"))); | |
237 v8::Debug::Call(debuggerContext(), removeBreakpointFunction, info).ToLocalCh
ecked(); | |
238 } | |
239 | |
240 void V8InspectorImpl::clearBreakpoints() | |
241 { | |
242 v8::HandleScope scope(m_isolate); | |
243 v8::Context::Scope contextScope(debuggerContext()); | |
244 | |
245 v8::Local<v8::Function> clearBreakpoints = v8::Local<v8::Function>::Cast(m_d
ebuggerScript.Get(m_isolate)->Get(v8InternalizedString("clearBreakpoints"))); | |
246 v8::Debug::Call(debuggerContext(), clearBreakpoints).ToLocalChecked(); | |
247 } | |
248 | |
249 void V8InspectorImpl::setBreakpointsActivated(bool activated) | |
250 { | |
251 if (!enabled()) { | |
252 NOTREACHED(); | |
253 return; | |
254 } | |
255 v8::HandleScope scope(m_isolate); | |
256 v8::Context::Scope contextScope(debuggerContext()); | |
257 | |
258 v8::Local<v8::Object> info = v8::Object::New(m_isolate); | |
259 info->Set(v8InternalizedString("enabled"), v8::Boolean::New(m_isolate, activ
ated)); | |
260 v8::Local<v8::Function> setBreakpointsActivated = v8::Local<v8::Function>::C
ast(m_debuggerScript.Get(m_isolate)->Get(v8InternalizedString("setBreakpointsAct
ivated"))); | |
261 v8::Debug::Call(debuggerContext(), setBreakpointsActivated, info).ToLocalChe
cked(); | |
262 | |
263 m_breakpointsActivated = activated; | |
264 } | |
265 | |
266 V8InspectorImpl::PauseOnExceptionsState V8InspectorImpl::getPauseOnExceptionsSta
te() | |
267 { | |
268 DCHECK(enabled()); | |
269 v8::HandleScope scope(m_isolate); | |
270 v8::Context::Scope contextScope(debuggerContext()); | |
271 | |
272 v8::Local<v8::Value> argv[] = { v8::Undefined(m_isolate) }; | |
273 v8::Local<v8::Value> result = callDebuggerMethod("pauseOnExceptionsState", 0
, argv).ToLocalChecked(); | |
274 return static_cast<V8InspectorImpl::PauseOnExceptionsState>(result->Int32Val
ue()); | |
275 } | |
276 | |
277 void V8InspectorImpl::setPauseOnExceptionsState(PauseOnExceptionsState pauseOnEx
ceptionsState) | |
278 { | |
279 DCHECK(enabled()); | |
280 v8::HandleScope scope(m_isolate); | |
281 v8::Context::Scope contextScope(debuggerContext()); | |
282 | |
283 v8::Local<v8::Value> argv[] = { v8::Int32::New(m_isolate, pauseOnExceptionsS
tate) }; | |
284 callDebuggerMethod("setPauseOnExceptionsState", 1, argv); | |
285 } | |
286 | |
287 void V8InspectorImpl::setPauseOnNextStatement(bool pause) | |
288 { | |
289 if (m_runningNestedMessageLoop) | |
290 return; | |
291 if (pause) | |
292 v8::Debug::DebugBreak(m_isolate); | |
293 else | |
294 v8::Debug::CancelDebugBreak(m_isolate); | |
295 } | |
296 | |
297 bool V8InspectorImpl::canBreakProgram() | |
298 { | |
299 if (!m_breakpointsActivated) | |
300 return false; | |
301 return m_isolate->InContext(); | |
302 } | |
303 | |
304 void V8InspectorImpl::breakProgram() | |
305 { | |
306 if (isPaused()) { | |
307 DCHECK(!m_runningNestedMessageLoop); | |
308 v8::Local<v8::Value> exception; | |
309 v8::Local<v8::Array> hitBreakpoints; | |
310 handleProgramBreak(m_pausedContext, m_executionState, exception, hitBrea
kpoints); | |
311 return; | |
312 } | |
313 | |
314 if (!canBreakProgram()) | |
315 return; | |
316 | |
317 v8::HandleScope scope(m_isolate); | |
318 v8::Local<v8::Function> breakFunction; | |
319 if (!v8::Function::New(m_isolate->GetCurrentContext(), &V8InspectorImpl::bre
akProgramCallback, v8::External::New(m_isolate, this), 0, v8::ConstructorBehavio
r::kThrow).ToLocal(&breakFunction)) | |
320 return; | |
321 v8::Debug::Call(debuggerContext(), breakFunction).ToLocalChecked(); | |
322 } | |
323 | |
324 void V8InspectorImpl::continueProgram() | |
325 { | |
326 if (isPaused()) | |
327 m_client->quitMessageLoopOnPause(); | |
328 m_pausedContext.Clear(); | |
329 m_executionState.Clear(); | |
330 } | |
331 | |
332 void V8InspectorImpl::stepIntoStatement() | |
333 { | |
334 DCHECK(isPaused()); | |
335 DCHECK(!m_executionState.IsEmpty()); | |
336 v8::HandleScope handleScope(m_isolate); | |
337 v8::Local<v8::Value> argv[] = { m_executionState }; | |
338 callDebuggerMethod(stepIntoV8MethodName, 1, argv); | |
339 continueProgram(); | |
340 } | |
341 | |
342 void V8InspectorImpl::stepOverStatement() | |
343 { | |
344 DCHECK(isPaused()); | |
345 DCHECK(!m_executionState.IsEmpty()); | |
346 v8::HandleScope handleScope(m_isolate); | |
347 v8::Local<v8::Value> argv[] = { m_executionState }; | |
348 callDebuggerMethod("stepOverStatement", 1, argv); | |
349 continueProgram(); | |
350 } | |
351 | |
352 void V8InspectorImpl::stepOutOfFunction() | |
353 { | |
354 DCHECK(isPaused()); | |
355 DCHECK(!m_executionState.IsEmpty()); | |
356 v8::HandleScope handleScope(m_isolate); | |
357 v8::Local<v8::Value> argv[] = { m_executionState }; | |
358 callDebuggerMethod(stepOutV8MethodName, 1, argv); | |
359 continueProgram(); | |
360 } | |
361 | |
362 void V8InspectorImpl::clearStepping() | |
363 { | |
364 DCHECK(enabled()); | |
365 v8::HandleScope scope(m_isolate); | |
366 v8::Context::Scope contextScope(debuggerContext()); | |
367 | |
368 v8::Local<v8::Value> argv[] = { v8::Undefined(m_isolate) }; | |
369 callDebuggerMethod("clearStepping", 0, argv); | |
370 } | |
371 | |
372 bool V8InspectorImpl::setScriptSource(const String16& sourceID, v8::Local<v8::St
ring> newSource, bool preview, ErrorString* error, Maybe<protocol::Runtime::Exce
ptionDetails>* exceptionDetails, JavaScriptCallFrames* newCallFrames, Maybe<bool
>* stackChanged) | |
373 { | |
374 class EnableLiveEditScope { | |
375 public: | |
376 explicit EnableLiveEditScope(v8::Isolate* isolate) : m_isolate(isolate) | |
377 { | |
378 v8::Debug::SetLiveEditEnabled(m_isolate, true); | |
379 inLiveEditScope = true; | |
380 } | |
381 ~EnableLiveEditScope() | |
382 { | |
383 v8::Debug::SetLiveEditEnabled(m_isolate, false); | |
384 inLiveEditScope = false; | |
385 } | |
386 private: | |
387 v8::Isolate* m_isolate; | |
388 }; | |
389 | |
390 DCHECK(enabled()); | |
391 v8::HandleScope scope(m_isolate); | |
392 | |
393 std::unique_ptr<v8::Context::Scope> contextScope; | |
394 if (!isPaused()) | |
395 contextScope = wrapUnique(new v8::Context::Scope(debuggerContext())); | |
396 | |
397 v8::Local<v8::Value> argv[] = { toV8String(m_isolate, sourceID), newSource,
v8Boolean(preview, m_isolate) }; | |
398 | |
399 v8::Local<v8::Value> v8result; | |
400 { | |
401 EnableLiveEditScope enableLiveEditScope(m_isolate); | |
402 v8::TryCatch tryCatch(m_isolate); | |
403 tryCatch.SetVerbose(false); | |
404 v8::MaybeLocal<v8::Value> maybeResult = callDebuggerMethod("liveEditScri
ptSource", 3, argv); | |
405 if (tryCatch.HasCaught()) { | |
406 v8::Local<v8::Message> message = tryCatch.Message(); | |
407 if (!message.IsEmpty()) | |
408 *error = toProtocolStringWithTypeCheck(message->Get()); | |
409 else | |
410 *error = "Unknown error."; | |
411 return false; | |
412 } | |
413 v8result = maybeResult.ToLocalChecked(); | |
414 } | |
415 DCHECK(!v8result.IsEmpty()); | |
416 v8::Local<v8::Object> resultTuple = v8result->ToObject(m_isolate); | |
417 int code = static_cast<int>(resultTuple->Get(0)->ToInteger(m_isolate)->Value
()); | |
418 switch (code) { | |
419 case 0: | |
420 { | |
421 *stackChanged = resultTuple->Get(1)->BooleanValue(); | |
422 // Call stack may have changed after if the edited function was on t
he stack. | |
423 if (!preview && isPaused()) { | |
424 JavaScriptCallFrames frames = currentCallFrames(); | |
425 newCallFrames->swap(frames); | |
426 } | |
427 return true; | |
428 } | |
429 // Compile error. | |
430 case 1: | |
431 { | |
432 *exceptionDetails = protocol::Runtime::ExceptionDetails::create() | |
433 .setText(toProtocolStringWithTypeCheck(resultTuple->Get(2))) | |
434 .setScriptId(String16("0")) | |
435 .setLineNumber(resultTuple->Get(3)->ToInteger(m_isolate)->Value(
) - 1) | |
436 .setColumnNumber(resultTuple->Get(4)->ToInteger(m_isolate)->Valu
e() - 1).build(); | |
437 return false; | |
438 } | |
439 } | |
440 *error = "Unknown error."; | |
441 return false; | |
442 } | |
443 | |
444 JavaScriptCallFrames V8InspectorImpl::currentCallFrames(int limit) | |
445 { | |
446 if (!m_isolate->InContext()) | |
447 return JavaScriptCallFrames(); | |
448 v8::Local<v8::Value> currentCallFramesV8; | |
449 if (m_executionState.IsEmpty()) { | |
450 v8::Local<v8::Function> currentCallFramesFunction = v8::Local<v8::Functi
on>::Cast(m_debuggerScript.Get(m_isolate)->Get(v8InternalizedString("currentCall
Frames"))); | |
451 currentCallFramesV8 = v8::Debug::Call(debuggerContext(), currentCallFram
esFunction, v8::Integer::New(m_isolate, limit)).ToLocalChecked(); | |
452 } else { | |
453 v8::Local<v8::Value> argv[] = { m_executionState, v8::Integer::New(m_iso
late, limit) }; | |
454 currentCallFramesV8 = callDebuggerMethod("currentCallFrames", PROTOCOL_A
RRAY_LENGTH(argv), argv).ToLocalChecked(); | |
455 } | |
456 DCHECK(!currentCallFramesV8.IsEmpty()); | |
457 if (!currentCallFramesV8->IsArray()) | |
458 return JavaScriptCallFrames(); | |
459 v8::Local<v8::Array> callFramesArray = currentCallFramesV8.As<v8::Array>(); | |
460 JavaScriptCallFrames callFrames; | |
461 for (size_t i = 0; i < callFramesArray->Length(); ++i) { | |
462 v8::Local<v8::Value> callFrameValue; | |
463 if (!callFramesArray->Get(debuggerContext(), i).ToLocal(&callFrameValue)
) | |
464 return JavaScriptCallFrames(); | |
465 if (!callFrameValue->IsObject()) | |
466 return JavaScriptCallFrames(); | |
467 v8::Local<v8::Object> callFrameObject = callFrameValue.As<v8::Object>(); | |
468 callFrames.push_back(JavaScriptCallFrame::create(debuggerContext(), v8::
Local<v8::Object>::Cast(callFrameObject))); | |
469 } | |
470 return callFrames; | |
471 } | |
472 | |
473 static V8InspectorImpl* toV8InspectorImpl(v8::Local<v8::Value> data) | |
474 { | |
475 void* p = v8::Local<v8::External>::Cast(data)->Value(); | |
476 return static_cast<V8InspectorImpl*>(p); | |
477 } | |
478 | |
479 void V8InspectorImpl::breakProgramCallback(const v8::FunctionCallbackInfo<v8::Va
lue>& info) | |
480 { | |
481 DCHECK_EQ(info.Length(), 2); | |
482 V8InspectorImpl* thisPtr = toV8InspectorImpl(info.Data()); | |
483 if (!thisPtr->enabled()) | |
484 return; | |
485 v8::Local<v8::Context> pausedContext = thisPtr->m_isolate->GetCurrentContext
(); | |
486 v8::Local<v8::Value> exception; | |
487 v8::Local<v8::Array> hitBreakpoints; | |
488 thisPtr->handleProgramBreak(pausedContext, v8::Local<v8::Object>::Cast(info[
0]), exception, hitBreakpoints); | |
489 } | |
490 | |
491 void V8InspectorImpl::handleProgramBreak(v8::Local<v8::Context> pausedContext, v
8::Local<v8::Object> executionState, v8::Local<v8::Value> exception, v8::Local<v
8::Array> hitBreakpointNumbers, bool isPromiseRejection) | |
492 { | |
493 // Don't allow nested breaks. | |
494 if (m_runningNestedMessageLoop) | |
495 return; | |
496 | |
497 V8DebuggerAgentImpl* agent = findEnabledDebuggerAgent(pausedContext); | |
498 if (!agent) | |
499 return; | |
500 | |
501 std::vector<String16> breakpointIds; | |
502 if (!hitBreakpointNumbers.IsEmpty()) { | |
503 breakpointIds.reserve(hitBreakpointNumbers->Length()); | |
504 for (size_t i = 0; i < hitBreakpointNumbers->Length(); i++) { | |
505 v8::Local<v8::Value> hitBreakpointNumber = hitBreakpointNumbers->Get
(i); | |
506 DCHECK(!hitBreakpointNumber.IsEmpty() && hitBreakpointNumber->IsInt3
2()); | |
507 breakpointIds.push_back(String16::fromInteger(hitBreakpointNumber->I
nt32Value())); | |
508 } | |
509 } | |
510 | |
511 m_pausedContext = pausedContext; | |
512 m_executionState = executionState; | |
513 V8DebuggerAgentImpl::SkipPauseRequest result = agent->didPause(pausedContext
, exception, breakpointIds, isPromiseRejection); | |
514 if (result == V8DebuggerAgentImpl::RequestNoSkip) { | |
515 m_runningNestedMessageLoop = true; | |
516 int groupId = getGroupId(pausedContext); | |
517 DCHECK(groupId); | |
518 m_client->runMessageLoopOnPause(groupId); | |
519 // The agent may have been removed in the nested loop. | |
520 agent = findEnabledDebuggerAgent(pausedContext); | |
521 if (agent) | |
522 agent->didContinue(); | |
523 m_runningNestedMessageLoop = false; | |
524 } | |
525 m_pausedContext.Clear(); | |
526 m_executionState.Clear(); | |
527 | |
528 if (result == V8DebuggerAgentImpl::RequestStepFrame) { | |
529 v8::Local<v8::Value> argv[] = { executionState }; | |
530 callDebuggerMethod("stepFrameStatement", 1, argv); | |
531 } else if (result == V8DebuggerAgentImpl::RequestStepInto) { | |
532 v8::Local<v8::Value> argv[] = { executionState }; | |
533 callDebuggerMethod(stepIntoV8MethodName, 1, argv); | |
534 } else if (result == V8DebuggerAgentImpl::RequestStepOut) { | |
535 v8::Local<v8::Value> argv[] = { executionState }; | |
536 callDebuggerMethod(stepOutV8MethodName, 1, argv); | |
537 } | |
538 } | |
539 | |
540 void V8InspectorImpl::v8DebugEventCallback(const v8::Debug::EventDetails& eventD
etails) | |
541 { | |
542 V8InspectorImpl* thisPtr = toV8InspectorImpl(eventDetails.GetCallbackData())
; | |
543 thisPtr->handleV8DebugEvent(eventDetails); | |
544 } | |
545 | |
546 v8::Local<v8::Value> V8InspectorImpl::callInternalGetterFunction(v8::Local<v8::O
bject> object, const char* functionName) | |
547 { | |
548 v8::MicrotasksScope microtasks(m_isolate, v8::MicrotasksScope::kDoNotRunMicr
otasks); | |
549 v8::Local<v8::Value> getterValue = object->Get(v8InternalizedString(function
Name)); | |
550 DCHECK(!getterValue.IsEmpty() && getterValue->IsFunction()); | |
551 return v8::Local<v8::Function>::Cast(getterValue)->Call(m_isolate->GetCurren
tContext(), object, 0, 0).ToLocalChecked(); | |
552 } | |
553 | |
554 void V8InspectorImpl::handleV8DebugEvent(const v8::Debug::EventDetails& eventDet
ails) | |
555 { | |
556 if (!enabled()) | |
557 return; | |
558 v8::DebugEvent event = eventDetails.GetEvent(); | |
559 if (event != v8::AsyncTaskEvent && event != v8::Break && event != v8::Except
ion && event != v8::AfterCompile && event != v8::BeforeCompile && event != v8::C
ompileError) | |
560 return; | |
561 | |
562 v8::Local<v8::Context> eventContext = eventDetails.GetEventContext(); | |
563 DCHECK(!eventContext.IsEmpty()); | |
564 | |
565 if (event == v8::AsyncTaskEvent) { | |
566 v8::HandleScope scope(m_isolate); | |
567 handleV8AsyncTaskEvent(eventContext, eventDetails.GetExecutionState(), e
ventDetails.GetEventData()); | |
568 return; | |
569 } | |
570 | |
571 V8DebuggerAgentImpl* agent = findEnabledDebuggerAgent(eventContext); | |
572 if (agent) { | |
573 v8::HandleScope scope(m_isolate); | |
574 if (event == v8::AfterCompile || event == v8::CompileError) { | |
575 v8::Context::Scope contextScope(debuggerContext()); | |
576 v8::Local<v8::Value> argv[] = { eventDetails.GetEventData() }; | |
577 v8::Local<v8::Value> value = callDebuggerMethod("getAfterCompileScri
pt", 1, argv).ToLocalChecked(); | |
578 DCHECK(value->IsObject()); | |
579 v8::Local<v8::Object> scriptObject = v8::Local<v8::Object>::Cast(val
ue); | |
580 agent->didParseSource(wrapUnique(new V8DebuggerScript(m_isolate, scr
iptObject, inLiveEditScope)), event == v8::AfterCompile); | |
581 } else if (event == v8::Exception) { | |
582 v8::Local<v8::Object> eventData = eventDetails.GetEventData(); | |
583 v8::Local<v8::Value> exception = callInternalGetterFunction(eventDat
a, "exception"); | |
584 v8::Local<v8::Value> promise = callInternalGetterFunction(eventData,
"promise"); | |
585 bool isPromiseRejection = !promise.IsEmpty() && promise->IsObject(); | |
586 handleProgramBreak(eventContext, eventDetails.GetExecutionState(), e
xception, v8::Local<v8::Array>(), isPromiseRejection); | |
587 } else if (event == v8::Break) { | |
588 v8::Local<v8::Value> argv[] = { eventDetails.GetEventData() }; | |
589 v8::Local<v8::Value> hitBreakpoints = callDebuggerMethod("getBreakpo
intNumbers", 1, argv).ToLocalChecked(); | |
590 DCHECK(hitBreakpoints->IsArray()); | |
591 handleProgramBreak(eventContext, eventDetails.GetExecutionState(), v
8::Local<v8::Value>(), hitBreakpoints.As<v8::Array>()); | |
592 } | |
593 } | |
594 } | |
595 | |
596 void V8InspectorImpl::handleV8AsyncTaskEvent(v8::Local<v8::Context> context, v8:
:Local<v8::Object> executionState, v8::Local<v8::Object> eventData) | |
597 { | |
598 if (!m_maxAsyncCallStackDepth) | |
599 return; | |
600 | |
601 String16 type = toProtocolStringWithTypeCheck(callInternalGetterFunction(eve
ntData, "type")); | |
602 String16 name = toProtocolStringWithTypeCheck(callInternalGetterFunction(eve
ntData, "name")); | |
603 int id = callInternalGetterFunction(eventData, "id")->ToInteger(m_isolate)->
Value(); | |
604 // The scopes for the ids are defined by the eventData.name namespaces. Ther
e are currently two namespaces: "Object." and "Promise.". | |
605 void* ptr = reinterpret_cast<void*>(id * 4 + (name[0] == 'P' ? 2 : 0) + 1); | |
606 if (type == v8AsyncTaskEventEnqueue) | |
607 asyncTaskScheduled(name, ptr, false); | |
608 else if (type == v8AsyncTaskEventWillHandle) | |
609 asyncTaskStarted(ptr); | |
610 else if (type == v8AsyncTaskEventDidHandle) | |
611 asyncTaskFinished(ptr); | |
612 else | |
613 NOTREACHED(); | |
614 } | |
615 | |
616 V8StackTraceImpl* V8InspectorImpl::currentAsyncCallChain() | |
617 { | |
618 if (!m_currentStacks.size()) | |
619 return nullptr; | |
620 return m_currentStacks.back().get(); | |
621 } | |
622 | |
623 void V8InspectorImpl::compileDebuggerScript() | |
624 { | |
625 if (!m_debuggerScript.IsEmpty()) { | |
626 NOTREACHED(); | |
627 return; | |
628 } | |
629 | |
630 v8::HandleScope scope(m_isolate); | |
631 v8::Context::Scope contextScope(debuggerContext()); | |
632 | |
633 v8::Local<v8::String> scriptValue = v8::String::NewFromUtf8(m_isolate, Debug
gerScript_js, v8::NewStringType::kInternalized, sizeof(DebuggerScript_js)).ToLoc
alChecked(); | |
634 v8::Local<v8::Value> value; | |
635 if (!compileAndRunInternalScript(debuggerContext(), scriptValue).ToLocal(&va
lue)) { | |
636 NOTREACHED(); | |
637 return; | |
638 } | |
639 DCHECK(value->IsObject()); | |
640 m_debuggerScript.Reset(m_isolate, value.As<v8::Object>()); | |
641 } | |
642 | |
643 v8::Local<v8::Context> V8InspectorImpl::debuggerContext() const | |
644 { | |
645 DCHECK(!m_debuggerContext.IsEmpty()); | |
646 return m_debuggerContext.Get(m_isolate); | |
647 } | |
648 | |
649 v8::Local<v8::String> V8InspectorImpl::v8InternalizedString(const char* str) con
st | |
650 { | |
651 return v8::String::NewFromUtf8(m_isolate, str, v8::NewStringType::kInternali
zed).ToLocalChecked(); | |
652 } | |
653 | |
654 v8::MaybeLocal<v8::Value> V8InspectorImpl::functionScopes(v8::Local<v8::Function
> function) | |
655 { | |
656 if (!enabled()) { | |
657 NOTREACHED(); | |
658 return v8::Local<v8::Value>::New(m_isolate, v8::Undefined(m_isolate)); | |
659 } | |
660 v8::Local<v8::Value> argv[] = { function }; | |
661 v8::Local<v8::Value> scopesValue; | |
662 if (!callDebuggerMethod("getFunctionScopes", 1, argv).ToLocal(&scopesValue)
|| !scopesValue->IsArray()) | |
663 return v8::MaybeLocal<v8::Value>(); | |
664 v8::Local<v8::Array> scopes = scopesValue.As<v8::Array>(); | |
665 v8::Local<v8::Context> context = m_debuggerContext.Get(m_isolate); | |
666 if (!markAsInternal(context, scopes, V8InternalValueType::kScopeList)) | |
667 return v8::MaybeLocal<v8::Value>(); | |
668 if (!markArrayEntriesAsInternal(context, scopes, V8InternalValueType::kScope
)) | |
669 return v8::MaybeLocal<v8::Value>(); | |
670 if (!scopes->SetPrototype(context, v8::Null(m_isolate)).FromMaybe(false)) | |
671 return v8::Undefined(m_isolate); | |
672 return scopes; | |
673 } | |
674 | |
675 v8::MaybeLocal<v8::Array> V8InspectorImpl::internalProperties(v8::Local<v8::Cont
ext> context, v8::Local<v8::Value> value) | |
676 { | |
677 v8::Local<v8::Array> properties; | |
678 if (!v8::Debug::GetInternalProperties(m_isolate, value).ToLocal(&properties)
) | |
679 return v8::MaybeLocal<v8::Array>(); | |
680 if (value->IsFunction()) { | |
681 v8::Local<v8::Function> function = value.As<v8::Function>(); | |
682 v8::Local<v8::Value> location = functionLocation(context, function); | |
683 if (location->IsObject()) { | |
684 properties->Set(properties->Length(), v8InternalizedString("[[Functi
onLocation]]")); | |
685 properties->Set(properties->Length(), location); | |
686 } | |
687 if (function->IsGeneratorFunction()) { | |
688 properties->Set(properties->Length(), v8InternalizedString("[[IsGene
rator]]")); | |
689 properties->Set(properties->Length(), v8::True(m_isolate)); | |
690 } | |
691 } | |
692 if (!enabled()) | |
693 return properties; | |
694 if (value->IsMap() || value->IsWeakMap() || value->IsSet() || value->IsWeakS
et() || value->IsSetIterator() || value->IsMapIterator()) { | |
695 v8::Local<v8::Value> entries = collectionEntries(context, v8::Local<v8::
Object>::Cast(value)); | |
696 if (entries->IsArray()) { | |
697 properties->Set(properties->Length(), v8InternalizedString("[[Entrie
s]]")); | |
698 properties->Set(properties->Length(), entries); | |
699 } | |
700 } | |
701 if (value->IsGeneratorObject()) { | |
702 v8::Local<v8::Value> location = generatorObjectLocation(v8::Local<v8::Ob
ject>::Cast(value)); | |
703 if (location->IsObject()) { | |
704 properties->Set(properties->Length(), v8InternalizedString("[[Genera
torLocation]]")); | |
705 properties->Set(properties->Length(), location); | |
706 } | |
707 } | |
708 if (value->IsFunction()) { | |
709 v8::Local<v8::Function> function = value.As<v8::Function>(); | |
710 v8::Local<v8::Value> boundFunction = function->GetBoundFunction(); | |
711 v8::Local<v8::Value> scopes; | |
712 if (boundFunction->IsUndefined() && functionScopes(function).ToLocal(&sc
opes)) { | |
713 properties->Set(properties->Length(), v8InternalizedString("[[Scopes
]]")); | |
714 properties->Set(properties->Length(), scopes); | |
715 } | |
716 } | |
717 return properties; | |
718 } | |
719 | |
720 v8::Local<v8::Value> V8InspectorImpl::collectionEntries(v8::Local<v8::Context> c
ontext, v8::Local<v8::Object> object) | |
721 { | |
722 if (!enabled()) { | |
723 NOTREACHED(); | |
724 return v8::Undefined(m_isolate); | |
725 } | |
726 v8::Local<v8::Value> argv[] = { object }; | |
727 v8::Local<v8::Value> entriesValue = callDebuggerMethod("getCollectionEntries
", 1, argv).ToLocalChecked(); | |
728 if (!entriesValue->IsArray()) | |
729 return v8::Undefined(m_isolate); | |
730 v8::Local<v8::Array> entries = entriesValue.As<v8::Array>(); | |
731 if (!markArrayEntriesAsInternal(context, entries, V8InternalValueType::kEntr
y)) | |
732 return v8::Undefined(m_isolate); | |
733 if (!entries->SetPrototype(context, v8::Null(m_isolate)).FromMaybe(false)) | |
734 return v8::Undefined(m_isolate); | |
735 return entries; | |
736 } | |
737 | |
738 v8::Local<v8::Value> V8InspectorImpl::generatorObjectLocation(v8::Local<v8::Obje
ct> object) | |
739 { | |
740 if (!enabled()) { | |
741 NOTREACHED(); | |
742 return v8::Null(m_isolate); | |
743 } | |
744 v8::Local<v8::Value> argv[] = { object }; | |
745 v8::Local<v8::Value> location = callDebuggerMethod("getGeneratorObjectLocati
on", 1, argv).ToLocalChecked(); | |
746 if (!location->IsObject()) | |
747 return v8::Null(m_isolate); | |
748 v8::Local<v8::Context> context = m_debuggerContext.Get(m_isolate); | |
749 if (!markAsInternal(context, v8::Local<v8::Object>::Cast(location), V8Intern
alValueType::kLocation)) | |
750 return v8::Null(m_isolate); | |
751 return location; | |
752 } | |
753 | |
754 v8::Local<v8::Value> V8InspectorImpl::functionLocation(v8::Local<v8::Context> co
ntext, v8::Local<v8::Function> function) | |
755 { | |
756 int scriptId = function->ScriptId(); | |
757 if (scriptId == v8::UnboundScript::kNoScriptId) | |
758 return v8::Null(m_isolate); | |
759 int lineNumber = function->GetScriptLineNumber(); | |
760 int columnNumber = function->GetScriptColumnNumber(); | |
761 if (lineNumber == v8::Function::kLineOffsetNotFound || columnNumber == v8::F
unction::kLineOffsetNotFound) | |
762 return v8::Null(m_isolate); | |
763 v8::Local<v8::Object> location = v8::Object::New(m_isolate); | |
764 if (!location->Set(context, v8InternalizedString("scriptId"), toV8String(m_i
solate, String16::fromInteger(scriptId))).FromMaybe(false)) | |
765 return v8::Null(m_isolate); | |
766 if (!location->Set(context, v8InternalizedString("lineNumber"), v8::Integer:
:New(m_isolate, lineNumber)).FromMaybe(false)) | |
767 return v8::Null(m_isolate); | |
768 if (!location->Set(context, v8InternalizedString("columnNumber"), v8::Intege
r::New(m_isolate, columnNumber)).FromMaybe(false)) | |
769 return v8::Null(m_isolate); | |
770 if (!markAsInternal(context, location, V8InternalValueType::kLocation)) | |
771 return v8::Null(m_isolate); | |
772 return location; | |
773 } | |
774 | |
775 bool V8InspectorImpl::isPaused() | |
776 { | |
777 return !m_pausedContext.IsEmpty(); | |
778 } | 78 } |
779 | 79 |
780 v8::MaybeLocal<v8::Value> V8InspectorImpl::runCompiledScript(v8::Local<v8::Conte
xt> context, v8::Local<v8::Script> script) | 80 v8::MaybeLocal<v8::Value> V8InspectorImpl::runCompiledScript(v8::Local<v8::Conte
xt> context, v8::Local<v8::Script> script) |
781 { | 81 { |
782 // TODO(dgozman): get rid of this check. | 82 // TODO(dgozman): get rid of this check. |
783 if (!m_client->isExecutionAllowed()) | 83 if (!m_client->isExecutionAllowed()) |
784 return v8::MaybeLocal<v8::Value>(); | 84 return v8::MaybeLocal<v8::Value>(); |
785 | 85 |
786 v8::MicrotasksScope microtasksScope(m_isolate, v8::MicrotasksScope::kRunMicr
otasks); | 86 v8::MicrotasksScope microtasksScope(m_isolate, v8::MicrotasksScope::kRunMicr
otasks); |
787 int groupId = getGroupId(context); | 87 int groupId = V8Debugger::getGroupId(context); |
788 if (V8DebuggerAgentImpl* agent = findEnabledDebuggerAgent(groupId)) | 88 if (V8DebuggerAgentImpl* agent = enabledDebuggerAgentForGroup(groupId)) |
789 agent->willExecuteScript(script->GetUnboundScript()->GetId()); | 89 agent->willExecuteScript(script->GetUnboundScript()->GetId()); |
790 v8::MaybeLocal<v8::Value> result = script->Run(context); | 90 v8::MaybeLocal<v8::Value> result = script->Run(context); |
791 // Get agent from the map again, since it could have detached during script
execution. | 91 // Get agent from the map again, since it could have detached during script
execution. |
792 if (V8DebuggerAgentImpl* agent = findEnabledDebuggerAgent(groupId)) | 92 if (V8DebuggerAgentImpl* agent = enabledDebuggerAgentForGroup(groupId)) |
793 agent->didExecuteScript(); | 93 agent->didExecuteScript(); |
794 return result; | 94 return result; |
795 } | 95 } |
796 | 96 |
797 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[]) | 97 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[]) |
798 { | 98 { |
799 // TODO(dgozman): get rid of this check. | 99 // TODO(dgozman): get rid of this check. |
800 if (!m_client->isExecutionAllowed()) | 100 if (!m_client->isExecutionAllowed()) |
801 return v8::MaybeLocal<v8::Value>(); | 101 return v8::MaybeLocal<v8::Value>(); |
802 | 102 |
803 v8::MicrotasksScope microtasksScope(m_isolate, v8::MicrotasksScope::kRunMicr
otasks); | 103 v8::MicrotasksScope microtasksScope(m_isolate, v8::MicrotasksScope::kRunMicr
otasks); |
804 int groupId = getGroupId(context); | 104 int groupId = V8Debugger::getGroupId(context); |
805 if (V8DebuggerAgentImpl* agent = findEnabledDebuggerAgent(groupId)) | 105 if (V8DebuggerAgentImpl* agent = enabledDebuggerAgentForGroup(groupId)) |
806 agent->willExecuteScript(function->ScriptId()); | 106 agent->willExecuteScript(function->ScriptId()); |
807 v8::MaybeLocal<v8::Value> result = function->Call(context, receiver, argc, i
nfo); | 107 v8::MaybeLocal<v8::Value> result = function->Call(context, receiver, argc, i
nfo); |
808 // Get agent from the map again, since it could have detached during script
execution. | 108 // Get agent from the map again, since it could have detached during script
execution. |
809 if (V8DebuggerAgentImpl* agent = findEnabledDebuggerAgent(groupId)) | 109 if (V8DebuggerAgentImpl* agent = enabledDebuggerAgentForGroup(groupId)) |
810 agent->didExecuteScript(); | 110 agent->didExecuteScript(); |
811 return result; | 111 return result; |
812 } | 112 } |
813 | 113 |
814 v8::MaybeLocal<v8::Value> V8InspectorImpl::compileAndRunInternalScript(v8::Local
<v8::Context> context, v8::Local<v8::String> source) | 114 v8::MaybeLocal<v8::Value> V8InspectorImpl::compileAndRunInternalScript(v8::Local
<v8::Context> context, v8::Local<v8::String> source) |
815 { | 115 { |
816 v8::Local<v8::Script> script = compileScript(context, source, String(), true
); | 116 v8::Local<v8::Script> script = compileScript(context, source, String(), true
); |
817 if (script.IsEmpty()) | 117 if (script.IsEmpty()) |
818 return v8::MaybeLocal<v8::Value>(); | 118 return v8::MaybeLocal<v8::Value>(); |
819 v8::MicrotasksScope microtasksScope(m_isolate, v8::MicrotasksScope::kDoNotRu
nMicrotasks); | 119 v8::MicrotasksScope microtasksScope(m_isolate, v8::MicrotasksScope::kDoNotRu
nMicrotasks); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
854 V8ConsoleMessageStorage* V8InspectorImpl::ensureConsoleMessageStorage(int contex
tGroupId) | 154 V8ConsoleMessageStorage* V8InspectorImpl::ensureConsoleMessageStorage(int contex
tGroupId) |
855 { | 155 { |
856 ConsoleStorageMap::iterator storageIt = m_consoleStorageMap.find(contextGrou
pId); | 156 ConsoleStorageMap::iterator storageIt = m_consoleStorageMap.find(contextGrou
pId); |
857 if (storageIt == m_consoleStorageMap.end()) | 157 if (storageIt == m_consoleStorageMap.end()) |
858 storageIt = m_consoleStorageMap.insert(std::make_pair(contextGroupId, wr
apUnique(new V8ConsoleMessageStorage(this, contextGroupId)))).first; | 158 storageIt = m_consoleStorageMap.insert(std::make_pair(contextGroupId, wr
apUnique(new V8ConsoleMessageStorage(this, contextGroupId)))).first; |
859 return storageIt->second.get(); | 159 return storageIt->second.get(); |
860 } | 160 } |
861 | 161 |
862 std::unique_ptr<V8StackTrace> V8InspectorImpl::createStackTrace(v8::Local<v8::St
ackTrace> stackTrace) | 162 std::unique_ptr<V8StackTrace> V8InspectorImpl::createStackTrace(v8::Local<v8::St
ackTrace> stackTrace) |
863 { | 163 { |
864 return createStackTraceImpl(stackTrace); | 164 return m_debugger->createStackTrace(stackTrace); |
865 } | |
866 | |
867 std::unique_ptr<V8StackTraceImpl> V8InspectorImpl::createStackTraceImpl(v8::Loca
l<v8::StackTrace> stackTrace) | |
868 { | |
869 int contextGroupId = m_isolate->InContext() ? getGroupId(m_isolate->GetCurre
ntContext()) : 0; | |
870 return V8StackTraceImpl::create(this, contextGroupId, stackTrace, V8StackTra
ceImpl::maxCallStackSizeToCapture); | |
871 } | 165 } |
872 | 166 |
873 std::unique_ptr<V8InspectorSession> V8InspectorImpl::connect(int contextGroupId,
protocol::FrontendChannel* channel, V8InspectorSessionClient* client, const Str
ing16* state) | 167 std::unique_ptr<V8InspectorSession> V8InspectorImpl::connect(int contextGroupId,
protocol::FrontendChannel* channel, V8InspectorSessionClient* client, const Str
ing16* state) |
874 { | 168 { |
875 DCHECK(m_sessions.find(contextGroupId) == m_sessions.cend()); | 169 DCHECK(m_sessions.find(contextGroupId) == m_sessions.cend()); |
876 std::unique_ptr<V8InspectorSessionImpl> session = | 170 std::unique_ptr<V8InspectorSessionImpl> session = V8InspectorSessionImpl::cr
eate(this, contextGroupId, channel, client, state); |
877 V8InspectorSessionImpl::create(this, contextGroupId, channel, client, st
ate); | |
878 m_sessions[contextGroupId] = session.get(); | 171 m_sessions[contextGroupId] = session.get(); |
879 return std::move(session); | 172 return std::move(session); |
880 } | 173 } |
881 | 174 |
882 void V8InspectorImpl::disconnect(V8InspectorSessionImpl* session) | 175 void V8InspectorImpl::disconnect(V8InspectorSessionImpl* session) |
883 { | 176 { |
884 DCHECK(m_sessions.find(session->contextGroupId()) != m_sessions.end()); | 177 DCHECK(m_sessions.find(session->contextGroupId()) != m_sessions.end()); |
885 m_sessions.erase(session->contextGroupId()); | 178 m_sessions.erase(session->contextGroupId()); |
886 } | 179 } |
887 | 180 |
888 InspectedContext* V8InspectorImpl::getContext(int groupId, int contextId) const | 181 InspectedContext* V8InspectorImpl::getContext(int groupId, int contextId) const |
889 { | 182 { |
890 ContextsByGroupMap::const_iterator contextGroupIt = m_contexts.find(groupId)
; | 183 ContextsByGroupMap::const_iterator contextGroupIt = m_contexts.find(groupId)
; |
891 if (contextGroupIt == m_contexts.end()) | 184 if (contextGroupIt == m_contexts.end()) |
892 return nullptr; | 185 return nullptr; |
893 | 186 |
894 ContextByIdMap::iterator contextIt = contextGroupIt->second->find(contextId)
; | 187 ContextByIdMap::iterator contextIt = contextGroupIt->second->find(contextId)
; |
895 if (contextIt == contextGroupIt->second->end()) | 188 if (contextIt == contextGroupIt->second->end()) |
896 return nullptr; | 189 return nullptr; |
897 | 190 |
898 return contextIt->second.get(); | 191 return contextIt->second.get(); |
899 } | 192 } |
900 | 193 |
901 void V8InspectorImpl::contextCreated(const V8ContextInfo& info) | 194 void V8InspectorImpl::contextCreated(const V8ContextInfo& info) |
902 { | 195 { |
903 DCHECK(info.context->GetIsolate() == m_isolate); | 196 int contextId = m_debugger->markContext(info); |
904 // TODO(dgozman): make s_lastContextId non-static. | |
905 int contextId = atomicIncrement(&s_lastContextId); | |
906 String16 debugData = String16::fromInteger(info.contextGroupId) + "," + Stri
ng16::fromInteger(contextId) + "," + (info.isDefault ? "default" : "nondefault")
; | |
907 v8::HandleScope scope(m_isolate); | |
908 v8::Context::Scope contextScope(info.context); | |
909 info.context->SetEmbedderData(static_cast<int>(v8::Context::kDebugIdIndex),
toV8String(m_isolate, debugData)); | |
910 | 197 |
911 ContextsByGroupMap::iterator contextIt = m_contexts.find(info.contextGroupId
); | 198 ContextsByGroupMap::iterator contextIt = m_contexts.find(info.contextGroupId
); |
912 if (contextIt == m_contexts.end()) | 199 if (contextIt == m_contexts.end()) |
913 contextIt = m_contexts.insert(std::make_pair(info.contextGroupId, wrapUn
ique(new ContextByIdMap()))).first; | 200 contextIt = m_contexts.insert(std::make_pair(info.contextGroupId, wrapUn
ique(new ContextByIdMap()))).first; |
914 | 201 |
915 const auto& contextById = contextIt->second; | 202 const auto& contextById = contextIt->second; |
916 | 203 |
917 DCHECK(contextById->find(contextId) == contextById->cend()); | 204 DCHECK(contextById->find(contextId) == contextById->cend()); |
918 InspectedContext* context = new InspectedContext(this, info, contextId); | 205 InspectedContext* context = new InspectedContext(this, info, contextId); |
919 (*contextById)[contextId] = wrapUnique(context); | 206 (*contextById)[contextId] = wrapUnique(context); |
920 SessionMap::iterator sessionIt = m_sessions.find(info.contextGroupId); | 207 SessionMap::iterator sessionIt = m_sessions.find(info.contextGroupId); |
921 if (sessionIt != m_sessions.end()) | 208 if (sessionIt != m_sessions.end()) |
922 sessionIt->second->runtimeAgent()->reportExecutionContextCreated(context
); | 209 sessionIt->second->runtimeAgent()->reportExecutionContextCreated(context
); |
923 } | 210 } |
924 | 211 |
925 void V8InspectorImpl::contextDestroyed(v8::Local<v8::Context> context) | 212 void V8InspectorImpl::contextDestroyed(v8::Local<v8::Context> context) |
926 { | 213 { |
927 int contextId = V8InspectorImpl::contextId(context); | 214 int contextId = V8Debugger::contextId(context); |
928 int contextGroupId = getGroupId(context); | 215 int contextGroupId = V8Debugger::getGroupId(context); |
929 | 216 |
930 ConsoleStorageMap::iterator storageIt = m_consoleStorageMap.find(contextGrou
pId); | 217 ConsoleStorageMap::iterator storageIt = m_consoleStorageMap.find(contextGrou
pId); |
931 if (storageIt != m_consoleStorageMap.end()) | 218 if (storageIt != m_consoleStorageMap.end()) |
932 storageIt->second->contextDestroyed(contextId); | 219 storageIt->second->contextDestroyed(contextId); |
933 | 220 |
934 InspectedContext* inspectedContext = getContext(contextGroupId, contextId); | 221 InspectedContext* inspectedContext = getContext(contextGroupId, contextId); |
935 if (!inspectedContext) | 222 if (!inspectedContext) |
936 return; | 223 return; |
937 | 224 |
938 SessionMap::iterator iter = m_sessions.find(contextGroupId); | 225 SessionMap::iterator iter = m_sessions.find(contextGroupId); |
939 if (iter != m_sessions.end()) | 226 if (iter != m_sessions.end()) |
940 iter->second->runtimeAgent()->reportExecutionContextDestroyed(inspectedC
ontext); | 227 iter->second->runtimeAgent()->reportExecutionContextDestroyed(inspectedC
ontext); |
941 discardInspectedContext(contextGroupId, contextId); | 228 discardInspectedContext(contextGroupId, contextId); |
942 } | 229 } |
943 | 230 |
944 void V8InspectorImpl::resetContextGroup(int contextGroupId) | 231 void V8InspectorImpl::resetContextGroup(int contextGroupId) |
945 { | 232 { |
946 m_consoleStorageMap.erase(contextGroupId); | 233 m_consoleStorageMap.erase(contextGroupId); |
947 SessionMap::iterator session = m_sessions.find(contextGroupId); | 234 SessionMap::iterator session = m_sessions.find(contextGroupId); |
948 if (session != m_sessions.end()) | 235 if (session != m_sessions.end()) |
949 session->second->reset(); | 236 session->second->reset(); |
950 m_contexts.erase(contextGroupId); | 237 m_contexts.erase(contextGroupId); |
951 } | 238 } |
952 | 239 |
953 void V8InspectorImpl::setAsyncCallStackDepth(V8DebuggerAgentImpl* agent, int dep
th) | |
954 { | |
955 if (depth <= 0) | |
956 m_maxAsyncCallStackDepthMap.erase(agent); | |
957 else | |
958 m_maxAsyncCallStackDepthMap[agent] = depth; | |
959 | |
960 int maxAsyncCallStackDepth = 0; | |
961 for (const auto& pair : m_maxAsyncCallStackDepthMap) { | |
962 if (pair.second > maxAsyncCallStackDepth) | |
963 maxAsyncCallStackDepth = pair.second; | |
964 } | |
965 | |
966 if (m_maxAsyncCallStackDepth == maxAsyncCallStackDepth) | |
967 return; | |
968 m_maxAsyncCallStackDepth = maxAsyncCallStackDepth; | |
969 if (!maxAsyncCallStackDepth) | |
970 allAsyncTasksCanceled(); | |
971 } | |
972 | |
973 void V8InspectorImpl::asyncTaskScheduled(const String16& taskName, void* task, b
ool recurring) | |
974 { | |
975 if (!m_maxAsyncCallStackDepth) | |
976 return; | |
977 v8::HandleScope scope(m_isolate); | |
978 int contextGroupId = m_isolate->InContext() ? getGroupId(m_isolate->GetCurre
ntContext()) : 0; | |
979 std::unique_ptr<V8StackTraceImpl> chain = V8StackTraceImpl::capture(this, co
ntextGroupId, V8StackTraceImpl::maxCallStackSizeToCapture, taskName); | |
980 if (chain) { | |
981 m_asyncTaskStacks[task] = std::move(chain); | |
982 if (recurring) | |
983 m_recurringTasks.insert(task); | |
984 } | |
985 } | |
986 | |
987 void V8InspectorImpl::asyncTaskCanceled(void* task) | |
988 { | |
989 if (!m_maxAsyncCallStackDepth) | |
990 return; | |
991 m_asyncTaskStacks.erase(task); | |
992 m_recurringTasks.erase(task); | |
993 } | |
994 | |
995 void V8InspectorImpl::asyncTaskStarted(void* task) | |
996 { | |
997 if (!m_maxAsyncCallStackDepth) | |
998 return; | |
999 m_currentTasks.push_back(task); | |
1000 AsyncTaskToStackTrace::iterator stackIt = m_asyncTaskStacks.find(task); | |
1001 // Needs to support following order of events: | |
1002 // - asyncTaskScheduled | |
1003 // <-- attached here --> | |
1004 // - asyncTaskStarted | |
1005 // - asyncTaskCanceled <-- canceled before finished | |
1006 // <-- async stack requested here --> | |
1007 // - asyncTaskFinished | |
1008 std::unique_ptr<V8StackTraceImpl> stack; | |
1009 if (stackIt != m_asyncTaskStacks.end() && stackIt->second) | |
1010 stack = stackIt->second->cloneImpl(); | |
1011 m_currentStacks.push_back(std::move(stack)); | |
1012 } | |
1013 | |
1014 void V8InspectorImpl::asyncTaskFinished(void* task) | |
1015 { | |
1016 if (!m_maxAsyncCallStackDepth) | |
1017 return; | |
1018 // We could start instrumenting half way and the stack is empty. | |
1019 if (!m_currentStacks.size()) | |
1020 return; | |
1021 | |
1022 DCHECK(m_currentTasks.back() == task); | |
1023 m_currentTasks.pop_back(); | |
1024 | |
1025 m_currentStacks.pop_back(); | |
1026 if (m_recurringTasks.find(task) == m_recurringTasks.end()) | |
1027 m_asyncTaskStacks.erase(task); | |
1028 } | |
1029 | |
1030 void V8InspectorImpl::allAsyncTasksCanceled() | |
1031 { | |
1032 m_asyncTaskStacks.clear(); | |
1033 m_recurringTasks.clear(); | |
1034 m_currentStacks.clear(); | |
1035 m_currentTasks.clear(); | |
1036 } | |
1037 | |
1038 void V8InspectorImpl::willExecuteScript(v8::Local<v8::Context> context, int scri
ptId) | 240 void V8InspectorImpl::willExecuteScript(v8::Local<v8::Context> context, int scri
ptId) |
1039 { | 241 { |
1040 if (V8DebuggerAgentImpl* agent = findEnabledDebuggerAgent(context)) | 242 if (V8DebuggerAgentImpl* agent = enabledDebuggerAgentForGroup(V8Debugger::ge
tGroupId(context))) |
1041 agent->willExecuteScript(scriptId); | 243 agent->willExecuteScript(scriptId); |
1042 } | 244 } |
1043 | 245 |
1044 void V8InspectorImpl::didExecuteScript(v8::Local<v8::Context> context) | 246 void V8InspectorImpl::didExecuteScript(v8::Local<v8::Context> context) |
1045 { | 247 { |
1046 if (V8DebuggerAgentImpl* agent = findEnabledDebuggerAgent(context)) | 248 if (V8DebuggerAgentImpl* agent = enabledDebuggerAgentForGroup(V8Debugger::ge
tGroupId(context))) |
1047 agent->didExecuteScript(); | 249 agent->didExecuteScript(); |
1048 } | 250 } |
1049 | 251 |
1050 void V8InspectorImpl::idleStarted() | 252 void V8InspectorImpl::idleStarted() |
1051 { | 253 { |
1052 m_isolate->GetCpuProfiler()->SetIdle(true); | 254 m_isolate->GetCpuProfiler()->SetIdle(true); |
1053 } | 255 } |
1054 | 256 |
1055 void V8InspectorImpl::idleFinished() | 257 void V8InspectorImpl::idleFinished() |
1056 { | 258 { |
1057 m_isolate->GetCpuProfiler()->SetIdle(false); | 259 m_isolate->GetCpuProfiler()->SetIdle(false); |
1058 } | 260 } |
1059 | 261 |
1060 unsigned V8InspectorImpl::exceptionThrown(v8::Local<v8::Context> context, const
String16& message, v8::Local<v8::Value> exception, const String16& detailedMessa
ge, const String16& url, unsigned lineNumber, unsigned columnNumber, std::unique
_ptr<V8StackTrace> stackTrace, int scriptId) | 262 unsigned V8InspectorImpl::exceptionThrown(v8::Local<v8::Context> context, const
String16& message, v8::Local<v8::Value> exception, const String16& detailedMessa
ge, const String16& url, unsigned lineNumber, unsigned columnNumber, std::unique
_ptr<V8StackTrace> stackTrace, int scriptId) |
1061 { | 263 { |
1062 int contextGroupId = getGroupId(context); | 264 int contextGroupId = V8Debugger::getGroupId(context); |
1063 if (!contextGroupId) | 265 if (!contextGroupId) |
1064 return 0; | 266 return 0; |
1065 std::unique_ptr<V8StackTraceImpl> stackTraceImpl = wrapUnique(static_cast<V8
StackTraceImpl*>(stackTrace.release())); | 267 std::unique_ptr<V8StackTraceImpl> stackTraceImpl = wrapUnique(static_cast<V8
StackTraceImpl*>(stackTrace.release())); |
1066 unsigned exceptionId = ++m_lastExceptionId; | 268 unsigned exceptionId = ++m_lastExceptionId; |
1067 std::unique_ptr<V8ConsoleMessage> consoleMessage = V8ConsoleMessage::createF
orException(m_client->currentTimeMS(), detailedMessage, url, lineNumber, columnN
umber, std::move(stackTraceImpl), scriptId, m_isolate, message, contextId(contex
t), exception, exceptionId); | 269 std::unique_ptr<V8ConsoleMessage> consoleMessage = V8ConsoleMessage::createF
orException(m_client->currentTimeMS(), detailedMessage, url, lineNumber, columnN
umber, std::move(stackTraceImpl), scriptId, m_isolate, message, V8Debugger::cont
extId(context), exception, exceptionId); |
1068 ensureConsoleMessageStorage(contextGroupId)->addMessage(std::move(consoleMes
sage)); | 270 ensureConsoleMessageStorage(contextGroupId)->addMessage(std::move(consoleMes
sage)); |
1069 return exceptionId; | 271 return exceptionId; |
1070 } | 272 } |
1071 | 273 |
1072 void V8InspectorImpl::exceptionRevoked(v8::Local<v8::Context> context, unsigned
exceptionId, const String16& message) | 274 void V8InspectorImpl::exceptionRevoked(v8::Local<v8::Context> context, unsigned
exceptionId, const String16& message) |
1073 { | 275 { |
1074 int contextGroupId = getGroupId(context); | 276 int contextGroupId = V8Debugger::getGroupId(context); |
1075 if (!contextGroupId) | 277 if (!contextGroupId) |
1076 return; | 278 return; |
1077 | 279 |
1078 std::unique_ptr<V8ConsoleMessage> consoleMessage = V8ConsoleMessage::createF
orRevokedException(m_client->currentTimeMS(), message, exceptionId); | 280 std::unique_ptr<V8ConsoleMessage> consoleMessage = V8ConsoleMessage::createF
orRevokedException(m_client->currentTimeMS(), message, exceptionId); |
1079 ensureConsoleMessageStorage(contextGroupId)->addMessage(std::move(consoleMes
sage)); | 281 ensureConsoleMessageStorage(contextGroupId)->addMessage(std::move(consoleMes
sage)); |
1080 } | 282 } |
1081 | 283 |
1082 std::unique_ptr<V8StackTrace> V8InspectorImpl::captureStackTrace(bool fullStack) | 284 std::unique_ptr<V8StackTrace> V8InspectorImpl::captureStackTrace(bool fullStack) |
1083 { | 285 { |
1084 return captureStackTraceImpl(fullStack); | 286 return m_debugger->captureStackTrace(fullStack); |
1085 } | 287 } |
1086 | 288 |
1087 std::unique_ptr<V8StackTraceImpl> V8InspectorImpl::captureStackTraceImpl(bool fu
llStack) | 289 void V8InspectorImpl::asyncTaskScheduled(const String16& taskName, void* task, b
ool recurring) |
1088 { | 290 { |
1089 if (!m_isolate->InContext()) | 291 m_debugger->asyncTaskScheduled(taskName, task, recurring); |
1090 return nullptr; | 292 } |
1091 | 293 |
1092 v8::HandleScope handles(m_isolate); | 294 void V8InspectorImpl::asyncTaskCanceled(void* task) |
1093 int contextGroupId = getGroupId(m_isolate->GetCurrentContext()); | 295 { |
1094 if (!contextGroupId) | 296 m_debugger->asyncTaskCanceled(task); |
1095 return nullptr; | 297 } |
1096 | 298 |
1097 size_t stackSize = fullStack ? V8StackTraceImpl::maxCallStackSizeToCapture :
1; | 299 void V8InspectorImpl::asyncTaskStarted(void* task) |
1098 SessionMap::iterator sessionIt = m_sessions.find(contextGroupId); | 300 { |
1099 if (sessionIt != m_sessions.end() && sessionIt->second->runtimeAgent()->enab
led()) | 301 m_debugger->asyncTaskStarted(task); |
1100 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; | 302 } |
1101 | 303 |
1102 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); | 304 void V8InspectorImpl::asyncTaskFinished(void* task) |
| 305 { |
| 306 m_debugger->asyncTaskFinished(task); |
| 307 } |
| 308 |
| 309 void V8InspectorImpl::allAsyncTasksCanceled() |
| 310 { |
| 311 m_debugger->allAsyncTasksCanceled(); |
1103 } | 312 } |
1104 | 313 |
1105 v8::Local<v8::Context> V8InspectorImpl::regexContext() | 314 v8::Local<v8::Context> V8InspectorImpl::regexContext() |
1106 { | 315 { |
1107 if (m_regexContext.IsEmpty()) | 316 if (m_regexContext.IsEmpty()) |
1108 m_regexContext.Reset(m_isolate, v8::Context::New(m_isolate)); | 317 m_regexContext.Reset(m_isolate, v8::Context::New(m_isolate)); |
1109 return m_regexContext.Get(m_isolate); | 318 return m_regexContext.Get(m_isolate); |
1110 } | 319 } |
1111 | 320 |
1112 void V8InspectorImpl::discardInspectedContext(int contextGroupId, int contextId) | 321 void V8InspectorImpl::discardInspectedContext(int contextGroupId, int contextId) |
(...skipping 13 matching lines...) Expand all Loading... |
1126 | 335 |
1127 V8InspectorSessionImpl* V8InspectorImpl::sessionForContextGroup(int contextGroup
Id) | 336 V8InspectorSessionImpl* V8InspectorImpl::sessionForContextGroup(int contextGroup
Id) |
1128 { | 337 { |
1129 if (!contextGroupId) | 338 if (!contextGroupId) |
1130 return nullptr; | 339 return nullptr; |
1131 SessionMap::iterator iter = m_sessions.find(contextGroupId); | 340 SessionMap::iterator iter = m_sessions.find(contextGroupId); |
1132 return iter == m_sessions.end() ? nullptr : iter->second; | 341 return iter == m_sessions.end() ? nullptr : iter->second; |
1133 } | 342 } |
1134 | 343 |
1135 } // namespace blink | 344 } // namespace blink |
OLD | NEW |