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

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

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

Powered by Google App Engine
This is Rietveld 408576698