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

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

Issue 2633803002: [inspector] implemented blackboxing inside v8 (Closed)
Patch Set: rebased 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
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_blackboxPattern = nullptr;
188 m_blackboxedPositions.clear();
189 for (const auto& it : m_scripts) {
190 it.second->blackboxStateChanged();
191 }
193 m_scripts.clear(); 192 m_scripts.clear();
194 m_blackboxedPositions.clear();
195 m_breakpointIdToDebuggerBreakpointIds.clear(); 193 m_breakpointIdToDebuggerBreakpointIds.clear();
196 m_debugger->setAsyncCallStackDepth(this, 0); 194 m_debugger->setAsyncCallStackDepth(this, 0);
197 m_continueToLocationBreakpointId = String16(); 195 m_continueToLocationBreakpointId = String16();
198 clearBreakDetails(); 196 clearBreakDetails();
199 m_scheduledDebuggerStep = NoStep; 197 m_scheduledDebuggerStep = NoStep;
200 m_skipNextDebuggerStepOut = false;
201 m_javaScriptPauseScheduled = false; 198 m_javaScriptPauseScheduled = false;
202 m_steppingFromFramework = false;
203 m_pausingOnNativeEvent = false;
204 m_skippedStepFrameCount = 0;
205 m_recursionLevelForStepFrame = 0;
206 m_skipAllPauses = false; 199 m_skipAllPauses = false;
207 m_blackboxPattern = nullptr;
208 m_state->remove(DebuggerAgentState::blackboxPattern); 200 m_state->remove(DebuggerAgentState::blackboxPattern);
209 m_enabled = false; 201 m_enabled = false;
210 m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false); 202 m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false);
211 return Response::OK(); 203 return Response::OK();
212 } 204 }
213 205
214 void V8DebuggerAgentImpl::restore() { 206 void V8DebuggerAgentImpl::restore() {
215 DCHECK(!m_enabled); 207 DCHECK(!m_enabled);
216 if (!m_state->booleanProperty(DebuggerAgentState::debuggerEnabled, false)) 208 if (!m_state->booleanProperty(DebuggerAgentState::debuggerEnabled, false))
217 return; 209 return;
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after
427 ScriptBreakpoint breakpoint(location->getScriptId(), 419 ScriptBreakpoint breakpoint(location->getScriptId(),
428 location->getLineNumber(), 420 location->getLineNumber(),
429 location->getColumnNumber(0), String16()); 421 location->getColumnNumber(0), String16());
430 422
431 m_continueToLocationBreakpointId = m_debugger->setBreakpoint( 423 m_continueToLocationBreakpointId = m_debugger->setBreakpoint(
432 breakpoint, &breakpoint.line_number, &breakpoint.column_number); 424 breakpoint, &breakpoint.line_number, &breakpoint.column_number);
433 // TODO(kozyatinskiy): Return actual line and column number. 425 // TODO(kozyatinskiy): Return actual line and column number.
434 return resume(); 426 return resume();
435 } 427 }
436 428
437 bool V8DebuggerAgentImpl::isCurrentCallStackEmptyOrBlackboxed() { 429 bool V8DebuggerAgentImpl::isBlackboxed(const String16& scriptId,
438 DCHECK(enabled()); 430 const v8::debug::Location& start,
439 JavaScriptCallFrames callFrames = m_debugger->currentCallFrames(); 431 const v8::debug::Location& end) {
440 for (size_t index = 0; index < callFrames.size(); ++index) { 432 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()) { 433 if (it == m_scripts.end()) {
460 // Unknown scripts are blackboxed. 434 // Unknown scripts are blackboxed.
461 return true; 435 return true;
462 } 436 }
463 if (m_blackboxPattern) { 437 if (m_blackboxPattern) {
464 const String16& scriptSourceURL = it->second->sourceURL(); 438 const String16& scriptSourceURL = it->second->sourceURL();
465 if (!scriptSourceURL.isEmpty() && 439 if (!scriptSourceURL.isEmpty() &&
466 m_blackboxPattern->match(scriptSourceURL) != -1) 440 m_blackboxPattern->match(scriptSourceURL) != -1)
467 return true; 441 return true;
468 } 442 }
469 auto itBlackboxedPositions = 443 auto itBlackboxedPositions = m_blackboxedPositions.find(scriptId);
470 m_blackboxedPositions.find(String16::fromInteger(frame->sourceID()));
471 if (itBlackboxedPositions == m_blackboxedPositions.end()) return false; 444 if (itBlackboxedPositions == m_blackboxedPositions.end()) return false;
472 445
473 const std::vector<std::pair<int, int>>& ranges = 446 const std::vector<std::pair<int, int>>& ranges =
474 itBlackboxedPositions->second; 447 itBlackboxedPositions->second;
475 auto itRange = std::lower_bound( 448 auto itRange = std::lower_bound(
476 ranges.begin(), ranges.end(), 449 ranges.begin(), ranges.end(),
477 std::make_pair(frame->line(), frame->column()), positionComparator); 450 std::make_pair(start.GetLineNumber(), start.GetColumnNumber()),
451 positionComparator);
478 // Ranges array contains positions in script where blackbox state is changed. 452 // Ranges array contains positions in script where blackbox state is changed.
479 // [(0,0) ... ranges[0]) isn't blackboxed, [ranges[0] ... ranges[1]) is 453 // [(0,0) ... ranges[0]) isn't blackboxed, [ranges[0] ... ranges[1]) is
480 // blackboxed... 454 // blackboxed...
481 return std::distance(ranges.begin(), itRange) % 2; 455 return std::distance(ranges.begin(), itRange) % 2;
482 } 456 }
483 457
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 }
512
513 std::unique_ptr<protocol::Debugger::Location> 458 std::unique_ptr<protocol::Debugger::Location>
514 V8DebuggerAgentImpl::resolveBreakpoint(const String16& breakpointId, 459 V8DebuggerAgentImpl::resolveBreakpoint(const String16& breakpointId,
515 const ScriptBreakpoint& breakpoint, 460 const ScriptBreakpoint& breakpoint,
516 BreakpointSource source) { 461 BreakpointSource source) {
517 v8::HandleScope handles(m_isolate); 462 v8::HandleScope handles(m_isolate);
518 DCHECK(enabled()); 463 DCHECK(enabled());
519 // FIXME: remove these checks once crbug.com/520702 is resolved. 464 // FIXME: remove these checks once crbug.com/520702 is resolved.
520 CHECK(!breakpointId.isEmpty()); 465 CHECK(!breakpointId.isEmpty());
521 CHECK(!breakpoint.script_id.isEmpty()); 466 CHECK(!breakpoint.script_id.isEmpty());
522 ScriptsMap::iterator scriptIterator = m_scripts.find(breakpoint.script_id); 467 ScriptsMap::iterator scriptIterator = m_scripts.find(breakpoint.script_id);
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
634 579
635 void V8DebuggerAgentImpl::schedulePauseOnNextStatement( 580 void V8DebuggerAgentImpl::schedulePauseOnNextStatement(
636 const String16& breakReason, 581 const String16& breakReason,
637 std::unique_ptr<protocol::DictionaryValue> data) { 582 std::unique_ptr<protocol::DictionaryValue> data) {
638 if (!enabled() || m_scheduledDebuggerStep == StepInto || 583 if (!enabled() || m_scheduledDebuggerStep == StepInto ||
639 m_javaScriptPauseScheduled || m_debugger->isPaused() || 584 m_javaScriptPauseScheduled || m_debugger->isPaused() ||
640 !m_debugger->breakpointsActivated()) 585 !m_debugger->breakpointsActivated())
641 return; 586 return;
642 m_breakReason = breakReason; 587 m_breakReason = breakReason;
643 m_breakAuxData = std::move(data); 588 m_breakAuxData = std::move(data);
644 m_pausingOnNativeEvent = true;
645 m_skipNextDebuggerStepOut = false;
646 m_debugger->setPauseOnNextStatement(true); 589 m_debugger->setPauseOnNextStatement(true);
647 } 590 }
648 591
649 void V8DebuggerAgentImpl::schedulePauseOnNextStatementIfSteppingInto() { 592 void V8DebuggerAgentImpl::schedulePauseOnNextStatementIfSteppingInto() {
650 DCHECK(enabled()); 593 DCHECK(enabled());
651 if (m_scheduledDebuggerStep != StepInto || m_javaScriptPauseScheduled || 594 if (m_scheduledDebuggerStep != StepInto || m_javaScriptPauseScheduled ||
652 m_debugger->isPaused()) 595 m_debugger->isPaused())
653 return; 596 return;
654 clearBreakDetails(); 597 clearBreakDetails();
655 m_pausingOnNativeEvent = false;
656 m_skippedStepFrameCount = 0;
657 m_recursionLevelForStepFrame = 0;
658 m_debugger->setPauseOnNextStatement(true); 598 m_debugger->setPauseOnNextStatement(true);
659 } 599 }
660 600
661 void V8DebuggerAgentImpl::cancelPauseOnNextStatement() { 601 void V8DebuggerAgentImpl::cancelPauseOnNextStatement() {
662 if (m_javaScriptPauseScheduled || m_debugger->isPaused()) return; 602 if (m_javaScriptPauseScheduled || m_debugger->isPaused()) return;
663 clearBreakDetails(); 603 clearBreakDetails();
664 m_pausingOnNativeEvent = false;
665 m_debugger->setPauseOnNextStatement(false); 604 m_debugger->setPauseOnNextStatement(false);
666 } 605 }
667 606
668 Response V8DebuggerAgentImpl::pause() { 607 Response V8DebuggerAgentImpl::pause() {
669 if (!enabled()) return Response::Error(kDebuggerNotEnabled); 608 if (!enabled()) return Response::Error(kDebuggerNotEnabled);
670 if (m_javaScriptPauseScheduled || m_debugger->isPaused()) 609 if (m_javaScriptPauseScheduled || m_debugger->isPaused())
671 return Response::OK(); 610 return Response::OK();
672 clearBreakDetails(); 611 clearBreakDetails();
673 m_javaScriptPauseScheduled = true; 612 m_javaScriptPauseScheduled = true;
674 m_scheduledDebuggerStep = NoStep; 613 m_scheduledDebuggerStep = NoStep;
675 m_skippedStepFrameCount = 0;
676 m_steppingFromFramework = false;
677 m_debugger->setPauseOnNextStatement(true); 614 m_debugger->setPauseOnNextStatement(true);
678 return Response::OK(); 615 return Response::OK();
679 } 616 }
680 617
681 Response V8DebuggerAgentImpl::resume() { 618 Response V8DebuggerAgentImpl::resume() {
682 if (m_pausedContext.IsEmpty()) return Response::Error(kDebuggerNotPaused); 619 if (m_pausedContext.IsEmpty()) return Response::Error(kDebuggerNotPaused);
683 m_scheduledDebuggerStep = NoStep; 620 m_scheduledDebuggerStep = NoStep;
684 m_steppingFromFramework = false;
685 m_session->releaseObjectGroup(kBacktraceObjectGroup); 621 m_session->releaseObjectGroup(kBacktraceObjectGroup);
686 m_debugger->continueProgram(); 622 m_debugger->continueProgram();
687 return Response::OK(); 623 return Response::OK();
688 } 624 }
689 625
690 Response V8DebuggerAgentImpl::stepOver() { 626 Response V8DebuggerAgentImpl::stepOver() {
691 if (m_pausedContext.IsEmpty()) return Response::Error(kDebuggerNotPaused); 627 if (m_pausedContext.IsEmpty()) return Response::Error(kDebuggerNotPaused);
692 // StepOver at function return point should fallback to StepInto. 628 // StepOver at function return point should fallback to StepInto.
693 JavaScriptCallFrame* frame = 629 JavaScriptCallFrame* frame =
694 !m_pausedCallFrames.empty() ? m_pausedCallFrames[0].get() : nullptr; 630 !m_pausedCallFrames.empty() ? m_pausedCallFrames[0].get() : nullptr;
695 if (frame && frame->isAtReturn()) return stepInto(); 631 if (frame && frame->isAtReturn()) return stepInto();
696 m_scheduledDebuggerStep = StepOver; 632 m_scheduledDebuggerStep = StepOver;
697 m_steppingFromFramework = isTopPausedCallFrameBlackboxed();
698 m_session->releaseObjectGroup(kBacktraceObjectGroup); 633 m_session->releaseObjectGroup(kBacktraceObjectGroup);
699 m_debugger->stepOverStatement(); 634 m_debugger->stepOverStatement();
700 return Response::OK(); 635 return Response::OK();
701 } 636 }
702 637
703 Response V8DebuggerAgentImpl::stepInto() { 638 Response V8DebuggerAgentImpl::stepInto() {
704 if (m_pausedContext.IsEmpty()) return Response::Error(kDebuggerNotPaused); 639 if (m_pausedContext.IsEmpty()) return Response::Error(kDebuggerNotPaused);
705 m_scheduledDebuggerStep = StepInto; 640 m_scheduledDebuggerStep = StepInto;
706 m_steppingFromFramework = isTopPausedCallFrameBlackboxed();
707 m_session->releaseObjectGroup(kBacktraceObjectGroup); 641 m_session->releaseObjectGroup(kBacktraceObjectGroup);
708 m_debugger->stepIntoStatement(); 642 m_debugger->stepIntoStatement();
709 return Response::OK(); 643 return Response::OK();
710 } 644 }
711 645
712 Response V8DebuggerAgentImpl::stepOut() { 646 Response V8DebuggerAgentImpl::stepOut() {
713 if (m_pausedContext.IsEmpty()) return Response::Error(kDebuggerNotPaused); 647 if (m_pausedContext.IsEmpty()) return Response::Error(kDebuggerNotPaused);
714 m_scheduledDebuggerStep = StepOut; 648 m_scheduledDebuggerStep = StepOut;
715 m_skipNextDebuggerStepOut = false;
716 m_recursionLevelForStepOut = 1; 649 m_recursionLevelForStepOut = 1;
717 m_steppingFromFramework = isTopPausedCallFrameBlackboxed();
718 m_session->releaseObjectGroup(kBacktraceObjectGroup); 650 m_session->releaseObjectGroup(kBacktraceObjectGroup);
719 m_debugger->stepOutOfFunction(); 651 m_debugger->stepOutOfFunction();
720 return Response::OK(); 652 return Response::OK();
721 } 653 }
722 654
723 Response V8DebuggerAgentImpl::setPauseOnExceptions( 655 Response V8DebuggerAgentImpl::setPauseOnExceptions(
724 const String16& stringPauseState) { 656 const String16& stringPauseState) {
725 if (!enabled()) return Response::Error(kDebuggerNotEnabled); 657 if (!enabled()) return Response::Error(kDebuggerNotEnabled);
726 v8::debug::ExceptionBreakState pauseState; 658 v8::debug::ExceptionBreakState pauseState;
727 if (stringPauseState == "none") { 659 if (stringPauseState == "none") {
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
804 if (!enabled()) return Response::Error(kDebuggerNotEnabled); 736 if (!enabled()) return Response::Error(kDebuggerNotEnabled);
805 m_state->setInteger(DebuggerAgentState::asyncCallStackDepth, depth); 737 m_state->setInteger(DebuggerAgentState::asyncCallStackDepth, depth);
806 m_debugger->setAsyncCallStackDepth(this, depth); 738 m_debugger->setAsyncCallStackDepth(this, depth);
807 return Response::OK(); 739 return Response::OK();
808 } 740 }
809 741
810 Response V8DebuggerAgentImpl::setBlackboxPatterns( 742 Response V8DebuggerAgentImpl::setBlackboxPatterns(
811 std::unique_ptr<protocol::Array<String16>> patterns) { 743 std::unique_ptr<protocol::Array<String16>> patterns) {
812 if (!patterns->length()) { 744 if (!patterns->length()) {
813 m_blackboxPattern = nullptr; 745 m_blackboxPattern = nullptr;
746 for (const auto& it : m_scripts) {
747 it.second->blackboxStateChanged();
748 }
814 m_state->remove(DebuggerAgentState::blackboxPattern); 749 m_state->remove(DebuggerAgentState::blackboxPattern);
815 return Response::OK(); 750 return Response::OK();
816 } 751 }
817 752
818 String16Builder patternBuilder; 753 String16Builder patternBuilder;
819 patternBuilder.append('('); 754 patternBuilder.append('(');
820 for (size_t i = 0; i < patterns->length() - 1; ++i) { 755 for (size_t i = 0; i < patterns->length() - 1; ++i) {
821 patternBuilder.append(patterns->get(i)); 756 patternBuilder.append(patterns->get(i));
822 patternBuilder.append("|"); 757 patternBuilder.append("|");
823 } 758 }
824 patternBuilder.append(patterns->get(patterns->length() - 1)); 759 patternBuilder.append(patterns->get(patterns->length() - 1));
825 patternBuilder.append(')'); 760 patternBuilder.append(')');
826 String16 pattern = patternBuilder.toString(); 761 String16 pattern = patternBuilder.toString();
827 Response response = setBlackboxPattern(pattern); 762 Response response = setBlackboxPattern(pattern);
828 if (!response.isSuccess()) return response; 763 if (!response.isSuccess()) return response;
829 m_state->setString(DebuggerAgentState::blackboxPattern, pattern); 764 m_state->setString(DebuggerAgentState::blackboxPattern, pattern);
830 return Response::OK(); 765 return Response::OK();
831 } 766 }
832 767
833 Response V8DebuggerAgentImpl::setBlackboxPattern(const String16& pattern) { 768 Response V8DebuggerAgentImpl::setBlackboxPattern(const String16& pattern) {
834 std::unique_ptr<V8Regex> regex(new V8Regex( 769 std::unique_ptr<V8Regex> regex(new V8Regex(
835 m_inspector, pattern, true /** caseSensitive */, false /** multiline */)); 770 m_inspector, pattern, true /** caseSensitive */, false /** multiline */));
836 if (!regex->isValid()) 771 if (!regex->isValid())
837 return Response::Error("Pattern parser error: " + regex->errorMessage()); 772 return Response::Error("Pattern parser error: " + regex->errorMessage());
838 m_blackboxPattern = std::move(regex); 773 m_blackboxPattern = std::move(regex);
774 for (const auto& it : m_scripts) {
775 it.second->blackboxStateChanged();
776 }
839 return Response::OK(); 777 return Response::OK();
840 } 778 }
841 779
842 Response V8DebuggerAgentImpl::setBlackboxedRanges( 780 Response V8DebuggerAgentImpl::setBlackboxedRanges(
843 const String16& scriptId, 781 const String16& scriptId,
844 std::unique_ptr<protocol::Array<protocol::Debugger::ScriptPosition>> 782 std::unique_ptr<protocol::Array<protocol::Debugger::ScriptPosition>>
845 inPositions) { 783 inPositions) {
846 if (m_scripts.find(scriptId) == m_scripts.end()) 784 auto it = m_scripts.find(scriptId);
785 if (it == m_scripts.end())
847 return Response::Error("No script with passed id."); 786 return Response::Error("No script with passed id.");
848 787
849 if (!inPositions->length()) { 788 if (!inPositions->length()) {
850 m_blackboxedPositions.erase(scriptId); 789 m_blackboxedPositions.erase(scriptId);
790 it->second->blackboxStateChanged();
851 return Response::OK(); 791 return Response::OK();
852 } 792 }
853 793
854 std::vector<std::pair<int, int>> positions; 794 std::vector<std::pair<int, int>> positions;
855 positions.reserve(inPositions->length()); 795 positions.reserve(inPositions->length());
856 for (size_t i = 0; i < inPositions->length(); ++i) { 796 for (size_t i = 0; i < inPositions->length(); ++i) {
857 protocol::Debugger::ScriptPosition* position = inPositions->get(i); 797 protocol::Debugger::ScriptPosition* position = inPositions->get(i);
858 if (position->getLineNumber() < 0) 798 if (position->getLineNumber() < 0)
859 return Response::Error("Position missing 'line' or 'line' < 0."); 799 return Response::Error("Position missing 'line' or 'line' < 0.");
860 if (position->getColumnNumber() < 0) 800 if (position->getColumnNumber() < 0)
861 return Response::Error("Position missing 'column' or 'column' < 0."); 801 return Response::Error("Position missing 'column' or 'column' < 0.");
862 positions.push_back( 802 positions.push_back(
863 std::make_pair(position->getLineNumber(), position->getColumnNumber())); 803 std::make_pair(position->getLineNumber(), position->getColumnNumber()));
864 } 804 }
865 805
866 for (size_t i = 1; i < positions.size(); ++i) { 806 for (size_t i = 1; i < positions.size(); ++i) {
867 if (positions[i - 1].first < positions[i].first) continue; 807 if (positions[i - 1].first < positions[i].first) continue;
868 if (positions[i - 1].first == positions[i].first && 808 if (positions[i - 1].first == positions[i].first &&
869 positions[i - 1].second < positions[i].second) 809 positions[i - 1].second < positions[i].second)
870 continue; 810 continue;
871 return Response::Error( 811 return Response::Error(
872 "Input positions array is not sorted or contains duplicate values."); 812 "Input positions array is not sorted or contains duplicate values.");
873 } 813 }
874 814
875 m_blackboxedPositions[scriptId] = positions; 815 m_blackboxedPositions[scriptId] = positions;
816 it->second->blackboxStateChanged();
876 return Response::OK(); 817 return Response::OK();
877 } 818 }
878 819
879 void V8DebuggerAgentImpl::willExecuteScript(int scriptId) { 820 void V8DebuggerAgentImpl::willExecuteScript(int scriptId) {
880 changeJavaScriptRecursionLevel(+1); 821 changeJavaScriptRecursionLevel(+1);
881 // Fast return. 822 // Fast return.
882 if (m_scheduledDebuggerStep != StepInto) return; 823 if (m_scheduledDebuggerStep != StepInto) return;
883 schedulePauseOnNextStatementIfSteppingInto(); 824 schedulePauseOnNextStatementIfSteppingInto();
884 } 825 }
885 826
886 void V8DebuggerAgentImpl::didExecuteScript() { 827 void V8DebuggerAgentImpl::didExecuteScript() {
887 changeJavaScriptRecursionLevel(-1); 828 changeJavaScriptRecursionLevel(-1);
888 } 829 }
889 830
890 void V8DebuggerAgentImpl::changeJavaScriptRecursionLevel(int step) { 831 void V8DebuggerAgentImpl::changeJavaScriptRecursionLevel(int step) {
891 if (m_javaScriptPauseScheduled && !m_skipAllPauses && 832 if (m_javaScriptPauseScheduled && !m_skipAllPauses &&
892 !m_debugger->isPaused()) { 833 !m_debugger->isPaused()) {
893 // Do not ever loose user's pause request until we have actually paused. 834 // Do not ever loose user's pause request until we have actually paused.
894 m_debugger->setPauseOnNextStatement(true); 835 m_debugger->setPauseOnNextStatement(true);
895 } 836 }
896 if (m_scheduledDebuggerStep == StepOut) { 837 if (m_scheduledDebuggerStep == StepOut) {
897 m_recursionLevelForStepOut += step; 838 m_recursionLevelForStepOut += step;
898 if (!m_recursionLevelForStepOut) { 839 if (!m_recursionLevelForStepOut) {
899 // When StepOut crosses a task boundary (i.e. js -> c++) from where it was 840 // When StepOut crosses a task boundary (i.e. js -> c++) from where it was
900 // requested, 841 // requested,
901 // switch stepping to step into a next JS task, as if we exited to a 842 // switch stepping to step into a next JS task, as if we exited to a
902 // blackboxed framework. 843 // blackboxed framework.
903 m_scheduledDebuggerStep = StepInto; 844 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 } 845 }
926 } 846 }
927 } 847 }
928 848
929 Response V8DebuggerAgentImpl::currentCallFrames( 849 Response V8DebuggerAgentImpl::currentCallFrames(
930 std::unique_ptr<Array<CallFrame>>* result) { 850 std::unique_ptr<Array<CallFrame>>* result) {
931 if (m_pausedContext.IsEmpty() || !m_pausedCallFrames.size()) { 851 if (m_pausedContext.IsEmpty() || !m_pausedCallFrames.size()) {
932 *result = Array<CallFrame>::create(); 852 *result = Array<CallFrame>::create();
933 return Response::OK(); 853 return Response::OK();
934 } 854 }
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
1065 bool isLiveEdit = script->isLiveEdit(); 985 bool isLiveEdit = script->isLiveEdit();
1066 bool hasSourceURL = script->hasSourceURL(); 986 bool hasSourceURL = script->hasSourceURL();
1067 String16 scriptId = script->scriptId(); 987 String16 scriptId = script->scriptId();
1068 String16 scriptURL = script->sourceURL(); 988 String16 scriptURL = script->sourceURL();
1069 989
1070 m_scripts[scriptId] = std::move(script); 990 m_scripts[scriptId] = std::move(script);
1071 991
1072 ScriptsMap::iterator scriptIterator = m_scripts.find(scriptId); 992 ScriptsMap::iterator scriptIterator = m_scripts.find(scriptId);
1073 DCHECK(scriptIterator != m_scripts.end()); 993 DCHECK(scriptIterator != m_scripts.end());
1074 V8DebuggerScript* scriptRef = scriptIterator->second.get(); 994 V8DebuggerScript* scriptRef = scriptIterator->second.get();
995 scriptRef->blackboxStateChanged();
1075 996
1076 Maybe<String16> sourceMapURLParam = scriptRef->sourceMappingURL(); 997 Maybe<String16> sourceMapURLParam = scriptRef->sourceMappingURL();
1077 Maybe<protocol::DictionaryValue> executionContextAuxDataParam( 998 Maybe<protocol::DictionaryValue> executionContextAuxDataParam(
1078 std::move(executionContextAuxData)); 999 std::move(executionContextAuxData));
1079 const bool* isLiveEditParam = isLiveEdit ? &isLiveEdit : nullptr; 1000 const bool* isLiveEditParam = isLiveEdit ? &isLiveEdit : nullptr;
1080 const bool* hasSourceURLParam = hasSourceURL ? &hasSourceURL : nullptr; 1001 const bool* hasSourceURLParam = hasSourceURL ? &hasSourceURL : nullptr;
1081 if (success) 1002 if (success)
1082 m_frontend.scriptParsed( 1003 m_frontend.scriptParsed(
1083 scriptId, scriptURL, scriptRef->startLine(), scriptRef->startColumn(), 1004 scriptId, scriptURL, scriptRef->startLine(), scriptRef->startColumn(),
1084 scriptRef->endLine(), scriptRef->endColumn(), contextId, 1005 scriptRef->endLine(), scriptRef->endColumn(), contextId,
(...skipping 29 matching lines...) Expand all
1114 &breakpoint.column_number); 1035 &breakpoint.column_number);
1115 breakpointObject->getString(DebuggerAgentState::condition, 1036 breakpointObject->getString(DebuggerAgentState::condition,
1116 &breakpoint.condition); 1037 &breakpoint.condition);
1117 std::unique_ptr<protocol::Debugger::Location> location = 1038 std::unique_ptr<protocol::Debugger::Location> location =
1118 resolveBreakpoint(cookie.first, breakpoint, UserBreakpointSource); 1039 resolveBreakpoint(cookie.first, breakpoint, UserBreakpointSource);
1119 if (location) 1040 if (location)
1120 m_frontend.breakpointResolved(cookie.first, std::move(location)); 1041 m_frontend.breakpointResolved(cookie.first, std::move(location));
1121 } 1042 }
1122 } 1043 }
1123 1044
1124 V8DebuggerAgentImpl::SkipPauseRequest V8DebuggerAgentImpl::didPause( 1045 bool V8DebuggerAgentImpl::didPause(v8::Local<v8::Context> context,
1125 v8::Local<v8::Context> context, v8::Local<v8::Value> exception, 1046 v8::Local<v8::Value> exception,
1126 const std::vector<String16>& hitBreakpoints, bool isPromiseRejection, 1047 const std::vector<String16>& hitBreakpoints,
1127 bool isUncaught, bool isOOMBreak) { 1048 bool isPromiseRejection, bool isUncaught,
1049 bool isOOMBreak) {
1128 JavaScriptCallFrames callFrames = m_debugger->currentCallFrames(1); 1050 JavaScriptCallFrames callFrames = m_debugger->currentCallFrames(1);
1129 JavaScriptCallFrame* topCallFrame = 1051 JavaScriptCallFrame* topCallFrame =
1130 !callFrames.empty() ? callFrames.begin()->get() : nullptr; 1052 !callFrames.empty() ? callFrames.begin()->get() : nullptr;
1131
1132 V8DebuggerAgentImpl::SkipPauseRequest result;
1133 if (isOOMBreak)
1134 result = RequestNoSkip;
1135 else if (m_skipAllPauses)
1136 result = RequestContinue;
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. 1053 // Skip pauses inside V8 internal scripts and on syntax errors.
1151 if (!topCallFrame) return RequestContinue; 1054 if (!isOOMBreak && (!topCallFrame || m_skipAllPauses)) return false;
1152
1153 DCHECK(m_pausedContext.IsEmpty()); 1055 DCHECK(m_pausedContext.IsEmpty());
1154 JavaScriptCallFrames frames = m_debugger->currentCallFrames(); 1056 JavaScriptCallFrames frames = m_debugger->currentCallFrames();
1155 m_pausedCallFrames.swap(frames); 1057 m_pausedCallFrames.swap(frames);
1156 m_pausedContext.Reset(m_isolate, context); 1058 m_pausedContext.Reset(m_isolate, context);
1157 v8::HandleScope handles(m_isolate); 1059 v8::HandleScope handles(m_isolate);
1158 1060
1159 if (isOOMBreak) { 1061 if (isOOMBreak) {
1160 m_breakReason = protocol::Debugger::Paused::ReasonEnum::OOM; 1062 m_breakReason = protocol::Debugger::Paused::ReasonEnum::OOM;
1161 m_breakAuxData = nullptr; 1063 m_breakAuxData = nullptr;
1162 } else if (!exception.IsEmpty()) { 1064 } else if (!exception.IsEmpty()) {
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1198 } 1100 }
1199 1101
1200 std::unique_ptr<Array<CallFrame>> protocolCallFrames; 1102 std::unique_ptr<Array<CallFrame>> protocolCallFrames;
1201 Response response = currentCallFrames(&protocolCallFrames); 1103 Response response = currentCallFrames(&protocolCallFrames);
1202 if (!response.isSuccess()) protocolCallFrames = Array<CallFrame>::create(); 1104 if (!response.isSuccess()) protocolCallFrames = Array<CallFrame>::create();
1203 m_frontend.paused(std::move(protocolCallFrames), m_breakReason, 1105 m_frontend.paused(std::move(protocolCallFrames), m_breakReason,
1204 std::move(m_breakAuxData), std::move(hitBreakpointIds), 1106 std::move(m_breakAuxData), std::move(hitBreakpointIds),
1205 currentAsyncStackTrace()); 1107 currentAsyncStackTrace());
1206 m_scheduledDebuggerStep = NoStep; 1108 m_scheduledDebuggerStep = NoStep;
1207 m_javaScriptPauseScheduled = false; 1109 m_javaScriptPauseScheduled = false;
1208 m_steppingFromFramework = false;
1209 m_pausingOnNativeEvent = false;
1210 m_skippedStepFrameCount = 0;
1211 m_recursionLevelForStepFrame = 0;
1212 1110
1213 if (!m_continueToLocationBreakpointId.isEmpty()) { 1111 if (!m_continueToLocationBreakpointId.isEmpty()) {
1214 m_debugger->removeBreakpoint(m_continueToLocationBreakpointId); 1112 m_debugger->removeBreakpoint(m_continueToLocationBreakpointId);
1215 m_continueToLocationBreakpointId = ""; 1113 m_continueToLocationBreakpointId = "";
1216 } 1114 }
1217 return result; 1115 return true;
1218 } 1116 }
1219 1117
1220 void V8DebuggerAgentImpl::didContinue() { 1118 void V8DebuggerAgentImpl::didContinue() {
1221 m_pausedContext.Reset(); 1119 m_pausedContext.Reset();
1222 JavaScriptCallFrames emptyCallFrames; 1120 JavaScriptCallFrames emptyCallFrames;
1223 m_pausedCallFrames.swap(emptyCallFrames); 1121 m_pausedCallFrames.swap(emptyCallFrames);
1224 clearBreakDetails(); 1122 clearBreakDetails();
1225 m_frontend.resumed(); 1123 m_frontend.resumed();
1226 } 1124 }
1227 1125
1228 void V8DebuggerAgentImpl::breakProgram( 1126 void V8DebuggerAgentImpl::breakProgram(
1229 const String16& breakReason, 1127 const String16& breakReason,
1230 std::unique_ptr<protocol::DictionaryValue> data) { 1128 std::unique_ptr<protocol::DictionaryValue> data) {
1231 if (!enabled() || m_skipAllPauses || !m_pausedContext.IsEmpty() || 1129 if (!enabled() || m_skipAllPauses || !m_pausedContext.IsEmpty() ||
1232 isCurrentCallStackEmptyOrBlackboxed() ||
1233 !m_debugger->breakpointsActivated()) 1130 !m_debugger->breakpointsActivated())
1234 return; 1131 return;
1132 if (!m_debugger->hasUserFrameOnStack()) return;
1235 m_breakReason = breakReason; 1133 m_breakReason = breakReason;
1236 m_breakAuxData = std::move(data); 1134 m_breakAuxData = std::move(data);
1237 m_scheduledDebuggerStep = NoStep; 1135 m_scheduledDebuggerStep = NoStep;
1238 m_steppingFromFramework = false;
1239 m_pausingOnNativeEvent = false;
1240 m_debugger->breakProgram(); 1136 m_debugger->breakProgram();
1241 } 1137 }
1242 1138
1243 void V8DebuggerAgentImpl::breakProgramOnException( 1139 void V8DebuggerAgentImpl::breakProgramOnException(
1244 const String16& breakReason, 1140 const String16& breakReason,
1245 std::unique_ptr<protocol::DictionaryValue> data) { 1141 std::unique_ptr<protocol::DictionaryValue> data) {
1246 if (!enabled() || 1142 if (!enabled() ||
1247 m_debugger->getPauseOnExceptionsState() == v8::debug::NoBreakOnException) 1143 m_debugger->getPauseOnExceptionsState() == v8::debug::NoBreakOnException)
1248 return; 1144 return;
1249 breakProgram(breakReason, std::move(data)); 1145 if (m_debugger->hasUserFrameOnStack())
1146 breakProgram(breakReason, std::move(data));
1250 } 1147 }
1251 1148
1252 void V8DebuggerAgentImpl::clearBreakDetails() { 1149 void V8DebuggerAgentImpl::clearBreakDetails() {
1253 m_breakReason = protocol::Debugger::Paused::ReasonEnum::Other; 1150 m_breakReason = protocol::Debugger::Paused::ReasonEnum::Other;
1254 m_breakAuxData = nullptr; 1151 m_breakAuxData = nullptr;
1255 } 1152 }
1256 1153
1257 void V8DebuggerAgentImpl::setBreakpointAt(const String16& scriptId, 1154 void V8DebuggerAgentImpl::setBreakpointAt(const String16& scriptId,
1258 int lineNumber, int columnNumber, 1155 int lineNumber, int columnNumber,
1259 BreakpointSource source, 1156 BreakpointSource source,
1260 const String16& condition) { 1157 const String16& condition) {
1261 ScriptBreakpoint breakpoint(scriptId, lineNumber, columnNumber, condition); 1158 ScriptBreakpoint breakpoint(scriptId, lineNumber, columnNumber, condition);
1262 String16 breakpointId = generateBreakpointId(breakpoint, source); 1159 String16 breakpointId = generateBreakpointId(breakpoint, source);
1263 resolveBreakpoint(breakpointId, breakpoint, source); 1160 resolveBreakpoint(breakpointId, breakpoint, source);
1264 } 1161 }
1265 1162
1266 void V8DebuggerAgentImpl::removeBreakpointAt(const String16& scriptId, 1163 void V8DebuggerAgentImpl::removeBreakpointAt(const String16& scriptId,
1267 int lineNumber, int columnNumber, 1164 int lineNumber, int columnNumber,
1268 BreakpointSource source) { 1165 BreakpointSource source) {
1269 removeBreakpointImpl(generateBreakpointId( 1166 removeBreakpointImpl(generateBreakpointId(
1270 ScriptBreakpoint(scriptId, lineNumber, columnNumber, String16()), 1167 ScriptBreakpoint(scriptId, lineNumber, columnNumber, String16()),
1271 source)); 1168 source));
1272 } 1169 }
1273 1170
1274 void V8DebuggerAgentImpl::reset() { 1171 void V8DebuggerAgentImpl::reset() {
1275 if (!enabled()) return; 1172 if (!enabled()) return;
1276 m_scheduledDebuggerStep = NoStep; 1173 m_scheduledDebuggerStep = NoStep;
1174 m_blackboxedPositions.clear();
1175 for (const auto& it : m_scripts) {
1176 it.second->blackboxStateChanged();
1177 }
1277 m_scripts.clear(); 1178 m_scripts.clear();
1278 m_blackboxedPositions.clear();
1279 m_breakpointIdToDebuggerBreakpointIds.clear(); 1179 m_breakpointIdToDebuggerBreakpointIds.clear();
1280 } 1180 }
1281 1181
1282 } // namespace v8_inspector 1182 } // namespace v8_inspector
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698