Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(788)

Side by Side Diff: third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.cpp

Issue 2295913003: [DevTools] Switch from platform/v8_inspector to v8/v8-inspector.h. (Closed)
Patch Set: rebase Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "platform/v8_inspector/V8DebuggerAgentImpl.h"
6
7 #include "platform/v8_inspector/InjectedScript.h"
8 #include "platform/v8_inspector/InspectedContext.h"
9 #include "platform/v8_inspector/JavaScriptCallFrame.h"
10 #include "platform/v8_inspector/RemoteObjectId.h"
11 #include "platform/v8_inspector/ScriptBreakpoint.h"
12 #include "platform/v8_inspector/SearchUtil.h"
13 #include "platform/v8_inspector/StringUtil.h"
14 #include "platform/v8_inspector/V8Debugger.h"
15 #include "platform/v8_inspector/V8DebuggerScript.h"
16 #include "platform/v8_inspector/V8InspectorImpl.h"
17 #include "platform/v8_inspector/V8InspectorSessionImpl.h"
18 #include "platform/v8_inspector/V8Regex.h"
19 #include "platform/v8_inspector/V8RuntimeAgentImpl.h"
20 #include "platform/v8_inspector/V8StackTraceImpl.h"
21 #include "platform/v8_inspector/protocol/Protocol.h"
22 #include "platform/v8_inspector/public/V8InspectorClient.h"
23
24 #include <algorithm>
25
26 namespace v8_inspector {
27
28 using protocol::Array;
29 using protocol::Maybe;
30 using protocol::Debugger::BreakpointId;
31 using protocol::Debugger::CallFrame;
32 using protocol::Runtime::ExceptionDetails;
33 using protocol::Runtime::ScriptId;
34 using protocol::Runtime::StackTrace;
35 using protocol::Runtime::RemoteObject;
36
37 namespace DebuggerAgentState {
38 static const char javaScriptBreakpoints[] = "javaScriptBreakopints";
39 static const char pauseOnExceptionsState[] = "pauseOnExceptionsState";
40 static const char asyncCallStackDepth[] = "asyncCallStackDepth";
41 static const char blackboxPattern[] = "blackboxPattern";
42 static const char debuggerEnabled[] = "debuggerEnabled";
43
44 // Breakpoint properties.
45 static const char url[] = "url";
46 static const char isRegex[] = "isRegex";
47 static const char lineNumber[] = "lineNumber";
48 static const char columnNumber[] = "columnNumber";
49 static const char condition[] = "condition";
50 static const char skipAllPauses[] = "skipAllPauses";
51
52 } // namespace DebuggerAgentState;
53
54 static const int maxSkipStepFrameCount = 128;
55 static const char backtraceObjectGroup[] = "backtrace";
56
57 static String16 breakpointIdSuffix(V8DebuggerAgentImpl::BreakpointSource source)
58 {
59 switch (source) {
60 case V8DebuggerAgentImpl::UserBreakpointSource:
61 break;
62 case V8DebuggerAgentImpl::DebugCommandBreakpointSource:
63 return ":debug";
64 case V8DebuggerAgentImpl::MonitorCommandBreakpointSource:
65 return ":monitor";
66 }
67 return String16();
68 }
69
70 static String16 generateBreakpointId(const String16& scriptId, int lineNumber, i nt columnNumber, V8DebuggerAgentImpl::BreakpointSource source)
71 {
72 return scriptId + ":" + String16::fromInteger(lineNumber) + ":" + String16:: fromInteger(columnNumber) + breakpointIdSuffix(source);
73 }
74
75 static bool positionComparator(const std::pair<int, int>& a, const std::pair<int , int>& b)
76 {
77 if (a.first != b.first)
78 return a.first < b.first;
79 return a.second < b.second;
80 }
81
82 static bool hasInternalError(ErrorString* errorString, bool hasError)
83 {
84 if (hasError)
85 *errorString = "Internal error";
86 return hasError;
87 }
88
89 static std::unique_ptr<protocol::Debugger::Location> buildProtocolLocation(const String16& scriptId, int lineNumber, int columnNumber)
90 {
91 return protocol::Debugger::Location::create()
92 .setScriptId(scriptId)
93 .setLineNumber(lineNumber)
94 .setColumnNumber(columnNumber).build();
95 }
96
97 V8DebuggerAgentImpl::V8DebuggerAgentImpl(V8InspectorSessionImpl* session, protoc ol::FrontendChannel* frontendChannel, protocol::DictionaryValue* state)
98 : m_inspector(session->inspector())
99 , m_debugger(m_inspector->debugger())
100 , m_session(session)
101 , m_enabled(false)
102 , m_state(state)
103 , m_frontend(frontendChannel)
104 , m_isolate(m_inspector->isolate())
105 , m_breakReason(protocol::Debugger::Paused::ReasonEnum::Other)
106 , m_scheduledDebuggerStep(NoStep)
107 , m_skipNextDebuggerStepOut(false)
108 , m_javaScriptPauseScheduled(false)
109 , m_steppingFromFramework(false)
110 , m_pausingOnNativeEvent(false)
111 , m_skippedStepFrameCount(0)
112 , m_recursionLevelForStepOut(0)
113 , m_recursionLevelForStepFrame(0)
114 , m_skipAllPauses(false)
115 {
116 clearBreakDetails();
117 }
118
119 V8DebuggerAgentImpl::~V8DebuggerAgentImpl()
120 {
121 }
122
123 bool V8DebuggerAgentImpl::checkEnabled(ErrorString* errorString)
124 {
125 if (enabled())
126 return true;
127 *errorString = "Debugger agent is not enabled";
128 return false;
129 }
130
131 void V8DebuggerAgentImpl::enable()
132 {
133 // m_inspector->addListener may result in reporting all parsed scripts to
134 // the agent so it should already be in enabled state by then.
135 m_enabled = true;
136 m_state->setBoolean(DebuggerAgentState::debuggerEnabled, true);
137 m_debugger->enable();
138
139 std::vector<std::unique_ptr<V8DebuggerScript>> compiledScripts;
140 m_debugger->getCompiledScripts(m_session->contextGroupId(), compiledScripts) ;
141 for (size_t i = 0; i < compiledScripts.size(); i++)
142 didParseSource(std::move(compiledScripts[i]), true);
143
144 // FIXME(WK44513): breakpoints activated flag should be synchronized between all front-ends
145 m_debugger->setBreakpointsActivated(true);
146 }
147
148 bool V8DebuggerAgentImpl::enabled()
149 {
150 return m_enabled;
151 }
152
153 void V8DebuggerAgentImpl::enable(ErrorString* errorString)
154 {
155 if (enabled())
156 return;
157
158 if (!m_inspector->client()->canExecuteScripts(m_session->contextGroupId())) {
159 *errorString = "Script execution is prohibited";
160 return;
161 }
162
163 enable();
164 }
165
166 void V8DebuggerAgentImpl::disable(ErrorString*)
167 {
168 if (!enabled())
169 return;
170
171 m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, protocol::Dict ionaryValue::create());
172 m_state->setInteger(DebuggerAgentState::pauseOnExceptionsState, V8Debugger:: DontPauseOnExceptions);
173 m_state->setInteger(DebuggerAgentState::asyncCallStackDepth, 0);
174
175 if (!m_pausedContext.IsEmpty())
176 m_debugger->continueProgram();
177 m_debugger->disable();
178 m_pausedContext.Reset();
179 JavaScriptCallFrames emptyCallFrames;
180 m_pausedCallFrames.swap(emptyCallFrames);
181 m_scripts.clear();
182 m_blackboxedPositions.clear();
183 m_breakpointIdToDebuggerBreakpointIds.clear();
184 m_debugger->setAsyncCallStackDepth(this, 0);
185 m_continueToLocationBreakpointId = String16();
186 clearBreakDetails();
187 m_scheduledDebuggerStep = NoStep;
188 m_skipNextDebuggerStepOut = false;
189 m_javaScriptPauseScheduled = false;
190 m_steppingFromFramework = false;
191 m_pausingOnNativeEvent = false;
192 m_skippedStepFrameCount = 0;
193 m_recursionLevelForStepFrame = 0;
194 m_skipAllPauses = false;
195 m_blackboxPattern = nullptr;
196 m_state->remove(DebuggerAgentState::blackboxPattern);
197 m_enabled = false;
198 m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false);
199 }
200
201 void V8DebuggerAgentImpl::restore()
202 {
203 DCHECK(!m_enabled);
204 if (!m_state->booleanProperty(DebuggerAgentState::debuggerEnabled, false))
205 return;
206 if (!m_inspector->client()->canExecuteScripts(m_session->contextGroupId()))
207 return;
208
209 enable();
210 ErrorString error;
211
212 int pauseState = V8Debugger::DontPauseOnExceptions;
213 m_state->getInteger(DebuggerAgentState::pauseOnExceptionsState, &pauseState) ;
214 setPauseOnExceptionsImpl(&error, pauseState);
215 DCHECK(error.isEmpty());
216
217 m_skipAllPauses = m_state->booleanProperty(DebuggerAgentState::skipAllPauses , false);
218
219 int asyncCallStackDepth = 0;
220 m_state->getInteger(DebuggerAgentState::asyncCallStackDepth, &asyncCallStack Depth);
221 m_debugger->setAsyncCallStackDepth(this, asyncCallStackDepth);
222
223 String16 blackboxPattern;
224 if (m_state->getString(DebuggerAgentState::blackboxPattern, &blackboxPattern )) {
225 if (!setBlackboxPattern(&error, blackboxPattern))
226 NOTREACHED();
227 }
228 }
229
230 void V8DebuggerAgentImpl::setBreakpointsActive(ErrorString* errorString, bool ac tive)
231 {
232 if (!checkEnabled(errorString))
233 return;
234 m_debugger->setBreakpointsActivated(active);
235 }
236
237 void V8DebuggerAgentImpl::setSkipAllPauses(ErrorString*, bool skip)
238 {
239 m_skipAllPauses = skip;
240 m_state->setBoolean(DebuggerAgentState::skipAllPauses, m_skipAllPauses);
241 }
242
243 static std::unique_ptr<protocol::DictionaryValue> buildObjectForBreakpointCookie (const String16& url, int lineNumber, int columnNumber, const String16& conditio n, bool isRegex)
244 {
245 std::unique_ptr<protocol::DictionaryValue> breakpointObject = protocol::Dict ionaryValue::create();
246 breakpointObject->setString(DebuggerAgentState::url, url);
247 breakpointObject->setInteger(DebuggerAgentState::lineNumber, lineNumber);
248 breakpointObject->setInteger(DebuggerAgentState::columnNumber, columnNumber) ;
249 breakpointObject->setString(DebuggerAgentState::condition, condition);
250 breakpointObject->setBoolean(DebuggerAgentState::isRegex, isRegex);
251 return breakpointObject;
252 }
253
254 static bool matches(V8InspectorImpl* inspector, const String16& url, const Strin g16& pattern, bool isRegex)
255 {
256 if (isRegex) {
257 V8Regex regex(inspector, pattern, true);
258 return regex.match(url) != -1;
259 }
260 return url == pattern;
261 }
262
263 void V8DebuggerAgentImpl::setBreakpointByUrl(ErrorString* errorString,
264 int lineNumber,
265 const Maybe<String16>& optionalURL,
266 const Maybe<String16>& optionalURLRegex,
267 const Maybe<int>& optionalColumnNumber,
268 const Maybe<String16>& optionalCondition,
269 String16* outBreakpointId,
270 std::unique_ptr<protocol::Array<protocol::Debugger::Location>>* locations)
271 {
272 *locations = Array<protocol::Debugger::Location>::create();
273 if (optionalURL.isJust() == optionalURLRegex.isJust()) {
274 *errorString = "Either url or urlRegex must be specified.";
275 return;
276 }
277
278 String16 url = optionalURL.isJust() ? optionalURL.fromJust() : optionalURLRe gex.fromJust();
279 int columnNumber = 0;
280 if (optionalColumnNumber.isJust()) {
281 columnNumber = optionalColumnNumber.fromJust();
282 if (columnNumber < 0) {
283 *errorString = "Incorrect column number";
284 return;
285 }
286 }
287 String16 condition = optionalCondition.fromMaybe("");
288 bool isRegex = optionalURLRegex.isJust();
289
290 String16 breakpointId = (isRegex ? "/" + url + "/" : url) + ":" + String16:: fromInteger(lineNumber) + ":" + String16::fromInteger(columnNumber);
291 protocol::DictionaryValue* breakpointsCookie = m_state->getObject(DebuggerAg entState::javaScriptBreakpoints);
292 if (!breakpointsCookie) {
293 std::unique_ptr<protocol::DictionaryValue> newValue = protocol::Dictiona ryValue::create();
294 breakpointsCookie = newValue.get();
295 m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, std::move( newValue));
296 }
297 if (breakpointsCookie->get(breakpointId)) {
298 *errorString = "Breakpoint at specified location already exists.";
299 return;
300 }
301
302 breakpointsCookie->setObject(breakpointId, buildObjectForBreakpointCookie(ur l, lineNumber, columnNumber, condition, isRegex));
303
304 ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition);
305 for (const auto& script : m_scripts) {
306 if (!matches(m_inspector, script.second->sourceURL(), url, isRegex))
307 continue;
308 std::unique_ptr<protocol::Debugger::Location> location = resolveBreakpoi nt(breakpointId, script.first, breakpoint, UserBreakpointSource);
309 if (location)
310 (*locations)->addItem(std::move(location));
311 }
312
313 *outBreakpointId = breakpointId;
314 }
315
316 static bool parseLocation(ErrorString* errorString, std::unique_ptr<protocol::De bugger::Location> location, String16* scriptId, int* lineNumber, int* columnNumb er)
317 {
318 *scriptId = location->getScriptId();
319 *lineNumber = location->getLineNumber();
320 *columnNumber = location->getColumnNumber(0);
321 return true;
322 }
323
324 void V8DebuggerAgentImpl::setBreakpoint(ErrorString* errorString,
325 std::unique_ptr<protocol::Debugger::Location> location,
326 const Maybe<String16>& optionalCondition,
327 String16* outBreakpointId,
328 std::unique_ptr<protocol::Debugger::Location>* actualLocation)
329 {
330 String16 scriptId;
331 int lineNumber;
332 int columnNumber;
333
334 if (!parseLocation(errorString, std::move(location), &scriptId, &lineNumber, &columnNumber))
335 return;
336
337 String16 condition = optionalCondition.fromMaybe("");
338
339 String16 breakpointId = generateBreakpointId(scriptId, lineNumber, columnNum ber, UserBreakpointSource);
340 if (m_breakpointIdToDebuggerBreakpointIds.find(breakpointId) != m_breakpoint IdToDebuggerBreakpointIds.end()) {
341 *errorString = "Breakpoint at specified location already exists.";
342 return;
343 }
344 ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition);
345 *actualLocation = resolveBreakpoint(breakpointId, scriptId, breakpoint, User BreakpointSource);
346 if (*actualLocation)
347 *outBreakpointId = breakpointId;
348 else
349 *errorString = "Could not resolve breakpoint";
350 }
351
352 void V8DebuggerAgentImpl::removeBreakpoint(ErrorString* errorString, const Strin g16& breakpointId)
353 {
354 if (!checkEnabled(errorString))
355 return;
356 protocol::DictionaryValue* breakpointsCookie = m_state->getObject(DebuggerAg entState::javaScriptBreakpoints);
357 if (breakpointsCookie)
358 breakpointsCookie->remove(breakpointId);
359 removeBreakpoint(breakpointId);
360 }
361
362 void V8DebuggerAgentImpl::removeBreakpoint(const String16& breakpointId)
363 {
364 DCHECK(enabled());
365 BreakpointIdToDebuggerBreakpointIdsMap::iterator debuggerBreakpointIdsIterat or = m_breakpointIdToDebuggerBreakpointIds.find(breakpointId);
366 if (debuggerBreakpointIdsIterator == m_breakpointIdToDebuggerBreakpointIds.e nd())
367 return;
368 const std::vector<String16>& ids = debuggerBreakpointIdsIterator->second;
369 for (size_t i = 0; i < ids.size(); ++i) {
370 const String16& debuggerBreakpointId = ids[i];
371
372 m_debugger->removeBreakpoint(debuggerBreakpointId);
373 m_serverBreakpoints.erase(debuggerBreakpointId);
374 }
375 m_breakpointIdToDebuggerBreakpointIds.erase(breakpointId);
376 }
377
378 void V8DebuggerAgentImpl::continueToLocation(ErrorString* errorString, std::uniq ue_ptr<protocol::Debugger::Location> location)
379 {
380 if (!checkEnabled(errorString))
381 return;
382 if (!m_continueToLocationBreakpointId.isEmpty()) {
383 m_debugger->removeBreakpoint(m_continueToLocationBreakpointId);
384 m_continueToLocationBreakpointId = "";
385 }
386
387 String16 scriptId;
388 int lineNumber;
389 int columnNumber;
390
391 if (!parseLocation(errorString, std::move(location), &scriptId, &lineNumber, &columnNumber))
392 return;
393
394 ScriptBreakpoint breakpoint(lineNumber, columnNumber, "");
395 m_continueToLocationBreakpointId = m_debugger->setBreakpoint(scriptId, break point, &lineNumber, &columnNumber);
396 resume(errorString);
397 }
398
399 bool V8DebuggerAgentImpl::isCurrentCallStackEmptyOrBlackboxed()
400 {
401 DCHECK(enabled());
402 JavaScriptCallFrames callFrames = m_debugger->currentCallFrames();
403 for (size_t index = 0; index < callFrames.size(); ++index) {
404 if (!isCallFrameWithUnknownScriptOrBlackboxed(callFrames[index].get()))
405 return false;
406 }
407 return true;
408 }
409
410 bool V8DebuggerAgentImpl::isTopPausedCallFrameBlackboxed()
411 {
412 DCHECK(enabled());
413 JavaScriptCallFrame* frame = m_pausedCallFrames.size() ? m_pausedCallFrames[ 0].get() : nullptr;
414 return isCallFrameWithUnknownScriptOrBlackboxed(frame);
415 }
416
417 bool V8DebuggerAgentImpl::isCallFrameWithUnknownScriptOrBlackboxed(JavaScriptCal lFrame* frame)
418 {
419 if (!frame)
420 return true;
421 ScriptsMap::iterator it = m_scripts.find(String16::fromInteger(frame->source ID()));
422 if (it == m_scripts.end()) {
423 // Unknown scripts are blackboxed.
424 return true;
425 }
426 if (m_blackboxPattern) {
427 const String16& scriptSourceURL = it->second->sourceURL();
428 if (!scriptSourceURL.isEmpty() && m_blackboxPattern->match(scriptSourceU RL) != -1)
429 return true;
430 }
431 auto itBlackboxedPositions = m_blackboxedPositions.find(String16::fromIntege r(frame->sourceID()));
432 if (itBlackboxedPositions == m_blackboxedPositions.end())
433 return false;
434
435 const std::vector<std::pair<int, int>>& ranges = itBlackboxedPositions->seco nd;
436 auto itRange = std::lower_bound(ranges.begin(), ranges.end(),
437 std::make_pair(frame->line(), frame->column()), positionComparator);
438 // Ranges array contains positions in script where blackbox state is changed .
439 // [(0,0) ... ranges[0]) isn't blackboxed, [ranges[0] ... ranges[1]) is blac kboxed...
440 return std::distance(ranges.begin(), itRange) % 2;
441 }
442
443 V8DebuggerAgentImpl::SkipPauseRequest V8DebuggerAgentImpl::shouldSkipExceptionPa use(JavaScriptCallFrame* topCallFrame)
444 {
445 if (m_steppingFromFramework)
446 return RequestNoSkip;
447 if (isCallFrameWithUnknownScriptOrBlackboxed(topCallFrame))
448 return RequestContinue;
449 return RequestNoSkip;
450 }
451
452 V8DebuggerAgentImpl::SkipPauseRequest V8DebuggerAgentImpl::shouldSkipStepPause(J avaScriptCallFrame* topCallFrame)
453 {
454 if (m_steppingFromFramework)
455 return RequestNoSkip;
456
457 if (m_skipNextDebuggerStepOut) {
458 m_skipNextDebuggerStepOut = false;
459 if (m_scheduledDebuggerStep == StepOut)
460 return RequestStepOut;
461 }
462
463 if (!isCallFrameWithUnknownScriptOrBlackboxed(topCallFrame))
464 return RequestNoSkip;
465
466 if (m_skippedStepFrameCount >= maxSkipStepFrameCount)
467 return RequestStepOut;
468
469 if (!m_skippedStepFrameCount)
470 m_recursionLevelForStepFrame = 1;
471
472 ++m_skippedStepFrameCount;
473 return RequestStepFrame;
474 }
475
476 std::unique_ptr<protocol::Debugger::Location> V8DebuggerAgentImpl::resolveBreakp oint(const String16& breakpointId, const String16& scriptId, const ScriptBreakpo int& breakpoint, BreakpointSource source)
477 {
478 DCHECK(enabled());
479 // FIXME: remove these checks once crbug.com/520702 is resolved.
480 CHECK(!breakpointId.isEmpty());
481 CHECK(!scriptId.isEmpty());
482 ScriptsMap::iterator scriptIterator = m_scripts.find(scriptId);
483 if (scriptIterator == m_scripts.end())
484 return nullptr;
485 if (breakpoint.lineNumber < scriptIterator->second->startLine() || scriptIte rator->second->endLine() < breakpoint.lineNumber)
486 return nullptr;
487
488 int actualLineNumber;
489 int actualColumnNumber;
490 String16 debuggerBreakpointId = m_debugger->setBreakpoint(scriptId, breakpoi nt, &actualLineNumber, &actualColumnNumber);
491 if (debuggerBreakpointId.isEmpty())
492 return nullptr;
493
494 m_serverBreakpoints[debuggerBreakpointId] = std::make_pair(breakpointId, sou rce);
495 CHECK(!breakpointId.isEmpty());
496
497 m_breakpointIdToDebuggerBreakpointIds[breakpointId].push_back(debuggerBreakp ointId);
498 return buildProtocolLocation(scriptId, actualLineNumber, actualColumnNumber) ;
499 }
500
501 void V8DebuggerAgentImpl::searchInContent(ErrorString* error, const String16& sc riptId, const String16& query,
502 const Maybe<bool>& optionalCaseSensitive,
503 const Maybe<bool>& optionalIsRegex,
504 std::unique_ptr<Array<protocol::Debugger::SearchMatch>>* results)
505 {
506 v8::HandleScope handles(m_isolate);
507 ScriptsMap::iterator it = m_scripts.find(scriptId);
508 if (it == m_scripts.end()) {
509 *error = String16("No script for id: " + scriptId);
510 return;
511 }
512
513 std::vector<std::unique_ptr<protocol::Debugger::SearchMatch>> matches = sear chInTextByLinesImpl(m_session, toProtocolString(it->second->source(m_isolate)), query, optionalCaseSensitive.fromMaybe(false), optionalIsRegex.fromMaybe(false)) ;
514 *results = protocol::Array<protocol::Debugger::SearchMatch>::create();
515 for (size_t i = 0; i < matches.size(); ++i)
516 (*results)->addItem(std::move(matches[i]));
517 }
518
519 void V8DebuggerAgentImpl::setScriptSource(ErrorString* errorString,
520 const String16& scriptId,
521 const String16& newContent,
522 const Maybe<bool>& dryRun,
523 Maybe<protocol::Array<protocol::Debugger::CallFrame>>* newCallFrames,
524 Maybe<bool>* stackChanged,
525 Maybe<StackTrace>* asyncStackTrace,
526 Maybe<protocol::Runtime::ExceptionDetails>* optOutCompileError)
527 {
528 if (!checkEnabled(errorString))
529 return;
530
531 v8::HandleScope handles(m_isolate);
532 v8::Local<v8::String> newSource = toV8String(m_isolate, newContent);
533 if (!m_debugger->setScriptSource(scriptId, newSource, dryRun.fromMaybe(false ), errorString, optOutCompileError, &m_pausedCallFrames, stackChanged))
534 return;
535
536 ScriptsMap::iterator it = m_scripts.find(scriptId);
537 if (it != m_scripts.end())
538 it->second->setSource(m_isolate, newSource);
539
540 std::unique_ptr<Array<CallFrame>> callFrames = currentCallFrames(errorString );
541 if (!callFrames)
542 return;
543 *newCallFrames = std::move(callFrames);
544 *asyncStackTrace = currentAsyncStackTrace();
545 }
546
547 void V8DebuggerAgentImpl::restartFrame(ErrorString* errorString,
548 const String16& callFrameId,
549 std::unique_ptr<Array<CallFrame>>* newCallFrames,
550 Maybe<StackTrace>* asyncStackTrace)
551 {
552 if (!assertPaused(errorString))
553 return;
554 InjectedScript::CallFrameScope scope(errorString, m_inspector, m_session->co ntextGroupId(), callFrameId);
555 if (!scope.initialize())
556 return;
557 if (scope.frameOrdinal() >= m_pausedCallFrames.size()) {
558 *errorString = "Could not find call frame with given id";
559 return;
560 }
561
562 v8::Local<v8::Value> resultValue;
563 v8::Local<v8::Boolean> result;
564 if (!m_pausedCallFrames[scope.frameOrdinal()]->restart().ToLocal(&resultValu e) || scope.tryCatch().HasCaught() || !resultValue->ToBoolean(scope.context()).T oLocal(&result) || !result->Value()) {
565 *errorString = "Internal error";
566 return;
567 }
568 JavaScriptCallFrames frames = m_debugger->currentCallFrames();
569 m_pausedCallFrames.swap(frames);
570
571 *newCallFrames = currentCallFrames(errorString);
572 if (!*newCallFrames)
573 return;
574 *asyncStackTrace = currentAsyncStackTrace();
575 }
576
577 void V8DebuggerAgentImpl::getScriptSource(ErrorString* error, const String16& sc riptId, String16* scriptSource)
578 {
579 if (!checkEnabled(error))
580 return;
581 ScriptsMap::iterator it = m_scripts.find(scriptId);
582 if (it == m_scripts.end()) {
583 *error = "No script for id: " + scriptId;
584 return;
585 }
586 v8::HandleScope handles(m_isolate);
587 *scriptSource = toProtocolString(it->second->source(m_isolate));
588 }
589
590 void V8DebuggerAgentImpl::schedulePauseOnNextStatement(const String16& breakReas on, std::unique_ptr<protocol::DictionaryValue> data)
591 {
592 if (!enabled() || m_scheduledDebuggerStep == StepInto || m_javaScriptPauseSc heduled || m_debugger->isPaused() || !m_debugger->breakpointsActivated())
593 return;
594 m_breakReason = breakReason;
595 m_breakAuxData = std::move(data);
596 m_pausingOnNativeEvent = true;
597 m_skipNextDebuggerStepOut = false;
598 m_debugger->setPauseOnNextStatement(true);
599 }
600
601 void V8DebuggerAgentImpl::schedulePauseOnNextStatementIfSteppingInto()
602 {
603 DCHECK(enabled());
604 if (m_scheduledDebuggerStep != StepInto || m_javaScriptPauseScheduled || m_d ebugger->isPaused())
605 return;
606 clearBreakDetails();
607 m_pausingOnNativeEvent = false;
608 m_skippedStepFrameCount = 0;
609 m_recursionLevelForStepFrame = 0;
610 m_debugger->setPauseOnNextStatement(true);
611 }
612
613 void V8DebuggerAgentImpl::cancelPauseOnNextStatement()
614 {
615 if (m_javaScriptPauseScheduled || m_debugger->isPaused())
616 return;
617 clearBreakDetails();
618 m_pausingOnNativeEvent = false;
619 m_debugger->setPauseOnNextStatement(false);
620 }
621
622 void V8DebuggerAgentImpl::pause(ErrorString* errorString)
623 {
624 if (!checkEnabled(errorString))
625 return;
626 if (m_javaScriptPauseScheduled || m_debugger->isPaused())
627 return;
628 clearBreakDetails();
629 m_javaScriptPauseScheduled = true;
630 m_scheduledDebuggerStep = NoStep;
631 m_skippedStepFrameCount = 0;
632 m_steppingFromFramework = false;
633 m_debugger->setPauseOnNextStatement(true);
634 }
635
636 void V8DebuggerAgentImpl::resume(ErrorString* errorString)
637 {
638 if (!assertPaused(errorString))
639 return;
640 m_scheduledDebuggerStep = NoStep;
641 m_steppingFromFramework = false;
642 m_session->releaseObjectGroup(backtraceObjectGroup);
643 m_debugger->continueProgram();
644 }
645
646 void V8DebuggerAgentImpl::stepOver(ErrorString* errorString)
647 {
648 if (!assertPaused(errorString))
649 return;
650 // StepOver at function return point should fallback to StepInto.
651 JavaScriptCallFrame* frame = !m_pausedCallFrames.empty() ? m_pausedCallFrame s[0].get() : nullptr;
652 if (frame && frame->isAtReturn()) {
653 stepInto(errorString);
654 return;
655 }
656 m_scheduledDebuggerStep = StepOver;
657 m_steppingFromFramework = isTopPausedCallFrameBlackboxed();
658 m_session->releaseObjectGroup(backtraceObjectGroup);
659 m_debugger->stepOverStatement();
660 }
661
662 void V8DebuggerAgentImpl::stepInto(ErrorString* errorString)
663 {
664 if (!assertPaused(errorString))
665 return;
666 m_scheduledDebuggerStep = StepInto;
667 m_steppingFromFramework = isTopPausedCallFrameBlackboxed();
668 m_session->releaseObjectGroup(backtraceObjectGroup);
669 m_debugger->stepIntoStatement();
670 }
671
672 void V8DebuggerAgentImpl::stepOut(ErrorString* errorString)
673 {
674 if (!assertPaused(errorString))
675 return;
676 m_scheduledDebuggerStep = StepOut;
677 m_skipNextDebuggerStepOut = false;
678 m_recursionLevelForStepOut = 1;
679 m_steppingFromFramework = isTopPausedCallFrameBlackboxed();
680 m_session->releaseObjectGroup(backtraceObjectGroup);
681 m_debugger->stepOutOfFunction();
682 }
683
684 void V8DebuggerAgentImpl::setPauseOnExceptions(ErrorString* errorString, const S tring16& stringPauseState)
685 {
686 if (!checkEnabled(errorString))
687 return;
688 V8Debugger::PauseOnExceptionsState pauseState;
689 if (stringPauseState == "none") {
690 pauseState = V8Debugger::DontPauseOnExceptions;
691 } else if (stringPauseState == "all") {
692 pauseState = V8Debugger::PauseOnAllExceptions;
693 } else if (stringPauseState == "uncaught") {
694 pauseState = V8Debugger::PauseOnUncaughtExceptions;
695 } else {
696 *errorString = "Unknown pause on exceptions mode: " + stringPauseState;
697 return;
698 }
699 setPauseOnExceptionsImpl(errorString, pauseState);
700 }
701
702 void V8DebuggerAgentImpl::setPauseOnExceptionsImpl(ErrorString* errorString, int pauseState)
703 {
704 m_debugger->setPauseOnExceptionsState(static_cast<V8Debugger::PauseOnExcepti onsState>(pauseState));
705 if (m_debugger->getPauseOnExceptionsState() != pauseState)
706 *errorString = "Internal error. Could not change pause on exceptions sta te";
707 else
708 m_state->setInteger(DebuggerAgentState::pauseOnExceptionsState, pauseSta te);
709 }
710
711 void V8DebuggerAgentImpl::evaluateOnCallFrame(ErrorString* errorString,
712 const String16& callFrameId,
713 const String16& expression,
714 const Maybe<String16>& objectGroup,
715 const Maybe<bool>& includeCommandLineAPI,
716 const Maybe<bool>& silent,
717 const Maybe<bool>& returnByValue,
718 const Maybe<bool>& generatePreview,
719 std::unique_ptr<RemoteObject>* result,
720 Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails)
721 {
722 if (!assertPaused(errorString))
723 return;
724 InjectedScript::CallFrameScope scope(errorString, m_inspector, m_session->co ntextGroupId(), callFrameId);
725 if (!scope.initialize())
726 return;
727 if (scope.frameOrdinal() >= m_pausedCallFrames.size()) {
728 *errorString = "Could not find call frame with given id";
729 return;
730 }
731
732 if (includeCommandLineAPI.fromMaybe(false) && !scope.installCommandLineAPI() )
733 return;
734 if (silent.fromMaybe(false))
735 scope.ignoreExceptionsAndMuteConsole();
736
737 v8::MaybeLocal<v8::Value> maybeResultValue = m_pausedCallFrames[scope.frameO rdinal()]->evaluate(toV8String(m_isolate, expression));
738
739 // Re-initialize after running client's code, as it could have destroyed con text or session.
740 if (!scope.initialize())
741 return;
742 scope.injectedScript()->wrapEvaluateResult(errorString,
743 maybeResultValue,
744 scope.tryCatch(),
745 objectGroup.fromMaybe(""),
746 returnByValue.fromMaybe(false),
747 generatePreview.fromMaybe(false),
748 result,
749 exceptionDetails);
750 }
751
752 void V8DebuggerAgentImpl::setVariableValue(ErrorString* errorString,
753 int scopeNumber,
754 const String16& variableName,
755 std::unique_ptr<protocol::Runtime::CallArgument> newValueArgument,
756 const String16& callFrameId)
757 {
758 if (!checkEnabled(errorString))
759 return;
760 if (!assertPaused(errorString))
761 return;
762 InjectedScript::CallFrameScope scope(errorString, m_inspector, m_session->co ntextGroupId(), callFrameId);
763 if (!scope.initialize())
764 return;
765
766 v8::Local<v8::Value> newValue;
767 if (!scope.injectedScript()->resolveCallArgument(errorString, newValueArgume nt.get()).ToLocal(&newValue))
768 return;
769
770 if (scope.frameOrdinal() >= m_pausedCallFrames.size()) {
771 *errorString = "Could not find call frame with given id";
772 return;
773 }
774 v8::MaybeLocal<v8::Value> result = m_pausedCallFrames[scope.frameOrdinal()]- >setVariableValue(scopeNumber, toV8String(m_isolate, variableName), newValue);
775 if (scope.tryCatch().HasCaught() || result.IsEmpty()) {
776 *errorString = "Internal error";
777 return;
778 }
779 }
780
781 void V8DebuggerAgentImpl::setAsyncCallStackDepth(ErrorString* errorString, int d epth)
782 {
783 if (!checkEnabled(errorString))
784 return;
785 m_state->setInteger(DebuggerAgentState::asyncCallStackDepth, depth);
786 m_debugger->setAsyncCallStackDepth(this, depth);
787 }
788
789 void V8DebuggerAgentImpl::setBlackboxPatterns(ErrorString* errorString, std::uni que_ptr<protocol::Array<String16>> patterns)
790 {
791 if (!patterns->length()) {
792 m_blackboxPattern = nullptr;
793 m_state->remove(DebuggerAgentState::blackboxPattern);
794 return;
795 }
796
797 String16Builder patternBuilder;
798 patternBuilder.append('(');
799 for (size_t i = 0; i < patterns->length() - 1; ++i) {
800 patternBuilder.append(patterns->get(i));
801 patternBuilder.append("|");
802 }
803 patternBuilder.append(patterns->get(patterns->length() - 1));
804 patternBuilder.append(')');
805 String16 pattern = patternBuilder.toString();
806 if (!setBlackboxPattern(errorString, pattern))
807 return;
808 m_state->setString(DebuggerAgentState::blackboxPattern, pattern);
809 }
810
811 bool V8DebuggerAgentImpl::setBlackboxPattern(ErrorString* errorString, const Str ing16& pattern)
812 {
813 std::unique_ptr<V8Regex> regex(new V8Regex(m_inspector, pattern, true /** ca seSensitive */, false /** multiline */));
814 if (!regex->isValid()) {
815 *errorString = "Pattern parser error: " + regex->errorMessage();
816 return false;
817 }
818 m_blackboxPattern = std::move(regex);
819 return true;
820 }
821
822 void V8DebuggerAgentImpl::setBlackboxedRanges(ErrorString* error, const String16 & scriptId,
823 std::unique_ptr<protocol::Array<protocol::Debugger::ScriptPosition>> inPosit ions)
824 {
825 if (m_scripts.find(scriptId) == m_scripts.end()) {
826 *error = "No script with passed id.";
827 return;
828 }
829
830 if (!inPositions->length()) {
831 m_blackboxedPositions.erase(scriptId);
832 return;
833 }
834
835 std::vector<std::pair<int, int>> positions;
836 positions.reserve(inPositions->length());
837 for (size_t i = 0; i < inPositions->length(); ++i) {
838 protocol::Debugger::ScriptPosition* position = inPositions->get(i);
839 if (position->getLineNumber() < 0) {
840 *error = "Position missing 'line' or 'line' < 0.";
841 return;
842 }
843 if (position->getColumnNumber() < 0) {
844 *error = "Position missing 'column' or 'column' < 0.";
845 return;
846 }
847 positions.push_back(std::make_pair(position->getLineNumber(), position-> getColumnNumber()));
848 }
849
850 for (size_t i = 1; i < positions.size(); ++i) {
851 if (positions[i - 1].first < positions[i].first)
852 continue;
853 if (positions[i - 1].first == positions[i].first && positions[i - 1].sec ond < positions[i].second)
854 continue;
855 *error = "Input positions array is not sorted or contains duplicate valu es.";
856 return;
857 }
858
859 m_blackboxedPositions[scriptId] = positions;
860 }
861
862 void V8DebuggerAgentImpl::willExecuteScript(int scriptId)
863 {
864 changeJavaScriptRecursionLevel(+1);
865 // Fast return.
866 if (m_scheduledDebuggerStep != StepInto)
867 return;
868 schedulePauseOnNextStatementIfSteppingInto();
869 }
870
871 void V8DebuggerAgentImpl::didExecuteScript()
872 {
873 changeJavaScriptRecursionLevel(-1);
874 }
875
876 void V8DebuggerAgentImpl::changeJavaScriptRecursionLevel(int step)
877 {
878 if (m_javaScriptPauseScheduled && !m_skipAllPauses && !m_debugger->isPaused( )) {
879 // Do not ever loose user's pause request until we have actually paused.
880 m_debugger->setPauseOnNextStatement(true);
881 }
882 if (m_scheduledDebuggerStep == StepOut) {
883 m_recursionLevelForStepOut += step;
884 if (!m_recursionLevelForStepOut) {
885 // When StepOut crosses a task boundary (i.e. js -> c++) from where it was requested,
886 // switch stepping to step into a next JS task, as if we exited to a blackboxed framework.
887 m_scheduledDebuggerStep = StepInto;
888 m_skipNextDebuggerStepOut = false;
889 }
890 }
891 if (m_recursionLevelForStepFrame) {
892 m_recursionLevelForStepFrame += step;
893 if (!m_recursionLevelForStepFrame) {
894 // We have walked through a blackboxed framework and got back to whe re we started.
895 // If there was no stepping scheduled, we should cancel the stepping explicitly,
896 // since there may be a scheduled StepFrame left.
897 // Otherwise, if we were stepping in/over, the StepFrame will stop a t the right location,
898 // whereas if we were stepping out, we should continue doing so afte r debugger pauses
899 // from the old StepFrame.
900 m_skippedStepFrameCount = 0;
901 if (m_scheduledDebuggerStep == NoStep)
902 m_debugger->clearStepping();
903 else if (m_scheduledDebuggerStep == StepOut)
904 m_skipNextDebuggerStepOut = true;
905 }
906 }
907 }
908
909 std::unique_ptr<Array<CallFrame>> V8DebuggerAgentImpl::currentCallFrames(ErrorSt ring* errorString)
910 {
911 if (m_pausedContext.IsEmpty() || !m_pausedCallFrames.size())
912 return Array<CallFrame>::create();
913 ErrorString ignored;
914 v8::HandleScope handles(m_isolate);
915 v8::Local<v8::Context> debuggerContext = v8::Debug::GetDebugContext(m_isolat e);
916 v8::Context::Scope contextScope(debuggerContext);
917
918 v8::Local<v8::Array> objects = v8::Array::New(m_isolate);
919
920 for (size_t frameOrdinal = 0; frameOrdinal < m_pausedCallFrames.size(); ++fr ameOrdinal) {
921 const std::unique_ptr<JavaScriptCallFrame>& currentCallFrame = m_pausedC allFrames[frameOrdinal];
922
923 v8::Local<v8::Object> details = currentCallFrame->details();
924 if (hasInternalError(errorString, details.IsEmpty()))
925 return Array<CallFrame>::create();
926
927 int contextId = currentCallFrame->contextId();
928 InjectedScript* injectedScript = contextId ? m_session->findInjectedScri pt(&ignored, contextId) : nullptr;
929
930 String16 callFrameId = RemoteCallFrameId::serialize(contextId, frameOrdi nal);
931 if (hasInternalError(errorString, !details->Set(debuggerContext, toV8Str ingInternalized(m_isolate, "callFrameId"), toV8String(m_isolate, callFrameId)).F romMaybe(false)))
932 return Array<CallFrame>::create();
933
934 if (injectedScript) {
935 v8::Local<v8::Value> scopeChain;
936 if (hasInternalError(errorString, !details->Get(debuggerContext, toV 8StringInternalized(m_isolate, "scopeChain")).ToLocal(&scopeChain) || !scopeChai n->IsArray()))
937 return Array<CallFrame>::create();
938 v8::Local<v8::Array> scopeChainArray = scopeChain.As<v8::Array>();
939 if (!injectedScript->wrapPropertyInArray(errorString, scopeChainArra y, toV8StringInternalized(m_isolate, "object"), backtraceObjectGroup))
940 return Array<CallFrame>::create();
941 if (!injectedScript->wrapObjectProperty(errorString, details, toV8St ringInternalized(m_isolate, "this"), backtraceObjectGroup))
942 return Array<CallFrame>::create();
943 if (details->Has(debuggerContext, toV8StringInternalized(m_isolate, "returnValue")).FromMaybe(false)) {
944 if (!injectedScript->wrapObjectProperty(errorString, details, to V8StringInternalized(m_isolate, "returnValue"), backtraceObjectGroup))
945 return Array<CallFrame>::create();
946 }
947 } else {
948 if (hasInternalError(errorString, !details->Set(debuggerContext, toV 8StringInternalized(m_isolate, "scopeChain"), v8::Array::New(m_isolate, 0)).From Maybe(false)))
949 return Array<CallFrame>::create();
950 v8::Local<v8::Object> remoteObject = v8::Object::New(m_isolate);
951 if (hasInternalError(errorString, !remoteObject->Set(debuggerContext , toV8StringInternalized(m_isolate, "type"), toV8StringInternalized(m_isolate, " undefined")).FromMaybe(false)))
952 return Array<CallFrame>::create();
953 if (hasInternalError(errorString, !details->Set(debuggerContext, toV 8StringInternalized(m_isolate, "this"), remoteObject).FromMaybe(false)))
954 return Array<CallFrame>::create();
955 if (hasInternalError(errorString, !details->Delete(debuggerContext, toV8StringInternalized(m_isolate, "returnValue")).FromMaybe(false)))
956 return Array<CallFrame>::create();
957 }
958
959 if (hasInternalError(errorString, !objects->Set(debuggerContext, frameOr dinal, details).FromMaybe(false)))
960 return Array<CallFrame>::create();
961 }
962
963 protocol::ErrorSupport errorSupport;
964 std::unique_ptr<Array<CallFrame>> callFrames = Array<CallFrame>::parse(toPro tocolValue(debuggerContext, objects).get(), &errorSupport);
965 if (hasInternalError(errorString, !callFrames))
966 return Array<CallFrame>::create();
967 return callFrames;
968 }
969
970 std::unique_ptr<StackTrace> V8DebuggerAgentImpl::currentAsyncStackTrace()
971 {
972 if (m_pausedContext.IsEmpty())
973 return nullptr;
974 V8StackTraceImpl* stackTrace = m_debugger->currentAsyncCallChain();
975 return stackTrace ? stackTrace->buildInspectorObjectForTail(m_debugger) : nu llptr;
976 }
977
978 void V8DebuggerAgentImpl::didParseSource(std::unique_ptr<V8DebuggerScript> scrip t, bool success)
979 {
980 v8::HandleScope handles(m_isolate);
981 String16 scriptSource = toProtocolString(script->source(m_isolate));
982 if (!success)
983 script->setSourceURL(findSourceURL(scriptSource, false));
984 if (!success)
985 script->setSourceMappingURL(findSourceMapURL(scriptSource, false));
986
987 std::unique_ptr<protocol::DictionaryValue> executionContextAuxData;
988 if (!script->executionContextAuxData().isEmpty())
989 executionContextAuxData = protocol::DictionaryValue::cast(protocol::pars eJSON(script->executionContextAuxData()));
990 bool isLiveEdit = script->isLiveEdit();
991 bool hasSourceURL = script->hasSourceURL();
992 String16 scriptId = script->scriptId();
993 String16 scriptURL = script->sourceURL();
994
995 const Maybe<String16>& sourceMapURLParam = script->sourceMappingURL();
996 const Maybe<protocol::DictionaryValue>& executionContextAuxDataParam(std::mo ve(executionContextAuxData));
997 const bool* isLiveEditParam = isLiveEdit ? &isLiveEdit : nullptr;
998 const bool* hasSourceURLParam = hasSourceURL ? &hasSourceURL : nullptr;
999 if (success)
1000 m_frontend.scriptParsed(scriptId, scriptURL, script->startLine(), script ->startColumn(), script->endLine(), script->endColumn(), script->executionContex tId(), script->hash(), executionContextAuxDataParam, isLiveEditParam, sourceMapU RLParam, hasSourceURLParam);
1001 else
1002 m_frontend.scriptFailedToParse(scriptId, scriptURL, script->startLine(), script->startColumn(), script->endLine(), script->endColumn(), script->executio nContextId(), script->hash(), executionContextAuxDataParam, sourceMapURLParam, h asSourceURLParam);
1003
1004 m_scripts[scriptId] = std::move(script);
1005
1006 if (scriptURL.isEmpty() || !success)
1007 return;
1008
1009 protocol::DictionaryValue* breakpointsCookie = m_state->getObject(DebuggerAg entState::javaScriptBreakpoints);
1010 if (!breakpointsCookie)
1011 return;
1012
1013 for (size_t i = 0; i < breakpointsCookie->size(); ++i) {
1014 auto cookie = breakpointsCookie->at(i);
1015 protocol::DictionaryValue* breakpointObject = protocol::DictionaryValue: :cast(cookie.second);
1016 bool isRegex;
1017 breakpointObject->getBoolean(DebuggerAgentState::isRegex, &isRegex);
1018 String16 url;
1019 breakpointObject->getString(DebuggerAgentState::url, &url);
1020 if (!matches(m_inspector, scriptURL, url, isRegex))
1021 continue;
1022 ScriptBreakpoint breakpoint;
1023 breakpointObject->getInteger(DebuggerAgentState::lineNumber, &breakpoint .lineNumber);
1024 breakpointObject->getInteger(DebuggerAgentState::columnNumber, &breakpoi nt.columnNumber);
1025 breakpointObject->getString(DebuggerAgentState::condition, &breakpoint.c ondition);
1026 std::unique_ptr<protocol::Debugger::Location> location = resolveBreakpoi nt(cookie.first, scriptId, breakpoint, UserBreakpointSource);
1027 if (location)
1028 m_frontend.breakpointResolved(cookie.first, std::move(location));
1029 }
1030 }
1031
1032 V8DebuggerAgentImpl::SkipPauseRequest V8DebuggerAgentImpl::didPause(v8::Local<v8 ::Context> context, v8::Local<v8::Value> exception, const std::vector<String16>& hitBreakpoints, bool isPromiseRejection)
1033 {
1034 JavaScriptCallFrames callFrames = m_debugger->currentCallFrames(1);
1035 JavaScriptCallFrame* topCallFrame = !callFrames.empty() ? callFrames.begin() ->get() : nullptr;
1036
1037 V8DebuggerAgentImpl::SkipPauseRequest result;
1038 if (m_skipAllPauses)
1039 result = RequestContinue;
1040 else if (!hitBreakpoints.empty())
1041 result = RequestNoSkip; // Don't skip explicit breakpoints even if set i n frameworks.
1042 else if (!exception.IsEmpty())
1043 result = shouldSkipExceptionPause(topCallFrame);
1044 else if (m_scheduledDebuggerStep != NoStep || m_javaScriptPauseScheduled || m_pausingOnNativeEvent)
1045 result = shouldSkipStepPause(topCallFrame);
1046 else
1047 result = RequestNoSkip;
1048
1049 m_skipNextDebuggerStepOut = false;
1050 if (result != RequestNoSkip)
1051 return result;
1052 // Skip pauses inside V8 internal scripts and on syntax errors.
1053 if (!topCallFrame)
1054 return RequestContinue;
1055
1056 DCHECK(m_pausedContext.IsEmpty());
1057 JavaScriptCallFrames frames = m_debugger->currentCallFrames();
1058 m_pausedCallFrames.swap(frames);
1059 m_pausedContext.Reset(m_isolate, context);
1060 v8::HandleScope handles(m_isolate);
1061
1062 if (!exception.IsEmpty()) {
1063 ErrorString ignored;
1064 InjectedScript* injectedScript = m_session->findInjectedScript(&ignored, V8Debugger::contextId(context));
1065 if (injectedScript) {
1066 m_breakReason = isPromiseRejection ? protocol::Debugger::Paused::Rea sonEnum::PromiseRejection : protocol::Debugger::Paused::ReasonEnum::Exception;
1067 ErrorString errorString;
1068 auto obj = injectedScript->wrapObject(&errorString, exception, backt raceObjectGroup);
1069 m_breakAuxData = obj ? obj->serialize() : nullptr;
1070 // m_breakAuxData might be null after this.
1071 }
1072 }
1073
1074 std::unique_ptr<Array<String16>> hitBreakpointIds = Array<String16>::create( );
1075
1076 for (const auto& point : hitBreakpoints) {
1077 DebugServerBreakpointToBreakpointIdAndSourceMap::iterator breakpointIter ator = m_serverBreakpoints.find(point);
1078 if (breakpointIterator != m_serverBreakpoints.end()) {
1079 const String16& localId = breakpointIterator->second.first;
1080 hitBreakpointIds->addItem(localId);
1081
1082 BreakpointSource source = breakpointIterator->second.second;
1083 if (m_breakReason == protocol::Debugger::Paused::ReasonEnum::Other & & source == DebugCommandBreakpointSource)
1084 m_breakReason = protocol::Debugger::Paused::ReasonEnum::DebugCom mand;
1085 }
1086 }
1087
1088 ErrorString errorString;
1089 m_frontend.paused(currentCallFrames(&errorString), m_breakReason, std::move( m_breakAuxData), std::move(hitBreakpointIds), currentAsyncStackTrace());
1090 m_scheduledDebuggerStep = NoStep;
1091 m_javaScriptPauseScheduled = false;
1092 m_steppingFromFramework = false;
1093 m_pausingOnNativeEvent = false;
1094 m_skippedStepFrameCount = 0;
1095 m_recursionLevelForStepFrame = 0;
1096
1097 if (!m_continueToLocationBreakpointId.isEmpty()) {
1098 m_debugger->removeBreakpoint(m_continueToLocationBreakpointId);
1099 m_continueToLocationBreakpointId = "";
1100 }
1101 return result;
1102 }
1103
1104 void V8DebuggerAgentImpl::didContinue()
1105 {
1106 m_pausedContext.Reset();
1107 JavaScriptCallFrames emptyCallFrames;
1108 m_pausedCallFrames.swap(emptyCallFrames);
1109 clearBreakDetails();
1110 m_frontend.resumed();
1111 }
1112
1113 void V8DebuggerAgentImpl::breakProgram(const String16& breakReason, std::unique_ ptr<protocol::DictionaryValue> data)
1114 {
1115 if (!enabled() || m_skipAllPauses || !m_pausedContext.IsEmpty() || isCurrent CallStackEmptyOrBlackboxed() || !m_debugger->breakpointsActivated())
1116 return;
1117 m_breakReason = breakReason;
1118 m_breakAuxData = std::move(data);
1119 m_scheduledDebuggerStep = NoStep;
1120 m_steppingFromFramework = false;
1121 m_pausingOnNativeEvent = false;
1122 m_debugger->breakProgram();
1123 }
1124
1125 void V8DebuggerAgentImpl::breakProgramOnException(const String16& breakReason, s td::unique_ptr<protocol::DictionaryValue> data)
1126 {
1127 if (!enabled() || m_debugger->getPauseOnExceptionsState() == V8Debugger::Don tPauseOnExceptions)
1128 return;
1129 breakProgram(breakReason, std::move(data));
1130 }
1131
1132 bool V8DebuggerAgentImpl::assertPaused(ErrorString* errorString)
1133 {
1134 if (m_pausedContext.IsEmpty()) {
1135 *errorString = "Can only perform operation while paused.";
1136 return false;
1137 }
1138 return true;
1139 }
1140
1141 void V8DebuggerAgentImpl::clearBreakDetails()
1142 {
1143 m_breakReason = protocol::Debugger::Paused::ReasonEnum::Other;
1144 m_breakAuxData = nullptr;
1145 }
1146
1147 void V8DebuggerAgentImpl::setBreakpointAt(const String16& scriptId, int lineNumb er, int columnNumber, BreakpointSource source, const String16& condition)
1148 {
1149 String16 breakpointId = generateBreakpointId(scriptId, lineNumber, columnNum ber, source);
1150 ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition);
1151 resolveBreakpoint(breakpointId, scriptId, breakpoint, source);
1152 }
1153
1154 void V8DebuggerAgentImpl::removeBreakpointAt(const String16& scriptId, int lineN umber, int columnNumber, BreakpointSource source)
1155 {
1156 removeBreakpoint(generateBreakpointId(scriptId, lineNumber, columnNumber, so urce));
1157 }
1158
1159 void V8DebuggerAgentImpl::reset()
1160 {
1161 if (!enabled())
1162 return;
1163 m_scheduledDebuggerStep = NoStep;
1164 m_scripts.clear();
1165 m_blackboxedPositions.clear();
1166 m_breakpointIdToDebuggerBreakpointIds.clear();
1167 }
1168
1169 } // namespace v8_inspector
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698