OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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.h" | 5 #include "src/inspector/v8-debugger.h" |
6 | 6 |
7 #include "src/inspector/debugger-script.h" | 7 #include "src/inspector/debugger-script.h" |
8 #include "src/inspector/inspected-context.h" | 8 #include "src/inspector/inspected-context.h" |
9 #include "src/inspector/protocol/Protocol.h" | 9 #include "src/inspector/protocol/Protocol.h" |
10 #include "src/inspector/script-breakpoint.h" | 10 #include "src/inspector/script-breakpoint.h" |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
187 compileDebuggerScript(); | 187 compileDebuggerScript(); |
188 } | 188 } |
189 | 189 |
190 void V8Debugger::disable() { | 190 void V8Debugger::disable() { |
191 if (--m_enableCount) return; | 191 if (--m_enableCount) return; |
192 DCHECK(enabled()); | 192 DCHECK(enabled()); |
193 clearBreakpoints(); | 193 clearBreakpoints(); |
194 m_debuggerScript.Reset(); | 194 m_debuggerScript.Reset(); |
195 m_debuggerContext.Reset(); | 195 m_debuggerContext.Reset(); |
196 allAsyncTasksCanceled(); | 196 allAsyncTasksCanceled(); |
| 197 m_taskWithScheduledBreak = nullptr; |
197 m_wasmTranslation.Clear(); | 198 m_wasmTranslation.Clear(); |
198 v8::debug::SetDebugDelegate(m_isolate, nullptr); | 199 v8::debug::SetDebugDelegate(m_isolate, nullptr); |
199 v8::debug::SetOutOfMemoryCallback(m_isolate, nullptr, nullptr); | 200 v8::debug::SetOutOfMemoryCallback(m_isolate, nullptr, nullptr); |
200 m_isolate->RestoreOriginalHeapLimit(); | 201 m_isolate->RestoreOriginalHeapLimit(); |
201 } | 202 } |
202 | 203 |
203 bool V8Debugger::enabled() const { return !m_debuggerScript.IsEmpty(); } | 204 bool V8Debugger::enabled() const { return !m_debuggerScript.IsEmpty(); } |
204 | 205 |
205 void V8Debugger::getCompiledScripts( | 206 void V8Debugger::getCompiledScripts( |
206 int contextGroupId, | 207 int contextGroupId, |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
330 void V8Debugger::setPauseOnNextStatement(bool pause) { | 331 void V8Debugger::setPauseOnNextStatement(bool pause) { |
331 if (isPaused()) return; | 332 if (isPaused()) return; |
332 if (pause) | 333 if (pause) |
333 v8::debug::DebugBreak(m_isolate); | 334 v8::debug::DebugBreak(m_isolate); |
334 else | 335 else |
335 v8::debug::CancelDebugBreak(m_isolate); | 336 v8::debug::CancelDebugBreak(m_isolate); |
336 } | 337 } |
337 | 338 |
338 bool V8Debugger::canBreakProgram() { | 339 bool V8Debugger::canBreakProgram() { |
339 if (!m_breakpointsActivated) return false; | 340 if (!m_breakpointsActivated) return false; |
340 return v8::debug::HasNonBlackboxedFrameOnStack(m_isolate); | 341 return !v8::debug::AllFramesOnStackAreBlackboxed(m_isolate); |
341 } | 342 } |
342 | 343 |
343 void V8Debugger::breakProgram() { | 344 void V8Debugger::breakProgram() { |
344 // Don't allow nested breaks. | 345 // Don't allow nested breaks. |
345 if (isPaused()) return; | 346 if (isPaused()) return; |
346 if (!canBreakProgram()) return; | 347 if (!canBreakProgram()) return; |
347 | 348 |
348 v8::HandleScope scope(m_isolate); | 349 v8::HandleScope scope(m_isolate); |
349 v8::Local<v8::Function> breakFunction; | 350 v8::Local<v8::Function> breakFunction; |
350 if (!v8::Function::New(m_isolate->GetCurrentContext(), | 351 if (!v8::Function::New(m_isolate->GetCurrentContext(), |
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
618 | 619 |
619 bool V8Debugger::IsFunctionBlackboxed(v8::Local<v8::debug::Script> script, | 620 bool V8Debugger::IsFunctionBlackboxed(v8::Local<v8::debug::Script> script, |
620 const v8::debug::Location& start, | 621 const v8::debug::Location& start, |
621 const v8::debug::Location& end) { | 622 const v8::debug::Location& end) { |
622 V8DebuggerAgentImpl* agent = agentForScript(m_inspector, script); | 623 V8DebuggerAgentImpl* agent = agentForScript(m_inspector, script); |
623 if (!agent) return false; | 624 if (!agent) return false; |
624 return agent->isFunctionBlackboxed(String16::fromInteger(script->Id()), start, | 625 return agent->isFunctionBlackboxed(String16::fromInteger(script->Id()), start, |
625 end); | 626 end); |
626 } | 627 } |
627 | 628 |
628 void V8Debugger::PromiseEventOccurred(v8::debug::PromiseDebugActionType type, | 629 void V8Debugger::PromiseEventOccurred(v8::Local<v8::Context> context, |
629 int id, int parentId) { | 630 v8::debug::PromiseDebugActionType type, |
630 if (!m_maxAsyncCallStackDepth) return; | 631 int id, int parentId, |
| 632 bool createdByUser) { |
631 // Async task events from Promises are given misaligned pointers to prevent | 633 // Async task events from Promises are given misaligned pointers to prevent |
632 // from overlapping with other Blink task identifiers. There is a single | 634 // from overlapping with other Blink task identifiers. There is a single |
633 // namespace of such ids, managed by src/js/promise.js. | 635 // namespace of such ids, managed by src/js/promise.js. |
634 void* ptr = reinterpret_cast<void*>(id * 2 + 1); | 636 void* ptr = reinterpret_cast<void*>(id * 2 + 1); |
| 637 void* parentPtr = |
| 638 parentId ? reinterpret_cast<void*>(parentId * 2 + 1) : nullptr; |
| 639 handleAsyncTaskStepping(context, type, ptr, parentPtr, createdByUser); |
| 640 if (!m_maxAsyncCallStackDepth) return; |
635 switch (type) { | 641 switch (type) { |
636 case v8::debug::kDebugPromiseCreated: | 642 case v8::debug::kDebugPromiseCreated: |
637 asyncTaskCreated( | 643 asyncTaskCreated(ptr, parentPtr); |
638 ptr, parentId ? reinterpret_cast<void*>(parentId * 2 + 1) : nullptr); | |
639 break; | 644 break; |
640 case v8::debug::kDebugEnqueueAsyncFunction: | 645 case v8::debug::kDebugEnqueueAsyncFunction: |
641 asyncTaskScheduled("async function", ptr, true); | 646 asyncTaskScheduled("async function", ptr, true); |
642 break; | 647 break; |
643 case v8::debug::kDebugEnqueuePromiseResolve: | 648 case v8::debug::kDebugEnqueuePromiseResolve: |
644 asyncTaskScheduled("Promise.resolve", ptr, true); | 649 asyncTaskScheduled("Promise.resolve", ptr, true); |
645 break; | 650 break; |
646 case v8::debug::kDebugEnqueuePromiseReject: | 651 case v8::debug::kDebugEnqueuePromiseReject: |
647 asyncTaskScheduled("Promise.reject", ptr, true); | 652 asyncTaskScheduled("Promise.reject", ptr, true); |
648 break; | 653 break; |
649 case v8::debug::kDebugPromiseCollected: | 654 case v8::debug::kDebugPromiseCollected: |
650 asyncTaskCanceled(ptr); | 655 asyncTaskCanceled(ptr); |
651 break; | 656 break; |
652 case v8::debug::kDebugWillHandle: | 657 case v8::debug::kDebugWillHandle: |
653 asyncTaskStarted(ptr); | 658 asyncTaskStarted(ptr); |
654 break; | 659 break; |
655 case v8::debug::kDebugDidHandle: | 660 case v8::debug::kDebugDidHandle: |
656 asyncTaskFinished(ptr); | 661 asyncTaskFinished(ptr); |
657 break; | 662 break; |
658 } | 663 } |
659 } | 664 } |
660 | 665 |
| 666 void V8Debugger::handleAsyncTaskStepping(v8::Local<v8::Context> context, |
| 667 v8::debug::PromiseDebugActionType type, |
| 668 void* task, void* parentTask, |
| 669 bool createdByUser) { |
| 670 if (type == v8::debug::kDebugEnqueueAsyncFunction || |
| 671 type == v8::debug::kDebugEnqueuePromiseResolve || |
| 672 type == v8::debug::kDebugEnqueuePromiseReject) { |
| 673 return; |
| 674 } |
| 675 |
| 676 bool isScheduledTask = task == m_taskWithScheduledBreak; |
| 677 if (type == v8::debug::kDebugPromiseCollected) { |
| 678 if (isScheduledTask) m_taskWithScheduledBreak = nullptr; |
| 679 return; |
| 680 } |
| 681 if (type == v8::debug::kDebugPromiseCreated && !parentTask) return; |
| 682 |
| 683 DCHECK(!context.IsEmpty()); |
| 684 int contextGroupId = m_inspector->contextGroupId(context); |
| 685 V8DebuggerAgentImpl* agent = |
| 686 m_inspector->enabledDebuggerAgentForGroup(contextGroupId); |
| 687 if (!agent) return; |
| 688 if (createdByUser && type == v8::debug::kDebugPromiseCreated) { |
| 689 if (agent->shouldBreakInScheduledAsyncTask()) { |
| 690 m_taskWithScheduledBreak = task; |
| 691 } |
| 692 return; |
| 693 } |
| 694 if (!isScheduledTask) return; |
| 695 if (type == v8::debug::kDebugWillHandle) { |
| 696 agent->schedulePauseOnNextStatement( |
| 697 protocol::Debugger::Paused::ReasonEnum::Other, nullptr); |
| 698 return; |
| 699 } |
| 700 DCHECK(type == v8::debug::kDebugDidHandle); |
| 701 agent->cancelPauseOnNextStatement(); |
| 702 m_taskWithScheduledBreak = nullptr; |
| 703 } |
| 704 |
661 V8StackTraceImpl* V8Debugger::currentAsyncCallChain() { | 705 V8StackTraceImpl* V8Debugger::currentAsyncCallChain() { |
662 if (!m_currentStacks.size()) return nullptr; | 706 if (!m_currentStacks.size()) return nullptr; |
663 return m_currentStacks.back().get(); | 707 return m_currentStacks.back().get(); |
664 } | 708 } |
665 | 709 |
666 void V8Debugger::compileDebuggerScript() { | 710 void V8Debugger::compileDebuggerScript() { |
667 if (!m_debuggerScript.IsEmpty()) { | 711 if (!m_debuggerScript.IsEmpty()) { |
668 UNREACHABLE(); | 712 UNREACHABLE(); |
669 return; | 713 return; |
670 } | 714 } |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
795 createDataProperty(context, properties, properties->Length(), | 839 createDataProperty(context, properties, properties->Length(), |
796 toV8StringInternalized(m_isolate, "[[Scopes]]")); | 840 toV8StringInternalized(m_isolate, "[[Scopes]]")); |
797 createDataProperty(context, properties, properties->Length(), scopes); | 841 createDataProperty(context, properties, properties->Length(), scopes); |
798 } | 842 } |
799 } | 843 } |
800 return properties; | 844 return properties; |
801 } | 845 } |
802 | 846 |
803 std::unique_ptr<V8StackTraceImpl> V8Debugger::createStackTrace( | 847 std::unique_ptr<V8StackTraceImpl> V8Debugger::createStackTrace( |
804 v8::Local<v8::StackTrace> stackTrace) { | 848 v8::Local<v8::StackTrace> stackTrace) { |
805 int contextGroupId = | 849 return V8StackTraceImpl::create(this, currentContextGroupId(), stackTrace, |
806 m_isolate->InContext() | |
807 ? m_inspector->contextGroupId(m_isolate->GetCurrentContext()) | |
808 : 0; | |
809 return V8StackTraceImpl::create(this, contextGroupId, stackTrace, | |
810 V8StackTraceImpl::maxCallStackSizeToCapture); | 850 V8StackTraceImpl::maxCallStackSizeToCapture); |
811 } | 851 } |
812 | 852 |
813 void V8Debugger::setAsyncCallStackDepth(V8DebuggerAgentImpl* agent, int depth) { | 853 void V8Debugger::setAsyncCallStackDepth(V8DebuggerAgentImpl* agent, int depth) { |
814 if (depth <= 0) | 854 if (depth <= 0) |
815 m_maxAsyncCallStackDepthMap.erase(agent); | 855 m_maxAsyncCallStackDepthMap.erase(agent); |
816 else | 856 else |
817 m_maxAsyncCallStackDepthMap[agent] = depth; | 857 m_maxAsyncCallStackDepthMap[agent] = depth; |
818 | 858 |
819 int maxAsyncCallStackDepth = 0; | 859 int maxAsyncCallStackDepth = 0; |
(...skipping 16 matching lines...) Expand all Loading... |
836 if (static_cast<int>(m_idToTask.size()) > m_maxAsyncCallStacks) { | 876 if (static_cast<int>(m_idToTask.size()) > m_maxAsyncCallStacks) { |
837 void* taskToRemove = m_idToTask.begin()->second; | 877 void* taskToRemove = m_idToTask.begin()->second; |
838 asyncTaskCanceled(taskToRemove); | 878 asyncTaskCanceled(taskToRemove); |
839 } | 879 } |
840 } | 880 } |
841 | 881 |
842 void V8Debugger::asyncTaskCreated(void* task, void* parentTask) { | 882 void V8Debugger::asyncTaskCreated(void* task, void* parentTask) { |
843 if (!m_maxAsyncCallStackDepth) return; | 883 if (!m_maxAsyncCallStackDepth) return; |
844 if (parentTask) m_parentTask[task] = parentTask; | 884 if (parentTask) m_parentTask[task] = parentTask; |
845 v8::HandleScope scope(m_isolate); | 885 v8::HandleScope scope(m_isolate); |
846 // We don't need to pass context group id here because we gets this callback | 886 // We don't need to pass context group id here because we get this callback |
847 // from V8 for promise events only. | 887 // from V8 for promise events only. |
848 // Passing one as maxStackSize forces no async chain for the new stack and | 888 // Passing one as maxStackSize forces no async chain for the new stack and |
849 // allows us to not grow exponentially. | 889 // allows us to not grow exponentially. |
850 std::unique_ptr<V8StackTraceImpl> creationStack = | 890 std::unique_ptr<V8StackTraceImpl> creationStack = |
851 V8StackTraceImpl::capture(this, 0, 1, String16()); | 891 V8StackTraceImpl::capture(this, 0, 1, String16()); |
852 if (creationStack && !creationStack->isEmpty()) { | 892 if (creationStack && !creationStack->isEmpty()) { |
853 m_asyncTaskCreationStacks[task] = std::move(creationStack); | 893 m_asyncTaskCreationStacks[task] = std::move(creationStack); |
854 registerAsyncTaskIfNeeded(task); | 894 registerAsyncTaskIfNeeded(task); |
855 } | 895 } |
856 } | 896 } |
857 | 897 |
858 void V8Debugger::asyncTaskScheduled(const StringView& taskName, void* task, | 898 void V8Debugger::asyncTaskScheduled(const StringView& taskName, void* task, |
859 bool recurring) { | 899 bool recurring) { |
860 if (!m_maxAsyncCallStackDepth) return; | 900 if (!m_maxAsyncCallStackDepth) return; |
861 asyncTaskScheduled(toString16(taskName), task, recurring); | 901 asyncTaskScheduled(toString16(taskName), task, recurring); |
862 } | 902 } |
863 | 903 |
864 void V8Debugger::asyncTaskScheduled(const String16& taskName, void* task, | 904 void V8Debugger::asyncTaskScheduled(const String16& taskName, void* task, |
865 bool recurring) { | 905 bool recurring) { |
866 if (!m_maxAsyncCallStackDepth) return; | 906 if (!m_maxAsyncCallStackDepth) return; |
867 v8::HandleScope scope(m_isolate); | 907 v8::HandleScope scope(m_isolate); |
868 int contextGroupId = | |
869 m_isolate->InContext() | |
870 ? m_inspector->contextGroupId(m_isolate->GetCurrentContext()) | |
871 : 0; | |
872 std::unique_ptr<V8StackTraceImpl> chain = V8StackTraceImpl::capture( | 908 std::unique_ptr<V8StackTraceImpl> chain = V8StackTraceImpl::capture( |
873 this, contextGroupId, V8StackTraceImpl::maxCallStackSizeToCapture, | 909 this, currentContextGroupId(), |
874 taskName); | 910 V8StackTraceImpl::maxCallStackSizeToCapture, taskName); |
875 if (chain) { | 911 if (chain) { |
876 m_asyncTaskStacks[task] = std::move(chain); | 912 m_asyncTaskStacks[task] = std::move(chain); |
877 if (recurring) m_recurringTasks.insert(task); | 913 if (recurring) m_recurringTasks.insert(task); |
878 registerAsyncTaskIfNeeded(task); | 914 registerAsyncTaskIfNeeded(task); |
879 } | 915 } |
880 } | 916 } |
881 | 917 |
882 void V8Debugger::asyncTaskCanceled(void* task) { | 918 void V8Debugger::asyncTaskCanceled(void* task) { |
883 if (!m_maxAsyncCallStackDepth) return; | 919 if (!m_maxAsyncCallStackDepth) return; |
884 m_asyncTaskStacks.erase(task); | 920 m_asyncTaskStacks.erase(task); |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
947 void V8Debugger::unmuteScriptParsedEvents() { | 983 void V8Debugger::unmuteScriptParsedEvents() { |
948 --m_ignoreScriptParsedEventsCounter; | 984 --m_ignoreScriptParsedEventsCounter; |
949 DCHECK_GE(m_ignoreScriptParsedEventsCounter, 0); | 985 DCHECK_GE(m_ignoreScriptParsedEventsCounter, 0); |
950 } | 986 } |
951 | 987 |
952 std::unique_ptr<V8StackTraceImpl> V8Debugger::captureStackTrace( | 988 std::unique_ptr<V8StackTraceImpl> V8Debugger::captureStackTrace( |
953 bool fullStack) { | 989 bool fullStack) { |
954 if (!m_isolate->InContext()) return nullptr; | 990 if (!m_isolate->InContext()) return nullptr; |
955 | 991 |
956 v8::HandleScope handles(m_isolate); | 992 v8::HandleScope handles(m_isolate); |
957 int contextGroupId = | 993 int contextGroupId = currentContextGroupId(); |
958 m_inspector->contextGroupId(m_isolate->GetCurrentContext()); | |
959 if (!contextGroupId) return nullptr; | 994 if (!contextGroupId) return nullptr; |
960 | 995 |
961 size_t stackSize = | 996 size_t stackSize = |
962 fullStack ? V8StackTraceImpl::maxCallStackSizeToCapture : 1; | 997 fullStack ? V8StackTraceImpl::maxCallStackSizeToCapture : 1; |
963 if (m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) | 998 if (m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) |
964 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; | 999 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; |
965 | 1000 |
966 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); | 1001 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); |
967 } | 1002 } |
968 | 1003 |
| 1004 int V8Debugger::currentContextGroupId() { |
| 1005 if (!m_isolate->InContext()) return 0; |
| 1006 return m_inspector->contextGroupId(m_isolate->GetCurrentContext()); |
| 1007 } |
| 1008 |
969 } // namespace v8_inspector | 1009 } // namespace v8_inspector |
OLD | NEW |