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

Side by Side Diff: src/inspector/v8-debugger-agent-impl.cc

Issue 2633803002: [inspector] implemented blackboxing inside v8 (Closed)
Patch Set: addressed comments Created 3 years, 11 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
« no previous file with comments | « src/inspector/v8-debugger-agent-impl.h ('k') | src/inspector/v8-debugger-script.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/inspector/v8-debugger-agent-impl.h" 5 #include "src/inspector/v8-debugger-agent-impl.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "src/debug/debug-interface.h" 9 #include "src/debug/debug-interface.h"
10 #include "src/inspector/injected-script.h" 10 #include "src/inspector/injected-script.h"
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
47 // Breakpoint properties. 47 // Breakpoint properties.
48 static const char url[] = "url"; 48 static const char url[] = "url";
49 static const char isRegex[] = "isRegex"; 49 static const char isRegex[] = "isRegex";
50 static const char lineNumber[] = "lineNumber"; 50 static const char lineNumber[] = "lineNumber";
51 static const char columnNumber[] = "columnNumber"; 51 static const char columnNumber[] = "columnNumber";
52 static const char condition[] = "condition"; 52 static const char condition[] = "condition";
53 static const char skipAllPauses[] = "skipAllPauses"; 53 static const char skipAllPauses[] = "skipAllPauses";
54 54
55 } // namespace DebuggerAgentState 55 } // namespace DebuggerAgentState
56 56
57 static const int kMaxSkipStepFrameCount = 128;
58 static const char kBacktraceObjectGroup[] = "backtrace"; 57 static const char kBacktraceObjectGroup[] = "backtrace";
59 static const char kDebuggerNotEnabled[] = "Debugger agent is not enabled"; 58 static const char kDebuggerNotEnabled[] = "Debugger agent is not enabled";
60 static const char kDebuggerNotPaused[] = 59 static const char kDebuggerNotPaused[] =
61 "Can only perform operation while paused."; 60 "Can only perform operation while paused.";
62 61
63 namespace { 62 namespace {
64 63
65 void TranslateWasmStackTraceLocations(Array<CallFrame>* stackTrace, 64 void TranslateWasmStackTraceLocations(Array<CallFrame>* stackTrace,
66 WasmTranslation* wasmTranslation) { 65 WasmTranslation* wasmTranslation) {
67 for (size_t i = 0, e = stackTrace->length(); i != e; ++i) { 66 for (size_t i = 0, e = stackTrace->length(); i != e; ++i) {
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
127 protocol::DictionaryValue* state) 126 protocol::DictionaryValue* state)
128 : m_inspector(session->inspector()), 127 : m_inspector(session->inspector()),
129 m_debugger(m_inspector->debugger()), 128 m_debugger(m_inspector->debugger()),
130 m_session(session), 129 m_session(session),
131 m_enabled(false), 130 m_enabled(false),
132 m_state(state), 131 m_state(state),
133 m_frontend(frontendChannel), 132 m_frontend(frontendChannel),
134 m_isolate(m_inspector->isolate()), 133 m_isolate(m_inspector->isolate()),
135 m_breakReason(protocol::Debugger::Paused::ReasonEnum::Other), 134 m_breakReason(protocol::Debugger::Paused::ReasonEnum::Other),
136 m_scheduledDebuggerStep(NoStep), 135 m_scheduledDebuggerStep(NoStep),
137 m_skipNextDebuggerStepOut(false),
138 m_javaScriptPauseScheduled(false), 136 m_javaScriptPauseScheduled(false),
139 m_steppingFromFramework(false),
140 m_pausingOnNativeEvent(false),
141 m_skippedStepFrameCount(0),
142 m_recursionLevelForStepOut(0), 137 m_recursionLevelForStepOut(0),
143 m_recursionLevelForStepFrame(0),
144 m_skipAllPauses(false) { 138 m_skipAllPauses(false) {
145 clearBreakDetails(); 139 clearBreakDetails();
146 } 140 }
147 141
148 V8DebuggerAgentImpl::~V8DebuggerAgentImpl() {} 142 V8DebuggerAgentImpl::~V8DebuggerAgentImpl() {}
149 143
150 void V8DebuggerAgentImpl::enableImpl() { 144 void V8DebuggerAgentImpl::enableImpl() {
151 // m_inspector->addListener may result in reporting all parsed scripts to 145 // m_inspector->addListener may result in reporting all parsed scripts to
152 // the agent so it should already be in enabled state by then. 146 // the agent so it should already be in enabled state by then.
153 m_enabled = true; 147 m_enabled = true;
(...skipping 29 matching lines...) Expand all
183 protocol::DictionaryValue::create()); 177 protocol::DictionaryValue::create());
184 m_state->setInteger(DebuggerAgentState::pauseOnExceptionsState, 178 m_state->setInteger(DebuggerAgentState::pauseOnExceptionsState,
185 v8::debug::NoBreakOnException); 179 v8::debug::NoBreakOnException);
186 m_state->setInteger(DebuggerAgentState::asyncCallStackDepth, 0); 180 m_state->setInteger(DebuggerAgentState::asyncCallStackDepth, 0);
187 181
188 if (!m_pausedContext.IsEmpty()) m_debugger->continueProgram(); 182 if (!m_pausedContext.IsEmpty()) m_debugger->continueProgram();
189 m_debugger->disable(); 183 m_debugger->disable();
190 m_pausedContext.Reset(); 184 m_pausedContext.Reset();
191 JavaScriptCallFrames emptyCallFrames; 185 JavaScriptCallFrames emptyCallFrames;
192 m_pausedCallFrames.swap(emptyCallFrames); 186 m_pausedCallFrames.swap(emptyCallFrames);
187 m_blackboxedPositions.clear();
188 m_blackboxPattern.reset();
189 resetBlackboxedStateCache();
193 m_scripts.clear(); 190 m_scripts.clear();
194 m_blackboxedPositions.clear();
195 m_breakpointIdToDebuggerBreakpointIds.clear(); 191 m_breakpointIdToDebuggerBreakpointIds.clear();
196 m_debugger->setAsyncCallStackDepth(this, 0); 192 m_debugger->setAsyncCallStackDepth(this, 0);
197 m_continueToLocationBreakpointId = String16(); 193 m_continueToLocationBreakpointId = String16();
198 clearBreakDetails(); 194 clearBreakDetails();
199 m_scheduledDebuggerStep = NoStep; 195 m_scheduledDebuggerStep = NoStep;
200 m_skipNextDebuggerStepOut = false;
201 m_javaScriptPauseScheduled = false; 196 m_javaScriptPauseScheduled = false;
202 m_steppingFromFramework = false;
203 m_pausingOnNativeEvent = false;
204 m_skippedStepFrameCount = 0;
205 m_recursionLevelForStepFrame = 0;
206 m_skipAllPauses = false; 197 m_skipAllPauses = false;
207 m_blackboxPattern = nullptr;
208 m_state->remove(DebuggerAgentState::blackboxPattern); 198 m_state->remove(DebuggerAgentState::blackboxPattern);
209 m_enabled = false; 199 m_enabled = false;
210 m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false); 200 m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false);
211 return Response::OK(); 201 return Response::OK();
212 } 202 }
213 203
214 void V8DebuggerAgentImpl::restore() { 204 void V8DebuggerAgentImpl::restore() {
215 DCHECK(!m_enabled); 205 DCHECK(!m_enabled);
216 if (!m_state->booleanProperty(DebuggerAgentState::debuggerEnabled, false)) 206 if (!m_state->booleanProperty(DebuggerAgentState::debuggerEnabled, false))
217 return; 207 return;
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after
427 ScriptBreakpoint breakpoint(location->getScriptId(), 417 ScriptBreakpoint breakpoint(location->getScriptId(),
428 location->getLineNumber(), 418 location->getLineNumber(),
429 location->getColumnNumber(0), String16()); 419 location->getColumnNumber(0), String16());
430 420
431 m_continueToLocationBreakpointId = m_debugger->setBreakpoint( 421 m_continueToLocationBreakpointId = m_debugger->setBreakpoint(
432 breakpoint, &breakpoint.line_number, &breakpoint.column_number); 422 breakpoint, &breakpoint.line_number, &breakpoint.column_number);
433 // TODO(kozyatinskiy): Return actual line and column number. 423 // TODO(kozyatinskiy): Return actual line and column number.
434 return resume(); 424 return resume();
435 } 425 }
436 426
437 bool V8DebuggerAgentImpl::isCurrentCallStackEmptyOrBlackboxed() { 427 bool V8DebuggerAgentImpl::isFunctionBlackboxed(const String16& scriptId,
438 DCHECK(enabled()); 428 const v8::debug::Location& start,
439 JavaScriptCallFrames callFrames = m_debugger->currentCallFrames(); 429 const v8::debug::Location& end) {
440 for (size_t index = 0; index < callFrames.size(); ++index) { 430 ScriptsMap::iterator it = m_scripts.find(scriptId);
441 if (!isCallFrameWithUnknownScriptOrBlackboxed(callFrames[index].get()))
442 return false;
443 }
444 return true;
445 }
446
447 bool V8DebuggerAgentImpl::isTopPausedCallFrameBlackboxed() {
448 DCHECK(enabled());
449 JavaScriptCallFrame* frame =
450 m_pausedCallFrames.size() ? m_pausedCallFrames[0].get() : nullptr;
451 return isCallFrameWithUnknownScriptOrBlackboxed(frame);
452 }
453
454 bool V8DebuggerAgentImpl::isCallFrameWithUnknownScriptOrBlackboxed(
455 JavaScriptCallFrame* frame) {
456 if (!frame) return true;
457 ScriptsMap::iterator it =
458 m_scripts.find(String16::fromInteger(frame->sourceID()));
459 if (it == m_scripts.end()) { 431 if (it == m_scripts.end()) {
460 // Unknown scripts are blackboxed. 432 // Unknown scripts are blackboxed.
461 return true; 433 return true;
462 } 434 }
463 if (m_blackboxPattern) { 435 if (m_blackboxPattern) {
464 const String16& scriptSourceURL = it->second->sourceURL(); 436 const String16& scriptSourceURL = it->second->sourceURL();
465 if (!scriptSourceURL.isEmpty() && 437 if (!scriptSourceURL.isEmpty() &&
466 m_blackboxPattern->match(scriptSourceURL) != -1) 438 m_blackboxPattern->match(scriptSourceURL) != -1)
467 return true; 439 return true;
468 } 440 }
469 auto itBlackboxedPositions = 441 auto itBlackboxedPositions = m_blackboxedPositions.find(scriptId);
470 m_blackboxedPositions.find(String16::fromInteger(frame->sourceID()));
471 if (itBlackboxedPositions == m_blackboxedPositions.end()) return false; 442 if (itBlackboxedPositions == m_blackboxedPositions.end()) return false;
472 443
473 const std::vector<std::pair<int, int>>& ranges = 444 const std::vector<std::pair<int, int>>& ranges =
474 itBlackboxedPositions->second; 445 itBlackboxedPositions->second;
475 auto itRange = std::lower_bound( 446 auto itStartRange = std::lower_bound(
476 ranges.begin(), ranges.end(), 447 ranges.begin(), ranges.end(),
477 std::make_pair(frame->line(), frame->column()), positionComparator); 448 std::make_pair(start.GetLineNumber(), start.GetColumnNumber()),
449 positionComparator);
450 auto itEndRange = std::lower_bound(
451 itStartRange, ranges.end(),
452 std::make_pair(end.GetLineNumber(), end.GetColumnNumber()),
453 positionComparator);
478 // Ranges array contains positions in script where blackbox state is changed. 454 // Ranges array contains positions in script where blackbox state is changed.
479 // [(0,0) ... ranges[0]) isn't blackboxed, [ranges[0] ... ranges[1]) is 455 // [(0,0) ... ranges[0]) isn't blackboxed, [ranges[0] ... ranges[1]) is
480 // blackboxed... 456 // blackboxed...
481 return std::distance(ranges.begin(), itRange) % 2; 457 return itStartRange == itEndRange &&
482 } 458 std::distance(ranges.begin(), itStartRange) % 2;
483
484 V8DebuggerAgentImpl::SkipPauseRequest
485 V8DebuggerAgentImpl::shouldSkipExceptionPause(
486 JavaScriptCallFrame* topCallFrame) {
487 if (m_steppingFromFramework) return RequestNoSkip;
488 if (isCallFrameWithUnknownScriptOrBlackboxed(topCallFrame))
489 return RequestContinue;
490 return RequestNoSkip;
491 }
492
493 V8DebuggerAgentImpl::SkipPauseRequest V8DebuggerAgentImpl::shouldSkipStepPause(
494 JavaScriptCallFrame* topCallFrame) {
495 if (m_steppingFromFramework) return RequestNoSkip;
496
497 if (m_skipNextDebuggerStepOut) {
498 m_skipNextDebuggerStepOut = false;
499 if (m_scheduledDebuggerStep == StepOut) return RequestStepOut;
500 }
501
502 if (!isCallFrameWithUnknownScriptOrBlackboxed(topCallFrame))
503 return RequestNoSkip;
504
505 if (m_skippedStepFrameCount >= kMaxSkipStepFrameCount) return RequestStepOut;
506
507 if (!m_skippedStepFrameCount) m_recursionLevelForStepFrame = 1;
508
509 ++m_skippedStepFrameCount;
510 return RequestStepFrame;
511 } 459 }
512 460
513 std::unique_ptr<protocol::Debugger::Location> 461 std::unique_ptr<protocol::Debugger::Location>
514 V8DebuggerAgentImpl::resolveBreakpoint(const String16& breakpointId, 462 V8DebuggerAgentImpl::resolveBreakpoint(const String16& breakpointId,
515 const ScriptBreakpoint& breakpoint, 463 const ScriptBreakpoint& breakpoint,
516 BreakpointSource source) { 464 BreakpointSource source) {
517 v8::HandleScope handles(m_isolate); 465 v8::HandleScope handles(m_isolate);
518 DCHECK(enabled()); 466 DCHECK(enabled());
519 // FIXME: remove these checks once crbug.com/520702 is resolved. 467 // FIXME: remove these checks once crbug.com/520702 is resolved.
520 CHECK(!breakpointId.isEmpty()); 468 CHECK(!breakpointId.isEmpty());
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
634 582
635 void V8DebuggerAgentImpl::schedulePauseOnNextStatement( 583 void V8DebuggerAgentImpl::schedulePauseOnNextStatement(
636 const String16& breakReason, 584 const String16& breakReason,
637 std::unique_ptr<protocol::DictionaryValue> data) { 585 std::unique_ptr<protocol::DictionaryValue> data) {
638 if (!enabled() || m_scheduledDebuggerStep == StepInto || 586 if (!enabled() || m_scheduledDebuggerStep == StepInto ||
639 m_javaScriptPauseScheduled || m_debugger->isPaused() || 587 m_javaScriptPauseScheduled || m_debugger->isPaused() ||
640 !m_debugger->breakpointsActivated()) 588 !m_debugger->breakpointsActivated())
641 return; 589 return;
642 m_breakReason = breakReason; 590 m_breakReason = breakReason;
643 m_breakAuxData = std::move(data); 591 m_breakAuxData = std::move(data);
644 m_pausingOnNativeEvent = true;
645 m_skipNextDebuggerStepOut = false;
646 m_debugger->setPauseOnNextStatement(true); 592 m_debugger->setPauseOnNextStatement(true);
647 } 593 }
648 594
649 void V8DebuggerAgentImpl::schedulePauseOnNextStatementIfSteppingInto() { 595 void V8DebuggerAgentImpl::schedulePauseOnNextStatementIfSteppingInto() {
650 DCHECK(enabled()); 596 DCHECK(enabled());
651 if (m_scheduledDebuggerStep != StepInto || m_javaScriptPauseScheduled || 597 if (m_scheduledDebuggerStep != StepInto || m_javaScriptPauseScheduled ||
652 m_debugger->isPaused()) 598 m_debugger->isPaused())
653 return; 599 return;
654 clearBreakDetails(); 600 clearBreakDetails();
655 m_pausingOnNativeEvent = false;
656 m_skippedStepFrameCount = 0;
657 m_recursionLevelForStepFrame = 0;
658 m_debugger->setPauseOnNextStatement(true); 601 m_debugger->setPauseOnNextStatement(true);
659 } 602 }
660 603
661 void V8DebuggerAgentImpl::cancelPauseOnNextStatement() { 604 void V8DebuggerAgentImpl::cancelPauseOnNextStatement() {
662 if (m_javaScriptPauseScheduled || m_debugger->isPaused()) return; 605 if (m_javaScriptPauseScheduled || m_debugger->isPaused()) return;
663 clearBreakDetails(); 606 clearBreakDetails();
664 m_pausingOnNativeEvent = false;
665 m_debugger->setPauseOnNextStatement(false); 607 m_debugger->setPauseOnNextStatement(false);
666 } 608 }
667 609
668 Response V8DebuggerAgentImpl::pause() { 610 Response V8DebuggerAgentImpl::pause() {
669 if (!enabled()) return Response::Error(kDebuggerNotEnabled); 611 if (!enabled()) return Response::Error(kDebuggerNotEnabled);
670 if (m_javaScriptPauseScheduled || m_debugger->isPaused()) 612 if (m_javaScriptPauseScheduled || m_debugger->isPaused())
671 return Response::OK(); 613 return Response::OK();
672 clearBreakDetails(); 614 clearBreakDetails();
673 m_javaScriptPauseScheduled = true; 615 m_javaScriptPauseScheduled = true;
674 m_scheduledDebuggerStep = NoStep; 616 m_scheduledDebuggerStep = NoStep;
675 m_skippedStepFrameCount = 0;
676 m_steppingFromFramework = false;
677 m_debugger->setPauseOnNextStatement(true); 617 m_debugger->setPauseOnNextStatement(true);
678 return Response::OK(); 618 return Response::OK();
679 } 619 }
680 620
681 Response V8DebuggerAgentImpl::resume() { 621 Response V8DebuggerAgentImpl::resume() {
682 if (m_pausedContext.IsEmpty()) return Response::Error(kDebuggerNotPaused); 622 if (m_pausedContext.IsEmpty()) return Response::Error(kDebuggerNotPaused);
683 m_scheduledDebuggerStep = NoStep; 623 m_scheduledDebuggerStep = NoStep;
684 m_steppingFromFramework = false;
685 m_session->releaseObjectGroup(kBacktraceObjectGroup); 624 m_session->releaseObjectGroup(kBacktraceObjectGroup);
686 m_debugger->continueProgram(); 625 m_debugger->continueProgram();
687 return Response::OK(); 626 return Response::OK();
688 } 627 }
689 628
690 Response V8DebuggerAgentImpl::stepOver() { 629 Response V8DebuggerAgentImpl::stepOver() {
691 if (m_pausedContext.IsEmpty()) return Response::Error(kDebuggerNotPaused); 630 if (m_pausedContext.IsEmpty()) return Response::Error(kDebuggerNotPaused);
692 // StepOver at function return point should fallback to StepInto. 631 // StepOver at function return point should fallback to StepInto.
693 JavaScriptCallFrame* frame = 632 JavaScriptCallFrame* frame =
694 !m_pausedCallFrames.empty() ? m_pausedCallFrames[0].get() : nullptr; 633 !m_pausedCallFrames.empty() ? m_pausedCallFrames[0].get() : nullptr;
695 if (frame && frame->isAtReturn()) return stepInto(); 634 if (frame && frame->isAtReturn()) return stepInto();
696 m_scheduledDebuggerStep = StepOver; 635 m_scheduledDebuggerStep = StepOver;
697 m_steppingFromFramework = isTopPausedCallFrameBlackboxed();
698 m_session->releaseObjectGroup(kBacktraceObjectGroup); 636 m_session->releaseObjectGroup(kBacktraceObjectGroup);
699 m_debugger->stepOverStatement(); 637 m_debugger->stepOverStatement();
700 return Response::OK(); 638 return Response::OK();
701 } 639 }
702 640
703 Response V8DebuggerAgentImpl::stepInto() { 641 Response V8DebuggerAgentImpl::stepInto() {
704 if (m_pausedContext.IsEmpty()) return Response::Error(kDebuggerNotPaused); 642 if (m_pausedContext.IsEmpty()) return Response::Error(kDebuggerNotPaused);
705 m_scheduledDebuggerStep = StepInto; 643 m_scheduledDebuggerStep = StepInto;
706 m_steppingFromFramework = isTopPausedCallFrameBlackboxed();
707 m_session->releaseObjectGroup(kBacktraceObjectGroup); 644 m_session->releaseObjectGroup(kBacktraceObjectGroup);
708 m_debugger->stepIntoStatement(); 645 m_debugger->stepIntoStatement();
709 return Response::OK(); 646 return Response::OK();
710 } 647 }
711 648
712 Response V8DebuggerAgentImpl::stepOut() { 649 Response V8DebuggerAgentImpl::stepOut() {
713 if (m_pausedContext.IsEmpty()) return Response::Error(kDebuggerNotPaused); 650 if (m_pausedContext.IsEmpty()) return Response::Error(kDebuggerNotPaused);
714 m_scheduledDebuggerStep = StepOut; 651 m_scheduledDebuggerStep = StepOut;
715 m_skipNextDebuggerStepOut = false;
716 m_recursionLevelForStepOut = 1; 652 m_recursionLevelForStepOut = 1;
717 m_steppingFromFramework = isTopPausedCallFrameBlackboxed();
718 m_session->releaseObjectGroup(kBacktraceObjectGroup); 653 m_session->releaseObjectGroup(kBacktraceObjectGroup);
719 m_debugger->stepOutOfFunction(); 654 m_debugger->stepOutOfFunction();
720 return Response::OK(); 655 return Response::OK();
721 } 656 }
722 657
723 Response V8DebuggerAgentImpl::setPauseOnExceptions( 658 Response V8DebuggerAgentImpl::setPauseOnExceptions(
724 const String16& stringPauseState) { 659 const String16& stringPauseState) {
725 if (!enabled()) return Response::Error(kDebuggerNotEnabled); 660 if (!enabled()) return Response::Error(kDebuggerNotEnabled);
726 v8::debug::ExceptionBreakState pauseState; 661 v8::debug::ExceptionBreakState pauseState;
727 if (stringPauseState == "none") { 662 if (stringPauseState == "none") {
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
804 if (!enabled()) return Response::Error(kDebuggerNotEnabled); 739 if (!enabled()) return Response::Error(kDebuggerNotEnabled);
805 m_state->setInteger(DebuggerAgentState::asyncCallStackDepth, depth); 740 m_state->setInteger(DebuggerAgentState::asyncCallStackDepth, depth);
806 m_debugger->setAsyncCallStackDepth(this, depth); 741 m_debugger->setAsyncCallStackDepth(this, depth);
807 return Response::OK(); 742 return Response::OK();
808 } 743 }
809 744
810 Response V8DebuggerAgentImpl::setBlackboxPatterns( 745 Response V8DebuggerAgentImpl::setBlackboxPatterns(
811 std::unique_ptr<protocol::Array<String16>> patterns) { 746 std::unique_ptr<protocol::Array<String16>> patterns) {
812 if (!patterns->length()) { 747 if (!patterns->length()) {
813 m_blackboxPattern = nullptr; 748 m_blackboxPattern = nullptr;
749 resetBlackboxedStateCache();
814 m_state->remove(DebuggerAgentState::blackboxPattern); 750 m_state->remove(DebuggerAgentState::blackboxPattern);
815 return Response::OK(); 751 return Response::OK();
816 } 752 }
817 753
818 String16Builder patternBuilder; 754 String16Builder patternBuilder;
819 patternBuilder.append('('); 755 patternBuilder.append('(');
820 for (size_t i = 0; i < patterns->length() - 1; ++i) { 756 for (size_t i = 0; i < patterns->length() - 1; ++i) {
821 patternBuilder.append(patterns->get(i)); 757 patternBuilder.append(patterns->get(i));
822 patternBuilder.append("|"); 758 patternBuilder.append("|");
823 } 759 }
824 patternBuilder.append(patterns->get(patterns->length() - 1)); 760 patternBuilder.append(patterns->get(patterns->length() - 1));
825 patternBuilder.append(')'); 761 patternBuilder.append(')');
826 String16 pattern = patternBuilder.toString(); 762 String16 pattern = patternBuilder.toString();
827 Response response = setBlackboxPattern(pattern); 763 Response response = setBlackboxPattern(pattern);
828 if (!response.isSuccess()) return response; 764 if (!response.isSuccess()) return response;
765 resetBlackboxedStateCache();
829 m_state->setString(DebuggerAgentState::blackboxPattern, pattern); 766 m_state->setString(DebuggerAgentState::blackboxPattern, pattern);
830 return Response::OK(); 767 return Response::OK();
831 } 768 }
832 769
833 Response V8DebuggerAgentImpl::setBlackboxPattern(const String16& pattern) { 770 Response V8DebuggerAgentImpl::setBlackboxPattern(const String16& pattern) {
834 std::unique_ptr<V8Regex> regex(new V8Regex( 771 std::unique_ptr<V8Regex> regex(new V8Regex(
835 m_inspector, pattern, true /** caseSensitive */, false /** multiline */)); 772 m_inspector, pattern, true /** caseSensitive */, false /** multiline */));
836 if (!regex->isValid()) 773 if (!regex->isValid())
837 return Response::Error("Pattern parser error: " + regex->errorMessage()); 774 return Response::Error("Pattern parser error: " + regex->errorMessage());
838 m_blackboxPattern = std::move(regex); 775 m_blackboxPattern = std::move(regex);
839 return Response::OK(); 776 return Response::OK();
840 } 777 }
841 778
779 void V8DebuggerAgentImpl::resetBlackboxedStateCache() {
780 for (const auto& it : m_scripts) {
781 it.second->resetBlackboxedStateCache();
782 }
783 }
784
842 Response V8DebuggerAgentImpl::setBlackboxedRanges( 785 Response V8DebuggerAgentImpl::setBlackboxedRanges(
843 const String16& scriptId, 786 const String16& scriptId,
844 std::unique_ptr<protocol::Array<protocol::Debugger::ScriptPosition>> 787 std::unique_ptr<protocol::Array<protocol::Debugger::ScriptPosition>>
845 inPositions) { 788 inPositions) {
846 if (m_scripts.find(scriptId) == m_scripts.end()) 789 auto it = m_scripts.find(scriptId);
790 if (it == m_scripts.end())
847 return Response::Error("No script with passed id."); 791 return Response::Error("No script with passed id.");
848 792
849 if (!inPositions->length()) { 793 if (!inPositions->length()) {
850 m_blackboxedPositions.erase(scriptId); 794 m_blackboxedPositions.erase(scriptId);
795 it->second->resetBlackboxedStateCache();
851 return Response::OK(); 796 return Response::OK();
852 } 797 }
853 798
854 std::vector<std::pair<int, int>> positions; 799 std::vector<std::pair<int, int>> positions;
855 positions.reserve(inPositions->length()); 800 positions.reserve(inPositions->length());
856 for (size_t i = 0; i < inPositions->length(); ++i) { 801 for (size_t i = 0; i < inPositions->length(); ++i) {
857 protocol::Debugger::ScriptPosition* position = inPositions->get(i); 802 protocol::Debugger::ScriptPosition* position = inPositions->get(i);
858 if (position->getLineNumber() < 0) 803 if (position->getLineNumber() < 0)
859 return Response::Error("Position missing 'line' or 'line' < 0."); 804 return Response::Error("Position missing 'line' or 'line' < 0.");
860 if (position->getColumnNumber() < 0) 805 if (position->getColumnNumber() < 0)
861 return Response::Error("Position missing 'column' or 'column' < 0."); 806 return Response::Error("Position missing 'column' or 'column' < 0.");
862 positions.push_back( 807 positions.push_back(
863 std::make_pair(position->getLineNumber(), position->getColumnNumber())); 808 std::make_pair(position->getLineNumber(), position->getColumnNumber()));
864 } 809 }
865 810
866 for (size_t i = 1; i < positions.size(); ++i) { 811 for (size_t i = 1; i < positions.size(); ++i) {
867 if (positions[i - 1].first < positions[i].first) continue; 812 if (positions[i - 1].first < positions[i].first) continue;
868 if (positions[i - 1].first == positions[i].first && 813 if (positions[i - 1].first == positions[i].first &&
869 positions[i - 1].second < positions[i].second) 814 positions[i - 1].second < positions[i].second)
870 continue; 815 continue;
871 return Response::Error( 816 return Response::Error(
872 "Input positions array is not sorted or contains duplicate values."); 817 "Input positions array is not sorted or contains duplicate values.");
873 } 818 }
874 819
875 m_blackboxedPositions[scriptId] = positions; 820 m_blackboxedPositions[scriptId] = positions;
821 it->second->resetBlackboxedStateCache();
876 return Response::OK(); 822 return Response::OK();
877 } 823 }
878 824
879 void V8DebuggerAgentImpl::willExecuteScript(int scriptId) { 825 void V8DebuggerAgentImpl::willExecuteScript(int scriptId) {
880 changeJavaScriptRecursionLevel(+1); 826 changeJavaScriptRecursionLevel(+1);
881 // Fast return. 827 // Fast return.
882 if (m_scheduledDebuggerStep != StepInto) return; 828 if (m_scheduledDebuggerStep != StepInto) return;
883 schedulePauseOnNextStatementIfSteppingInto(); 829 schedulePauseOnNextStatementIfSteppingInto();
884 } 830 }
885 831
886 void V8DebuggerAgentImpl::didExecuteScript() { 832 void V8DebuggerAgentImpl::didExecuteScript() {
887 changeJavaScriptRecursionLevel(-1); 833 changeJavaScriptRecursionLevel(-1);
888 } 834 }
889 835
890 void V8DebuggerAgentImpl::changeJavaScriptRecursionLevel(int step) { 836 void V8DebuggerAgentImpl::changeJavaScriptRecursionLevel(int step) {
891 if (m_javaScriptPauseScheduled && !m_skipAllPauses && 837 if (m_javaScriptPauseScheduled && !m_skipAllPauses &&
892 !m_debugger->isPaused()) { 838 !m_debugger->isPaused()) {
893 // Do not ever loose user's pause request until we have actually paused. 839 // Do not ever loose user's pause request until we have actually paused.
894 m_debugger->setPauseOnNextStatement(true); 840 m_debugger->setPauseOnNextStatement(true);
895 } 841 }
896 if (m_scheduledDebuggerStep == StepOut) { 842 if (m_scheduledDebuggerStep == StepOut) {
897 m_recursionLevelForStepOut += step; 843 m_recursionLevelForStepOut += step;
898 if (!m_recursionLevelForStepOut) { 844 if (!m_recursionLevelForStepOut) {
899 // When StepOut crosses a task boundary (i.e. js -> c++) from where it was 845 // When StepOut crosses a task boundary (i.e. js -> c++) from where it was
900 // requested, 846 // requested,
901 // switch stepping to step into a next JS task, as if we exited to a 847 // switch stepping to step into a next JS task, as if we exited to a
902 // blackboxed framework. 848 // blackboxed framework.
903 m_scheduledDebuggerStep = StepInto; 849 m_scheduledDebuggerStep = StepInto;
904 m_skipNextDebuggerStepOut = false;
905 }
906 }
907 if (m_recursionLevelForStepFrame) {
908 m_recursionLevelForStepFrame += step;
909 if (!m_recursionLevelForStepFrame) {
910 // We have walked through a blackboxed framework and got back to where we
911 // started.
912 // If there was no stepping scheduled, we should cancel the stepping
913 // explicitly,
914 // since there may be a scheduled StepFrame left.
915 // Otherwise, if we were stepping in/over, the StepFrame will stop at the
916 // right location,
917 // whereas if we were stepping out, we should continue doing so after
918 // debugger pauses
919 // from the old StepFrame.
920 m_skippedStepFrameCount = 0;
921 if (m_scheduledDebuggerStep == NoStep)
922 m_debugger->clearStepping();
923 else if (m_scheduledDebuggerStep == StepOut)
924 m_skipNextDebuggerStepOut = true;
925 } 850 }
926 } 851 }
927 } 852 }
928 853
929 Response V8DebuggerAgentImpl::currentCallFrames( 854 Response V8DebuggerAgentImpl::currentCallFrames(
930 std::unique_ptr<Array<CallFrame>>* result) { 855 std::unique_ptr<Array<CallFrame>>* result) {
931 if (m_pausedContext.IsEmpty() || !m_pausedCallFrames.size()) { 856 if (m_pausedContext.IsEmpty() || !m_pausedCallFrames.size()) {
932 *result = Array<CallFrame>::create(); 857 *result = Array<CallFrame>::create();
933 return Response::OK(); 858 return Response::OK();
934 } 859 }
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
1065 bool isLiveEdit = script->isLiveEdit(); 990 bool isLiveEdit = script->isLiveEdit();
1066 bool hasSourceURL = script->hasSourceURL(); 991 bool hasSourceURL = script->hasSourceURL();
1067 String16 scriptId = script->scriptId(); 992 String16 scriptId = script->scriptId();
1068 String16 scriptURL = script->sourceURL(); 993 String16 scriptURL = script->sourceURL();
1069 994
1070 m_scripts[scriptId] = std::move(script); 995 m_scripts[scriptId] = std::move(script);
1071 996
1072 ScriptsMap::iterator scriptIterator = m_scripts.find(scriptId); 997 ScriptsMap::iterator scriptIterator = m_scripts.find(scriptId);
1073 DCHECK(scriptIterator != m_scripts.end()); 998 DCHECK(scriptIterator != m_scripts.end());
1074 V8DebuggerScript* scriptRef = scriptIterator->second.get(); 999 V8DebuggerScript* scriptRef = scriptIterator->second.get();
1000 // V8 could create functions for parsed scripts before reporting and asks
1001 // inspector about blackboxed state, we should reset state each time when we
1002 // make any change that change isFunctionBlackboxed output - adding parsed
1003 // script is changing.
1004 scriptRef->resetBlackboxedStateCache();
1075 1005
1076 Maybe<String16> sourceMapURLParam = scriptRef->sourceMappingURL(); 1006 Maybe<String16> sourceMapURLParam = scriptRef->sourceMappingURL();
1077 Maybe<protocol::DictionaryValue> executionContextAuxDataParam( 1007 Maybe<protocol::DictionaryValue> executionContextAuxDataParam(
1078 std::move(executionContextAuxData)); 1008 std::move(executionContextAuxData));
1079 const bool* isLiveEditParam = isLiveEdit ? &isLiveEdit : nullptr; 1009 const bool* isLiveEditParam = isLiveEdit ? &isLiveEdit : nullptr;
1080 const bool* hasSourceURLParam = hasSourceURL ? &hasSourceURL : nullptr; 1010 const bool* hasSourceURLParam = hasSourceURL ? &hasSourceURL : nullptr;
1081 if (success) 1011 if (success)
1082 m_frontend.scriptParsed( 1012 m_frontend.scriptParsed(
1083 scriptId, scriptURL, scriptRef->startLine(), scriptRef->startColumn(), 1013 scriptId, scriptURL, scriptRef->startLine(), scriptRef->startColumn(),
1084 scriptRef->endLine(), scriptRef->endColumn(), contextId, 1014 scriptRef->endLine(), scriptRef->endColumn(), contextId,
(...skipping 29 matching lines...) Expand all
1114 &breakpoint.column_number); 1044 &breakpoint.column_number);
1115 breakpointObject->getString(DebuggerAgentState::condition, 1045 breakpointObject->getString(DebuggerAgentState::condition,
1116 &breakpoint.condition); 1046 &breakpoint.condition);
1117 std::unique_ptr<protocol::Debugger::Location> location = 1047 std::unique_ptr<protocol::Debugger::Location> location =
1118 resolveBreakpoint(cookie.first, breakpoint, UserBreakpointSource); 1048 resolveBreakpoint(cookie.first, breakpoint, UserBreakpointSource);
1119 if (location) 1049 if (location)
1120 m_frontend.breakpointResolved(cookie.first, std::move(location)); 1050 m_frontend.breakpointResolved(cookie.first, std::move(location));
1121 } 1051 }
1122 } 1052 }
1123 1053
1124 V8DebuggerAgentImpl::SkipPauseRequest V8DebuggerAgentImpl::didPause( 1054 bool V8DebuggerAgentImpl::didPause(v8::Local<v8::Context> context,
1125 v8::Local<v8::Context> context, v8::Local<v8::Value> exception, 1055 v8::Local<v8::Value> exception,
1126 const std::vector<String16>& hitBreakpoints, bool isPromiseRejection, 1056 const std::vector<String16>& hitBreakpoints,
1127 bool isUncaught, bool isOOMBreak) { 1057 bool isPromiseRejection, bool isUncaught,
1128 JavaScriptCallFrames callFrames = m_debugger->currentCallFrames(1); 1058 bool isOOMBreak) {
1129 JavaScriptCallFrame* topCallFrame = 1059 if (!isOOMBreak) {
1130 !callFrames.empty() ? callFrames.begin()->get() : nullptr; 1060 if (m_skipAllPauses) return false;
1131 1061 JavaScriptCallFrames callFrames = m_debugger->currentCallFrames(1);
1132 V8DebuggerAgentImpl::SkipPauseRequest result; 1062 JavaScriptCallFrame* topCallFrame =
1133 if (isOOMBreak) 1063 !callFrames.empty() ? callFrames.begin()->get() : nullptr;
1134 result = RequestNoSkip; 1064 // Skip pauses inside V8 internal scripts and on syntax errors.
1135 else if (m_skipAllPauses) 1065 if (!topCallFrame) return false;
1136 result = RequestContinue; 1066 }
1137 else if (!hitBreakpoints.empty())
1138 result = RequestNoSkip; // Don't skip explicit breakpoints even if set in
1139 // frameworks.
1140 else if (!exception.IsEmpty())
1141 result = shouldSkipExceptionPause(topCallFrame);
1142 else if (m_scheduledDebuggerStep != NoStep || m_javaScriptPauseScheduled ||
1143 m_pausingOnNativeEvent)
1144 result = shouldSkipStepPause(topCallFrame);
1145 else
1146 result = RequestNoSkip;
1147
1148 m_skipNextDebuggerStepOut = false;
1149 if (result != RequestNoSkip) return result;
1150 // Skip pauses inside V8 internal scripts and on syntax errors.
1151 if (!topCallFrame) return RequestContinue;
1152
1153 DCHECK(m_pausedContext.IsEmpty()); 1067 DCHECK(m_pausedContext.IsEmpty());
1154 JavaScriptCallFrames frames = m_debugger->currentCallFrames(); 1068 JavaScriptCallFrames frames = m_debugger->currentCallFrames();
1155 m_pausedCallFrames.swap(frames); 1069 m_pausedCallFrames.swap(frames);
1156 m_pausedContext.Reset(m_isolate, context); 1070 m_pausedContext.Reset(m_isolate, context);
1157 v8::HandleScope handles(m_isolate); 1071 v8::HandleScope handles(m_isolate);
1158 1072
1159 if (isOOMBreak) { 1073 if (isOOMBreak) {
1160 m_breakReason = protocol::Debugger::Paused::ReasonEnum::OOM; 1074 m_breakReason = protocol::Debugger::Paused::ReasonEnum::OOM;
1161 m_breakAuxData = nullptr; 1075 m_breakAuxData = nullptr;
1162 } else if (!exception.IsEmpty()) { 1076 } else if (!exception.IsEmpty()) {
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1198 } 1112 }
1199 1113
1200 std::unique_ptr<Array<CallFrame>> protocolCallFrames; 1114 std::unique_ptr<Array<CallFrame>> protocolCallFrames;
1201 Response response = currentCallFrames(&protocolCallFrames); 1115 Response response = currentCallFrames(&protocolCallFrames);
1202 if (!response.isSuccess()) protocolCallFrames = Array<CallFrame>::create(); 1116 if (!response.isSuccess()) protocolCallFrames = Array<CallFrame>::create();
1203 m_frontend.paused(std::move(protocolCallFrames), m_breakReason, 1117 m_frontend.paused(std::move(protocolCallFrames), m_breakReason,
1204 std::move(m_breakAuxData), std::move(hitBreakpointIds), 1118 std::move(m_breakAuxData), std::move(hitBreakpointIds),
1205 currentAsyncStackTrace()); 1119 currentAsyncStackTrace());
1206 m_scheduledDebuggerStep = NoStep; 1120 m_scheduledDebuggerStep = NoStep;
1207 m_javaScriptPauseScheduled = false; 1121 m_javaScriptPauseScheduled = false;
1208 m_steppingFromFramework = false;
1209 m_pausingOnNativeEvent = false;
1210 m_skippedStepFrameCount = 0;
1211 m_recursionLevelForStepFrame = 0;
1212 1122
1213 if (!m_continueToLocationBreakpointId.isEmpty()) { 1123 if (!m_continueToLocationBreakpointId.isEmpty()) {
1214 m_debugger->removeBreakpoint(m_continueToLocationBreakpointId); 1124 m_debugger->removeBreakpoint(m_continueToLocationBreakpointId);
1215 m_continueToLocationBreakpointId = ""; 1125 m_continueToLocationBreakpointId = "";
1216 } 1126 }
1217 return result; 1127 return true;
1218 } 1128 }
1219 1129
1220 void V8DebuggerAgentImpl::didContinue() { 1130 void V8DebuggerAgentImpl::didContinue() {
1221 m_pausedContext.Reset(); 1131 m_pausedContext.Reset();
1222 JavaScriptCallFrames emptyCallFrames; 1132 JavaScriptCallFrames emptyCallFrames;
1223 m_pausedCallFrames.swap(emptyCallFrames); 1133 m_pausedCallFrames.swap(emptyCallFrames);
1224 clearBreakDetails(); 1134 clearBreakDetails();
1225 m_frontend.resumed(); 1135 m_frontend.resumed();
1226 } 1136 }
1227 1137
1228 void V8DebuggerAgentImpl::breakProgram( 1138 void V8DebuggerAgentImpl::breakProgram(
1229 const String16& breakReason, 1139 const String16& breakReason,
1230 std::unique_ptr<protocol::DictionaryValue> data) { 1140 std::unique_ptr<protocol::DictionaryValue> data) {
1231 if (!enabled() || m_skipAllPauses || !m_pausedContext.IsEmpty() || 1141 if (!enabled() || m_skipAllPauses || !m_pausedContext.IsEmpty() ||
1232 isCurrentCallStackEmptyOrBlackboxed() || 1142 !m_debugger->canBreakProgram())
1233 !m_debugger->breakpointsActivated())
1234 return; 1143 return;
1235 m_breakReason = breakReason; 1144 m_breakReason = breakReason;
1236 m_breakAuxData = std::move(data); 1145 m_breakAuxData = std::move(data);
1237 m_scheduledDebuggerStep = NoStep; 1146 m_scheduledDebuggerStep = NoStep;
1238 m_steppingFromFramework = false;
1239 m_pausingOnNativeEvent = false;
1240 m_debugger->breakProgram(); 1147 m_debugger->breakProgram();
1241 } 1148 }
1242 1149
1243 void V8DebuggerAgentImpl::breakProgramOnException( 1150 void V8DebuggerAgentImpl::breakProgramOnException(
1244 const String16& breakReason, 1151 const String16& breakReason,
1245 std::unique_ptr<protocol::DictionaryValue> data) { 1152 std::unique_ptr<protocol::DictionaryValue> data) {
1246 if (!enabled() || 1153 if (!enabled() ||
1247 m_debugger->getPauseOnExceptionsState() == v8::debug::NoBreakOnException) 1154 m_debugger->getPauseOnExceptionsState() == v8::debug::NoBreakOnException)
1248 return; 1155 return;
1249 breakProgram(breakReason, std::move(data)); 1156 breakProgram(breakReason, std::move(data));
(...skipping 17 matching lines...) Expand all
1267 int lineNumber, int columnNumber, 1174 int lineNumber, int columnNumber,
1268 BreakpointSource source) { 1175 BreakpointSource source) {
1269 removeBreakpointImpl(generateBreakpointId( 1176 removeBreakpointImpl(generateBreakpointId(
1270 ScriptBreakpoint(scriptId, lineNumber, columnNumber, String16()), 1177 ScriptBreakpoint(scriptId, lineNumber, columnNumber, String16()),
1271 source)); 1178 source));
1272 } 1179 }
1273 1180
1274 void V8DebuggerAgentImpl::reset() { 1181 void V8DebuggerAgentImpl::reset() {
1275 if (!enabled()) return; 1182 if (!enabled()) return;
1276 m_scheduledDebuggerStep = NoStep; 1183 m_scheduledDebuggerStep = NoStep;
1184 m_blackboxedPositions.clear();
1185 resetBlackboxedStateCache();
1277 m_scripts.clear(); 1186 m_scripts.clear();
1278 m_blackboxedPositions.clear();
1279 m_breakpointIdToDebuggerBreakpointIds.clear(); 1187 m_breakpointIdToDebuggerBreakpointIds.clear();
1280 } 1188 }
1281 1189
1282 } // namespace v8_inspector 1190 } // namespace v8_inspector
OLDNEW
« no previous file with comments | « src/inspector/v8-debugger-agent-impl.h ('k') | src/inspector/v8-debugger-script.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698