OLD | NEW |
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 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
191 V8DebuggerAgentImpl::V8DebuggerAgentImpl( | 191 V8DebuggerAgentImpl::V8DebuggerAgentImpl( |
192 V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel, | 192 V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel, |
193 protocol::DictionaryValue* state) | 193 protocol::DictionaryValue* state) |
194 : m_inspector(session->inspector()), | 194 : m_inspector(session->inspector()), |
195 m_debugger(m_inspector->debugger()), | 195 m_debugger(m_inspector->debugger()), |
196 m_session(session), | 196 m_session(session), |
197 m_enabled(false), | 197 m_enabled(false), |
198 m_state(state), | 198 m_state(state), |
199 m_frontend(frontendChannel), | 199 m_frontend(frontendChannel), |
200 m_isolate(m_inspector->isolate()), | 200 m_isolate(m_inspector->isolate()), |
201 m_scheduledDebuggerStep(NoStep), | 201 m_javaScriptPauseScheduled(false) {} |
202 m_javaScriptPauseScheduled(false), | |
203 m_recursionLevelForStepOut(0) { | |
204 } | |
205 | 202 |
206 V8DebuggerAgentImpl::~V8DebuggerAgentImpl() {} | 203 V8DebuggerAgentImpl::~V8DebuggerAgentImpl() {} |
207 | 204 |
208 void V8DebuggerAgentImpl::enableImpl() { | 205 void V8DebuggerAgentImpl::enableImpl() { |
209 m_enabled = true; | 206 m_enabled = true; |
210 m_state->setBoolean(DebuggerAgentState::debuggerEnabled, true); | 207 m_state->setBoolean(DebuggerAgentState::debuggerEnabled, true); |
211 m_debugger->enable(); | 208 m_debugger->enable(); |
212 | 209 |
213 std::vector<std::unique_ptr<V8DebuggerScript>> compiledScripts; | 210 std::vector<std::unique_ptr<V8DebuggerScript>> compiledScripts; |
214 m_debugger->getCompiledScripts(m_session->contextGroupId(), compiledScripts); | 211 m_debugger->getCompiledScripts(m_session->contextGroupId(), compiledScripts); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
246 JavaScriptCallFrames emptyCallFrames; | 243 JavaScriptCallFrames emptyCallFrames; |
247 m_pausedCallFrames.swap(emptyCallFrames); | 244 m_pausedCallFrames.swap(emptyCallFrames); |
248 m_blackboxedPositions.clear(); | 245 m_blackboxedPositions.clear(); |
249 m_blackboxPattern.reset(); | 246 m_blackboxPattern.reset(); |
250 resetBlackboxedStateCache(); | 247 resetBlackboxedStateCache(); |
251 m_scripts.clear(); | 248 m_scripts.clear(); |
252 m_breakpointIdToDebuggerBreakpointIds.clear(); | 249 m_breakpointIdToDebuggerBreakpointIds.clear(); |
253 m_debugger->setAsyncCallStackDepth(this, 0); | 250 m_debugger->setAsyncCallStackDepth(this, 0); |
254 m_continueToLocationBreakpointId = String16(); | 251 m_continueToLocationBreakpointId = String16(); |
255 clearBreakDetails(); | 252 clearBreakDetails(); |
256 m_scheduledDebuggerStep = NoStep; | |
257 m_javaScriptPauseScheduled = false; | 253 m_javaScriptPauseScheduled = false; |
258 m_skipAllPauses = false; | 254 m_skipAllPauses = false; |
259 m_state->setBoolean(DebuggerAgentState::skipAllPauses, false); | 255 m_state->setBoolean(DebuggerAgentState::skipAllPauses, false); |
260 m_state->remove(DebuggerAgentState::blackboxPattern); | 256 m_state->remove(DebuggerAgentState::blackboxPattern); |
261 m_enabled = false; | 257 m_enabled = false; |
262 m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false); | 258 m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false); |
263 return Response::OK(); | 259 return Response::OK(); |
264 } | 260 } |
265 | 261 |
266 void V8DebuggerAgentImpl::restore() { | 262 void V8DebuggerAgentImpl::restore() { |
(...skipping 414 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
681 } | 677 } |
682 | 678 |
683 void V8DebuggerAgentImpl::clearBreakDetails() { | 679 void V8DebuggerAgentImpl::clearBreakDetails() { |
684 std::vector<BreakReason> emptyBreakReason; | 680 std::vector<BreakReason> emptyBreakReason; |
685 m_breakReason.swap(emptyBreakReason); | 681 m_breakReason.swap(emptyBreakReason); |
686 } | 682 } |
687 | 683 |
688 void V8DebuggerAgentImpl::schedulePauseOnNextStatement( | 684 void V8DebuggerAgentImpl::schedulePauseOnNextStatement( |
689 const String16& breakReason, | 685 const String16& breakReason, |
690 std::unique_ptr<protocol::DictionaryValue> data) { | 686 std::unique_ptr<protocol::DictionaryValue> data) { |
691 if (!enabled() || m_scheduledDebuggerStep == StepInto || | 687 if (!enabled() || m_javaScriptPauseScheduled || isPaused() || |
692 m_javaScriptPauseScheduled || isPaused() || | |
693 !m_debugger->breakpointsActivated()) | 688 !m_debugger->breakpointsActivated()) |
694 return; | 689 return; |
695 if (m_breakReason.empty()) m_debugger->setPauseOnNextStatement(true); | 690 if (m_breakReason.empty()) { |
| 691 m_debugger->setPauseOnNextStatement(true, m_session->contextGroupId()); |
| 692 } |
696 pushBreakDetails(breakReason, std::move(data)); | 693 pushBreakDetails(breakReason, std::move(data)); |
697 } | 694 } |
698 | 695 |
699 void V8DebuggerAgentImpl::schedulePauseOnNextStatementIfSteppingInto() { | |
700 DCHECK(enabled()); | |
701 if (m_scheduledDebuggerStep != StepInto || m_javaScriptPauseScheduled || | |
702 isPaused()) | |
703 return; | |
704 m_debugger->setPauseOnNextStatement(true); | |
705 } | |
706 | |
707 void V8DebuggerAgentImpl::cancelPauseOnNextStatement() { | 696 void V8DebuggerAgentImpl::cancelPauseOnNextStatement() { |
708 if (m_javaScriptPauseScheduled || isPaused()) return; | 697 if (m_javaScriptPauseScheduled || isPaused()) return; |
709 popBreakDetails(); | 698 popBreakDetails(); |
710 if (m_breakReason.empty()) m_debugger->setPauseOnNextStatement(false); | 699 if (m_breakReason.empty()) |
| 700 m_debugger->setPauseOnNextStatement(false, m_session->contextGroupId()); |
711 } | 701 } |
712 | 702 |
713 Response V8DebuggerAgentImpl::pause() { | 703 Response V8DebuggerAgentImpl::pause() { |
714 if (!enabled()) return Response::Error(kDebuggerNotEnabled); | 704 if (!enabled()) return Response::Error(kDebuggerNotEnabled); |
715 if (m_javaScriptPauseScheduled || isPaused()) return Response::OK(); | 705 if (m_javaScriptPauseScheduled || isPaused()) return Response::OK(); |
716 clearBreakDetails(); | 706 clearBreakDetails(); |
717 m_javaScriptPauseScheduled = true; | 707 m_javaScriptPauseScheduled = true; |
718 m_scheduledDebuggerStep = NoStep; | 708 m_debugger->setPauseOnNextStatement(true, m_session->contextGroupId()); |
719 m_debugger->setPauseOnNextStatement(true); | |
720 return Response::OK(); | 709 return Response::OK(); |
721 } | 710 } |
722 | 711 |
723 Response V8DebuggerAgentImpl::resume() { | 712 Response V8DebuggerAgentImpl::resume() { |
724 if (!isPaused()) return Response::Error(kDebuggerNotPaused); | 713 if (!isPaused()) return Response::Error(kDebuggerNotPaused); |
725 m_scheduledDebuggerStep = NoStep; | |
726 m_session->releaseObjectGroup(kBacktraceObjectGroup); | 714 m_session->releaseObjectGroup(kBacktraceObjectGroup); |
727 m_debugger->continueProgram(); | 715 m_debugger->continueProgram(); |
728 return Response::OK(); | 716 return Response::OK(); |
729 } | 717 } |
730 | 718 |
731 Response V8DebuggerAgentImpl::stepOver() { | 719 Response V8DebuggerAgentImpl::stepOver() { |
732 if (!isPaused()) return Response::Error(kDebuggerNotPaused); | 720 if (!isPaused()) return Response::Error(kDebuggerNotPaused); |
733 // StepOver at function return point should fallback to StepInto. | |
734 JavaScriptCallFrame* frame = | |
735 !m_pausedCallFrames.empty() ? m_pausedCallFrames[0].get() : nullptr; | |
736 if (frame && frame->isAtReturn()) return stepInto(); | |
737 m_scheduledDebuggerStep = StepOver; | |
738 m_session->releaseObjectGroup(kBacktraceObjectGroup); | 721 m_session->releaseObjectGroup(kBacktraceObjectGroup); |
739 m_debugger->stepOverStatement(); | 722 m_debugger->stepOverStatement(m_session->contextGroupId()); |
740 return Response::OK(); | 723 return Response::OK(); |
741 } | 724 } |
742 | 725 |
743 Response V8DebuggerAgentImpl::stepInto() { | 726 Response V8DebuggerAgentImpl::stepInto() { |
744 if (!isPaused()) return Response::Error(kDebuggerNotPaused); | 727 if (!isPaused()) return Response::Error(kDebuggerNotPaused); |
745 m_scheduledDebuggerStep = StepInto; | |
746 m_session->releaseObjectGroup(kBacktraceObjectGroup); | 728 m_session->releaseObjectGroup(kBacktraceObjectGroup); |
747 m_debugger->stepIntoStatement(); | 729 m_debugger->stepIntoStatement(m_session->contextGroupId()); |
748 return Response::OK(); | 730 return Response::OK(); |
749 } | 731 } |
750 | 732 |
751 Response V8DebuggerAgentImpl::stepOut() { | 733 Response V8DebuggerAgentImpl::stepOut() { |
752 if (!isPaused()) return Response::Error(kDebuggerNotPaused); | 734 if (!isPaused()) return Response::Error(kDebuggerNotPaused); |
753 m_scheduledDebuggerStep = StepOut; | |
754 m_recursionLevelForStepOut = 1; | |
755 m_session->releaseObjectGroup(kBacktraceObjectGroup); | 735 m_session->releaseObjectGroup(kBacktraceObjectGroup); |
756 m_debugger->stepOutOfFunction(); | 736 m_debugger->stepOutOfFunction(m_session->contextGroupId()); |
757 return Response::OK(); | 737 return Response::OK(); |
758 } | 738 } |
759 | 739 |
760 void V8DebuggerAgentImpl::scheduleStepIntoAsync( | 740 void V8DebuggerAgentImpl::scheduleStepIntoAsync( |
761 std::unique_ptr<ScheduleStepIntoAsyncCallback> callback) { | 741 std::unique_ptr<ScheduleStepIntoAsyncCallback> callback) { |
762 if (!isPaused()) { | 742 if (!isPaused()) { |
763 callback->sendFailure(Response::Error(kDebuggerNotPaused)); | 743 callback->sendFailure(Response::Error(kDebuggerNotPaused)); |
764 return; | 744 return; |
765 } | 745 } |
766 if (m_stepIntoAsyncCallback) { | 746 if (m_stepIntoAsyncCallback) { |
767 m_stepIntoAsyncCallback->sendFailure(Response::Error( | 747 m_stepIntoAsyncCallback->sendFailure(Response::Error( |
768 "Current scheduled step into async was overriden with new one.")); | 748 "Current scheduled step into async was overriden with new one.")); |
769 } | 749 } |
770 m_stepIntoAsyncCallback = std::move(callback); | 750 m_stepIntoAsyncCallback = std::move(callback); |
771 } | 751 } |
772 | 752 |
773 bool V8DebuggerAgentImpl::shouldBreakInScheduledAsyncTask() { | 753 bool V8DebuggerAgentImpl::shouldBreakInScheduledAsyncTask() { |
774 if (!m_stepIntoAsyncCallback) return false; | 754 if (!m_stepIntoAsyncCallback) return false; |
775 m_stepIntoAsyncCallback->sendSuccess(); | 755 m_stepIntoAsyncCallback->sendSuccess(); |
776 m_stepIntoAsyncCallback.reset(); | 756 m_stepIntoAsyncCallback.reset(); |
777 m_scheduledDebuggerStep = NoStep; | |
778 v8::debug::ClearStepping(m_isolate); | |
779 return true; | 757 return true; |
780 } | 758 } |
781 | 759 |
782 Response V8DebuggerAgentImpl::setPauseOnExceptions( | 760 Response V8DebuggerAgentImpl::setPauseOnExceptions( |
783 const String16& stringPauseState) { | 761 const String16& stringPauseState) { |
784 if (!enabled()) return Response::Error(kDebuggerNotEnabled); | 762 if (!enabled()) return Response::Error(kDebuggerNotEnabled); |
785 v8::debug::ExceptionBreakState pauseState; | 763 v8::debug::ExceptionBreakState pauseState; |
786 if (stringPauseState == "none") { | 764 if (stringPauseState == "none") { |
787 pauseState = v8::debug::NoBreakOnException; | 765 pauseState = v8::debug::NoBreakOnException; |
788 } else if (stringPauseState == "all") { | 766 } else if (stringPauseState == "all") { |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
940 continue; | 918 continue; |
941 return Response::Error( | 919 return Response::Error( |
942 "Input positions array is not sorted or contains duplicate values."); | 920 "Input positions array is not sorted or contains duplicate values."); |
943 } | 921 } |
944 | 922 |
945 m_blackboxedPositions[scriptId] = positions; | 923 m_blackboxedPositions[scriptId] = positions; |
946 it->second->resetBlackboxedStateCache(); | 924 it->second->resetBlackboxedStateCache(); |
947 return Response::OK(); | 925 return Response::OK(); |
948 } | 926 } |
949 | 927 |
950 void V8DebuggerAgentImpl::willExecuteScript(int scriptId) { | |
951 changeJavaScriptRecursionLevel(+1); | |
952 if (m_scheduledDebuggerStep != StepInto) return; | |
953 schedulePauseOnNextStatementIfSteppingInto(); | |
954 } | |
955 | |
956 void V8DebuggerAgentImpl::didExecuteScript() { | |
957 changeJavaScriptRecursionLevel(-1); | |
958 } | |
959 | |
960 void V8DebuggerAgentImpl::changeJavaScriptRecursionLevel(int step) { | |
961 if (m_javaScriptPauseScheduled && !m_skipAllPauses && !isPaused()) { | |
962 // Do not ever loose user's pause request until we have actually paused. | |
963 m_debugger->setPauseOnNextStatement(true); | |
964 } | |
965 if (m_scheduledDebuggerStep == StepOut) { | |
966 m_recursionLevelForStepOut += step; | |
967 if (!m_recursionLevelForStepOut) { | |
968 // When StepOut crosses a task boundary (i.e. js -> c++) from where it was | |
969 // requested, | |
970 // switch stepping to step into a next JS task, as if we exited to a | |
971 // blackboxed framework. | |
972 m_scheduledDebuggerStep = StepInto; | |
973 } | |
974 } | |
975 } | |
976 | |
977 Response V8DebuggerAgentImpl::currentCallFrames( | 928 Response V8DebuggerAgentImpl::currentCallFrames( |
978 std::unique_ptr<Array<CallFrame>>* result) { | 929 std::unique_ptr<Array<CallFrame>>* result) { |
979 if (!isPaused()) { | 930 if (!isPaused()) { |
980 *result = Array<CallFrame>::create(); | 931 *result = Array<CallFrame>::create(); |
981 return Response::OK(); | 932 return Response::OK(); |
982 } | 933 } |
983 v8::HandleScope handles(m_isolate); | 934 v8::HandleScope handles(m_isolate); |
984 v8::Local<v8::Context> debuggerContext = | 935 v8::Local<v8::Context> debuggerContext = |
985 v8::debug::GetDebugContext(m_isolate); | 936 v8::debug::GetDebugContext(m_isolate); |
986 v8::Context::Scope contextScope(debuggerContext); | 937 v8::Context::Scope contextScope(debuggerContext); |
(...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1280 Response::Error("No async tasks were scheduled before pause.")); | 1231 Response::Error("No async tasks were scheduled before pause.")); |
1281 m_stepIntoAsyncCallback.reset(); | 1232 m_stepIntoAsyncCallback.reset(); |
1282 } | 1233 } |
1283 | 1234 |
1284 std::unique_ptr<Array<CallFrame>> protocolCallFrames; | 1235 std::unique_ptr<Array<CallFrame>> protocolCallFrames; |
1285 Response response = currentCallFrames(&protocolCallFrames); | 1236 Response response = currentCallFrames(&protocolCallFrames); |
1286 if (!response.isSuccess()) protocolCallFrames = Array<CallFrame>::create(); | 1237 if (!response.isSuccess()) protocolCallFrames = Array<CallFrame>::create(); |
1287 m_frontend.paused(std::move(protocolCallFrames), breakReason, | 1238 m_frontend.paused(std::move(protocolCallFrames), breakReason, |
1288 std::move(breakAuxData), std::move(hitBreakpointIds), | 1239 std::move(breakAuxData), std::move(hitBreakpointIds), |
1289 currentAsyncStackTrace()); | 1240 currentAsyncStackTrace()); |
1290 m_scheduledDebuggerStep = NoStep; | |
1291 m_javaScriptPauseScheduled = false; | 1241 m_javaScriptPauseScheduled = false; |
1292 | 1242 |
1293 if (!m_continueToLocationBreakpointId.isEmpty()) { | 1243 if (!m_continueToLocationBreakpointId.isEmpty()) { |
1294 m_debugger->removeBreakpoint(m_continueToLocationBreakpointId); | 1244 m_debugger->removeBreakpoint(m_continueToLocationBreakpointId); |
1295 m_continueToLocationBreakpointId = ""; | 1245 m_continueToLocationBreakpointId = ""; |
1296 } | 1246 } |
1297 } | 1247 } |
1298 | 1248 |
1299 void V8DebuggerAgentImpl::didContinue() { | 1249 void V8DebuggerAgentImpl::didContinue() { |
1300 JavaScriptCallFrames emptyCallFrames; | 1250 JavaScriptCallFrames emptyCallFrames; |
1301 m_pausedCallFrames.swap(emptyCallFrames); | 1251 m_pausedCallFrames.swap(emptyCallFrames); |
1302 clearBreakDetails(); | 1252 clearBreakDetails(); |
1303 m_frontend.resumed(); | 1253 m_frontend.resumed(); |
1304 } | 1254 } |
1305 | 1255 |
1306 void V8DebuggerAgentImpl::breakProgram( | 1256 void V8DebuggerAgentImpl::breakProgram( |
1307 const String16& breakReason, | 1257 const String16& breakReason, |
1308 std::unique_ptr<protocol::DictionaryValue> data) { | 1258 std::unique_ptr<protocol::DictionaryValue> data) { |
1309 if (!enabled() || !m_debugger->canBreakProgram() || m_skipAllPauses) return; | 1259 if (!enabled() || !m_debugger->canBreakProgram() || m_skipAllPauses) return; |
1310 std::vector<BreakReason> currentScheduledReason; | 1260 std::vector<BreakReason> currentScheduledReason; |
1311 currentScheduledReason.swap(m_breakReason); | 1261 currentScheduledReason.swap(m_breakReason); |
1312 pushBreakDetails(breakReason, std::move(data)); | 1262 pushBreakDetails(breakReason, std::move(data)); |
1313 m_scheduledDebuggerStep = NoStep; | |
1314 m_debugger->breakProgram(); | 1263 m_debugger->breakProgram(); |
1315 popBreakDetails(); | 1264 popBreakDetails(); |
1316 m_breakReason.swap(currentScheduledReason); | 1265 m_breakReason.swap(currentScheduledReason); |
1317 if (!m_breakReason.empty()) { | 1266 if (!m_breakReason.empty()) { |
1318 m_debugger->setPauseOnNextStatement(true); | 1267 m_debugger->setPauseOnNextStatement(true, m_session->contextGroupId()); |
1319 } | 1268 } |
1320 } | 1269 } |
1321 | 1270 |
1322 void V8DebuggerAgentImpl::breakProgramOnException( | 1271 void V8DebuggerAgentImpl::breakProgramOnException( |
1323 const String16& breakReason, | 1272 const String16& breakReason, |
1324 std::unique_ptr<protocol::DictionaryValue> data) { | 1273 std::unique_ptr<protocol::DictionaryValue> data) { |
1325 if (!enabled() || | 1274 if (!enabled() || |
1326 m_debugger->getPauseOnExceptionsState() == v8::debug::NoBreakOnException) | 1275 m_debugger->getPauseOnExceptionsState() == v8::debug::NoBreakOnException) |
1327 return; | 1276 return; |
1328 breakProgram(breakReason, std::move(data)); | 1277 breakProgram(breakReason, std::move(data)); |
(...skipping 11 matching lines...) Expand all Loading... |
1340 void V8DebuggerAgentImpl::removeBreakpointAt(const String16& scriptId, | 1289 void V8DebuggerAgentImpl::removeBreakpointAt(const String16& scriptId, |
1341 int lineNumber, int columnNumber, | 1290 int lineNumber, int columnNumber, |
1342 BreakpointSource source) { | 1291 BreakpointSource source) { |
1343 removeBreakpointImpl(generateBreakpointId( | 1292 removeBreakpointImpl(generateBreakpointId( |
1344 ScriptBreakpoint(scriptId, lineNumber, columnNumber, String16()), | 1293 ScriptBreakpoint(scriptId, lineNumber, columnNumber, String16()), |
1345 source)); | 1294 source)); |
1346 } | 1295 } |
1347 | 1296 |
1348 void V8DebuggerAgentImpl::reset() { | 1297 void V8DebuggerAgentImpl::reset() { |
1349 if (!enabled()) return; | 1298 if (!enabled()) return; |
1350 m_scheduledDebuggerStep = NoStep; | |
1351 m_blackboxedPositions.clear(); | 1299 m_blackboxedPositions.clear(); |
1352 resetBlackboxedStateCache(); | 1300 resetBlackboxedStateCache(); |
1353 m_scripts.clear(); | 1301 m_scripts.clear(); |
1354 m_breakpointIdToDebuggerBreakpointIds.clear(); | 1302 m_breakpointIdToDebuggerBreakpointIds.clear(); |
1355 } | 1303 } |
1356 | 1304 |
1357 } // namespace v8_inspector | 1305 } // namespace v8_inspector |
OLD | NEW |