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" |
11 #include "src/inspector/string-util.h" | 11 #include "src/inspector/string-util.h" |
12 #include "src/inspector/v8-debugger-agent-impl.h" | 12 #include "src/inspector/v8-debugger-agent-impl.h" |
13 #include "src/inspector/v8-inspector-impl.h" | 13 #include "src/inspector/v8-inspector-impl.h" |
14 #include "src/inspector/v8-internal-value-type.h" | 14 #include "src/inspector/v8-internal-value-type.h" |
15 #include "src/inspector/v8-stack-trace-impl.h" | 15 #include "src/inspector/v8-stack-trace-impl.h" |
16 #include "src/inspector/v8-value-copier.h" | 16 #include "src/inspector/v8-value-copier.h" |
17 | 17 |
18 #include "include/v8-util.h" | 18 #include "include/v8-util.h" |
19 | 19 |
20 namespace v8_inspector { | 20 namespace v8_inspector { |
21 | 21 |
22 namespace { | 22 namespace { |
23 | 23 |
24 // Based on DevTools frontend measurement, with asyncCallStackDepth = 4, | 24 static const int kMaxAsyncTaskStacks = 1024 * 1024; |
25 // average async call stack tail requires ~1 Kb. Let's reserve ~ 128 Mb | |
26 // for async stacks. | |
27 static const int kMaxAsyncTaskStacks = 128 * 1024; | |
28 | 25 |
29 inline v8::Local<v8::Boolean> v8Boolean(bool value, v8::Isolate* isolate) { | 26 inline v8::Local<v8::Boolean> v8Boolean(bool value, v8::Isolate* isolate) { |
30 return value ? v8::True(isolate) : v8::False(isolate); | 27 return value ? v8::True(isolate) : v8::False(isolate); |
31 } | 28 } |
32 | 29 |
33 V8DebuggerAgentImpl* agentForScript(V8InspectorImpl* inspector, | 30 V8DebuggerAgentImpl* agentForScript(V8InspectorImpl* inspector, |
34 v8::Local<v8::debug::Script> script) { | 31 v8::Local<v8::debug::Script> script) { |
35 v8::Local<v8::Value> contextData; | 32 v8::Local<v8::Value> contextData; |
36 if (!script->ContextData().ToLocal(&contextData) || !contextData->IsInt32()) { | 33 if (!script->ContextData().ToLocal(&contextData) || !contextData->IsInt32()) { |
37 return nullptr; | 34 return nullptr; |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
160 } | 157 } |
161 | 158 |
162 V8Debugger::V8Debugger(v8::Isolate* isolate, V8InspectorImpl* inspector) | 159 V8Debugger::V8Debugger(v8::Isolate* isolate, V8InspectorImpl* inspector) |
163 : m_isolate(isolate), | 160 : m_isolate(isolate), |
164 m_inspector(inspector), | 161 m_inspector(inspector), |
165 m_enableCount(0), | 162 m_enableCount(0), |
166 m_breakpointsActivated(true), | 163 m_breakpointsActivated(true), |
167 m_runningNestedMessageLoop(false), | 164 m_runningNestedMessageLoop(false), |
168 m_ignoreScriptParsedEventsCounter(0), | 165 m_ignoreScriptParsedEventsCounter(0), |
169 m_maxAsyncCallStacks(kMaxAsyncTaskStacks), | 166 m_maxAsyncCallStacks(kMaxAsyncTaskStacks), |
170 m_lastTaskId(0), | |
171 m_maxAsyncCallStackDepth(0), | 167 m_maxAsyncCallStackDepth(0), |
172 m_pauseOnExceptionsState(v8::debug::NoBreakOnException), | 168 m_pauseOnExceptionsState(v8::debug::NoBreakOnException), |
173 m_wasmTranslation(isolate) {} | 169 m_wasmTranslation(isolate) {} |
174 | 170 |
175 V8Debugger::~V8Debugger() {} | 171 V8Debugger::~V8Debugger() {} |
176 | 172 |
177 void V8Debugger::enable() { | 173 void V8Debugger::enable() { |
178 if (m_enableCount++) return; | 174 if (m_enableCount++) return; |
179 DCHECK(!enabled()); | 175 DCHECK(!enabled()); |
180 v8::HandleScope scope(m_isolate); | 176 v8::HandleScope scope(m_isolate); |
(...skipping 474 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
655 break; | 651 break; |
656 case v8::debug::kDebugEnqueueAsyncFunction: | 652 case v8::debug::kDebugEnqueueAsyncFunction: |
657 asyncTaskScheduledForStack("async function", task, true); | 653 asyncTaskScheduledForStack("async function", task, true); |
658 break; | 654 break; |
659 case v8::debug::kDebugEnqueuePromiseResolve: | 655 case v8::debug::kDebugEnqueuePromiseResolve: |
660 asyncTaskScheduledForStack("Promise.resolve", task, true); | 656 asyncTaskScheduledForStack("Promise.resolve", task, true); |
661 break; | 657 break; |
662 case v8::debug::kDebugEnqueuePromiseReject: | 658 case v8::debug::kDebugEnqueuePromiseReject: |
663 asyncTaskScheduledForStack("Promise.reject", task, true); | 659 asyncTaskScheduledForStack("Promise.reject", task, true); |
664 break; | 660 break; |
665 case v8::debug::kDebugPromiseCollected: | |
666 asyncTaskCanceledForStack(task); | |
667 asyncTaskCanceledForStepping(task); | |
668 break; | |
669 case v8::debug::kDebugWillHandle: | 661 case v8::debug::kDebugWillHandle: |
670 asyncTaskStartedForStack(task); | 662 asyncTaskStartedForStack(task); |
671 asyncTaskStartedForStepping(task); | 663 asyncTaskStartedForStepping(task); |
672 break; | 664 break; |
673 case v8::debug::kDebugDidHandle: | 665 case v8::debug::kDebugDidHandle: |
674 asyncTaskFinishedForStack(task); | 666 asyncTaskFinishedForStack(task); |
675 asyncTaskFinishedForStepping(task); | 667 asyncTaskFinishedForStepping(task); |
676 break; | 668 break; |
| 669 case v8::debug::kDebugPromiseCollected: |
| 670 asyncTaskCanceledForStack(task); |
| 671 asyncTaskCanceledForStepping(task); |
| 672 break; |
677 } | 673 } |
678 } | 674 } |
679 | 675 |
680 V8StackTraceImpl* V8Debugger::currentAsyncCallChain() { | 676 std::shared_ptr<AsyncStackTrace> V8Debugger::currentAsyncParent() { |
681 if (!m_currentStacks.size()) return nullptr; | 677 return m_currentAsyncParent.empty() ? nullptr : m_currentAsyncParent.back(); |
682 return m_currentStacks.back().get(); | |
683 } | 678 } |
684 | 679 |
685 V8StackTraceImpl* V8Debugger::currentAsyncTaskCreationStack() { | 680 std::shared_ptr<AsyncStackTrace> V8Debugger::currentAsyncCreation() { |
686 if (!m_currentCreationStacks.size()) return nullptr; | 681 return m_currentAsyncCreation.empty() ? nullptr |
687 return m_currentCreationStacks.back().get(); | 682 : m_currentAsyncCreation.back(); |
688 } | 683 } |
689 | 684 |
690 void V8Debugger::compileDebuggerScript() { | 685 void V8Debugger::compileDebuggerScript() { |
691 if (!m_debuggerScript.IsEmpty()) { | 686 if (!m_debuggerScript.IsEmpty()) { |
692 UNREACHABLE(); | 687 UNREACHABLE(); |
693 return; | 688 return; |
694 } | 689 } |
695 | 690 |
696 v8::HandleScope scope(m_isolate); | 691 v8::HandleScope scope(m_isolate); |
697 v8::Context::Scope contextScope(debuggerContext()); | 692 v8::Context::Scope contextScope(debuggerContext()); |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
818 functionScopes(context, function).ToLocal(&scopes)) { | 813 functionScopes(context, function).ToLocal(&scopes)) { |
819 createDataProperty(context, properties, properties->Length(), | 814 createDataProperty(context, properties, properties->Length(), |
820 toV8StringInternalized(m_isolate, "[[Scopes]]")); | 815 toV8StringInternalized(m_isolate, "[[Scopes]]")); |
821 createDataProperty(context, properties, properties->Length(), scopes); | 816 createDataProperty(context, properties, properties->Length(), scopes); |
822 } | 817 } |
823 } | 818 } |
824 return properties; | 819 return properties; |
825 } | 820 } |
826 | 821 |
827 std::unique_ptr<V8StackTraceImpl> V8Debugger::createStackTrace( | 822 std::unique_ptr<V8StackTraceImpl> V8Debugger::createStackTrace( |
828 v8::Local<v8::StackTrace> stackTrace) { | 823 v8::Local<v8::StackTrace> v8StackTrace) { |
829 return V8StackTraceImpl::create(this, currentContextGroupId(), stackTrace, | 824 return V8StackTraceImpl::create(this, currentContextGroupId(), v8StackTrace, |
830 V8StackTraceImpl::maxCallStackSizeToCapture); | 825 V8StackTraceImpl::maxCallStackSizeToCapture); |
831 } | 826 } |
832 | 827 |
833 void V8Debugger::setAsyncCallStackDepth(V8DebuggerAgentImpl* agent, int depth) { | 828 void V8Debugger::setAsyncCallStackDepth(V8DebuggerAgentImpl* agent, int depth) { |
834 if (depth <= 0) | 829 if (depth <= 0) |
835 m_maxAsyncCallStackDepthMap.erase(agent); | 830 m_maxAsyncCallStackDepthMap.erase(agent); |
836 else | 831 else |
837 m_maxAsyncCallStackDepthMap[agent] = depth; | 832 m_maxAsyncCallStackDepthMap[agent] = depth; |
838 | 833 |
839 int maxAsyncCallStackDepth = 0; | 834 int maxAsyncCallStackDepth = 0; |
840 for (const auto& pair : m_maxAsyncCallStackDepthMap) { | 835 for (const auto& pair : m_maxAsyncCallStackDepthMap) { |
841 if (pair.second > maxAsyncCallStackDepth) | 836 if (pair.second > maxAsyncCallStackDepth) |
842 maxAsyncCallStackDepth = pair.second; | 837 maxAsyncCallStackDepth = pair.second; |
843 } | 838 } |
844 | 839 |
845 if (m_maxAsyncCallStackDepth == maxAsyncCallStackDepth) return; | 840 if (m_maxAsyncCallStackDepth == maxAsyncCallStackDepth) return; |
846 m_maxAsyncCallStackDepth = maxAsyncCallStackDepth; | 841 m_maxAsyncCallStackDepth = maxAsyncCallStackDepth; |
847 if (!maxAsyncCallStackDepth) allAsyncTasksCanceled(); | 842 if (!maxAsyncCallStackDepth) allAsyncTasksCanceled(); |
848 } | 843 } |
849 | 844 |
850 void V8Debugger::registerAsyncTaskIfNeeded(void* task) { | |
851 if (m_taskToId.find(task) != m_taskToId.end()) return; | |
852 | |
853 int id = ++m_lastTaskId; | |
854 m_taskToId[task] = id; | |
855 m_idToTask[id] = task; | |
856 if (static_cast<int>(m_idToTask.size()) > m_maxAsyncCallStacks) { | |
857 void* taskToRemove = m_idToTask.begin()->second; | |
858 asyncTaskCanceledForStack(taskToRemove); | |
859 } | |
860 } | |
861 | |
862 void V8Debugger::asyncTaskCreatedForStack(void* task, void* parentTask) { | 845 void V8Debugger::asyncTaskCreatedForStack(void* task, void* parentTask) { |
863 if (!m_maxAsyncCallStackDepth) return; | 846 if (!m_maxAsyncCallStackDepth) return; |
864 if (parentTask) m_parentTask[task] = parentTask; | 847 if (parentTask) m_parentTask[task] = parentTask; |
865 v8::HandleScope scope(m_isolate); | 848 v8::HandleScope scope(m_isolate); |
866 // We don't need to pass context group id here because we get this callback | 849 std::shared_ptr<AsyncStackTrace> asyncCreation = |
867 // from V8 for promise events only. | 850 AsyncStackTrace::capture(this, currentContextGroupId(), String16(), 1); |
868 // Passing one as maxStackSize forces no async chain for the new stack and | 851 // Passing one as maxStackSize forces no async chain for the new stack. |
869 // allows us to not grow exponentially. | 852 if (asyncCreation && !asyncCreation->isEmpty()) { |
870 std::unique_ptr<V8StackTraceImpl> creationStack = | 853 m_asyncTaskCreationStacks[task] = asyncCreation; |
871 V8StackTraceImpl::capture(this, 0, 1, String16()); | 854 m_allAsyncStacks.push_back(asyncCreation); |
872 if (creationStack && !creationStack->isEmpty()) { | 855 ++m_asyncStacksCount; |
873 m_asyncTaskCreationStacks[task] = std::move(creationStack); | 856 collectOldAsyncStacksIfNeeded(); |
874 registerAsyncTaskIfNeeded(task); | |
875 } | 857 } |
876 } | 858 } |
877 | 859 |
878 void V8Debugger::asyncTaskScheduled(const StringView& taskName, void* task, | 860 void V8Debugger::asyncTaskScheduled(const StringView& taskName, void* task, |
879 bool recurring) { | 861 bool recurring) { |
880 asyncTaskScheduledForStack(toString16(taskName), task, recurring); | 862 asyncTaskScheduledForStack(toString16(taskName), task, recurring); |
881 asyncTaskCandidateForStepping(task); | 863 asyncTaskCandidateForStepping(task); |
882 } | 864 } |
883 | 865 |
884 void V8Debugger::asyncTaskCanceled(void* task) { | 866 void V8Debugger::asyncTaskCanceled(void* task) { |
885 asyncTaskCanceledForStack(task); | 867 asyncTaskCanceledForStack(task); |
886 asyncTaskCanceledForStepping(task); | 868 asyncTaskCanceledForStepping(task); |
887 } | 869 } |
888 | 870 |
889 void V8Debugger::asyncTaskStarted(void* task) { | 871 void V8Debugger::asyncTaskStarted(void* task) { |
890 asyncTaskStartedForStack(task); | 872 asyncTaskStartedForStack(task); |
891 asyncTaskStartedForStepping(task); | 873 asyncTaskStartedForStepping(task); |
892 } | 874 } |
893 | 875 |
894 void V8Debugger::asyncTaskFinished(void* task) { | 876 void V8Debugger::asyncTaskFinished(void* task) { |
895 asyncTaskFinishedForStack(task); | 877 asyncTaskFinishedForStack(task); |
896 asyncTaskFinishedForStepping(task); | 878 asyncTaskFinishedForStepping(task); |
897 } | 879 } |
898 | 880 |
899 void V8Debugger::asyncTaskScheduledForStack(const String16& taskName, | 881 void V8Debugger::asyncTaskScheduledForStack(const String16& taskName, |
900 void* task, bool recurring) { | 882 void* task, bool recurring) { |
901 if (!m_maxAsyncCallStackDepth) return; | 883 if (!m_maxAsyncCallStackDepth) return; |
902 v8::HandleScope scope(m_isolate); | 884 v8::HandleScope scope(m_isolate); |
903 std::unique_ptr<V8StackTraceImpl> chain = V8StackTraceImpl::capture( | 885 std::shared_ptr<AsyncStackTrace> asyncStack = |
904 this, currentContextGroupId(), | 886 AsyncStackTrace::capture(this, currentContextGroupId(), taskName, |
905 V8StackTraceImpl::maxCallStackSizeToCapture, taskName); | 887 V8StackTraceImpl::maxCallStackSizeToCapture); |
906 if (chain) { | 888 if (asyncStack) { |
907 m_asyncTaskStacks[task] = std::move(chain); | 889 m_asyncTaskStacks[task] = asyncStack; |
908 if (recurring) m_recurringTasks.insert(task); | 890 if (recurring) m_recurringTasks.insert(task); |
909 registerAsyncTaskIfNeeded(task); | 891 |
| 892 m_allAsyncStacks.push_back(asyncStack); |
| 893 ++m_asyncStacksCount; |
| 894 collectOldAsyncStacksIfNeeded(); |
910 } | 895 } |
911 } | 896 } |
912 | 897 |
913 void V8Debugger::asyncTaskCanceledForStack(void* task) { | 898 void V8Debugger::asyncTaskCanceledForStack(void* task) { |
914 if (!m_maxAsyncCallStackDepth) return; | 899 if (!m_maxAsyncCallStackDepth) return; |
915 m_asyncTaskStacks.erase(task); | 900 m_asyncTaskStacks.erase(task); |
916 m_recurringTasks.erase(task); | 901 m_recurringTasks.erase(task); |
917 m_parentTask.erase(task); | 902 m_parentTask.erase(task); |
918 m_asyncTaskCreationStacks.erase(task); | 903 m_asyncTaskCreationStacks.erase(task); |
919 auto it = m_taskToId.find(task); | |
920 if (it == m_taskToId.end()) return; | |
921 m_idToTask.erase(it->second); | |
922 m_taskToId.erase(it); | |
923 } | 904 } |
924 | 905 |
925 void V8Debugger::asyncTaskStartedForStack(void* task) { | 906 void V8Debugger::asyncTaskStartedForStack(void* task) { |
926 if (!m_maxAsyncCallStackDepth) return; | 907 if (!m_maxAsyncCallStackDepth) return; |
927 m_currentTasks.push_back(task); | 908 m_currentTasks.push_back(task); |
928 auto parentIt = m_parentTask.find(task); | 909 auto parentIt = m_parentTask.find(task); |
929 AsyncTaskToStackTrace::iterator stackIt = m_asyncTaskStacks.find( | 910 AsyncTaskToStackTrace::iterator stackIt = m_asyncTaskStacks.find( |
930 parentIt == m_parentTask.end() ? task : parentIt->second); | 911 parentIt == m_parentTask.end() ? task : parentIt->second); |
931 // Needs to support following order of events: | 912 // Needs to support following order of events: |
932 // - asyncTaskScheduled | 913 // - asyncTaskScheduled |
933 // <-- attached here --> | 914 // <-- attached here --> |
934 // - asyncTaskStarted | 915 // - asyncTaskStarted |
935 // - asyncTaskCanceled <-- canceled before finished | 916 // - asyncTaskCanceled <-- canceled before finished |
936 // <-- async stack requested here --> | 917 // <-- async stack requested here --> |
937 // - asyncTaskFinished | 918 // - asyncTaskFinished |
938 std::unique_ptr<V8StackTraceImpl> stack; | 919 std::shared_ptr<AsyncStackTrace> asyncParent; |
939 if (stackIt != m_asyncTaskStacks.end() && stackIt->second) | 920 if (stackIt != m_asyncTaskStacks.end()) asyncParent = stackIt->second.lock(); |
940 stack = stackIt->second->cloneImpl(); | |
941 auto itCreation = m_asyncTaskCreationStacks.find(task); | 921 auto itCreation = m_asyncTaskCreationStacks.find(task); |
942 if (stack && itCreation != m_asyncTaskCreationStacks.end()) { | 922 if (asyncParent && itCreation != m_asyncTaskCreationStacks.end()) { |
943 m_currentCreationStacks.push_back(itCreation->second->cloneImpl()); | 923 m_currentAsyncCreation.push_back(itCreation->second.lock()); |
944 } else { | 924 } else { |
945 m_currentCreationStacks.push_back(nullptr); | 925 m_currentAsyncCreation.push_back(nullptr); |
946 } | 926 } |
947 m_currentStacks.push_back(std::move(stack)); | 927 m_currentAsyncParent.push_back(asyncParent); |
948 } | 928 } |
949 | 929 |
950 void V8Debugger::asyncTaskFinishedForStack(void* task) { | 930 void V8Debugger::asyncTaskFinishedForStack(void* task) { |
951 if (!m_maxAsyncCallStackDepth) return; | 931 if (!m_maxAsyncCallStackDepth) return; |
952 // We could start instrumenting half way and the stack is empty. | 932 // We could start instrumenting half way and the stack is empty. |
953 if (!m_currentStacks.size()) return; | 933 if (!m_currentTasks.size()) return; |
954 DCHECK(m_currentTasks.back() == task); | 934 DCHECK(m_currentTasks.back() == task); |
955 m_currentTasks.pop_back(); | 935 m_currentTasks.pop_back(); |
956 | 936 |
957 DCHECK(m_currentStacks.size() == m_currentCreationStacks.size()); | 937 DCHECK(m_currentAsyncParent.size() == m_currentAsyncCreation.size()); |
958 m_currentStacks.pop_back(); | 938 m_currentAsyncParent.pop_back(); |
959 m_currentCreationStacks.pop_back(); | 939 m_currentAsyncCreation.pop_back(); |
| 940 |
960 if (m_recurringTasks.find(task) == m_recurringTasks.end()) { | 941 if (m_recurringTasks.find(task) == m_recurringTasks.end()) { |
961 asyncTaskCanceledForStack(task); | 942 asyncTaskCanceledForStack(task); |
962 } | 943 } |
963 } | 944 } |
964 | 945 |
965 void V8Debugger::asyncTaskCandidateForStepping(void* task) { | 946 void V8Debugger::asyncTaskCandidateForStepping(void* task) { |
966 if (!m_stepIntoAsyncCallback) return; | 947 if (!m_stepIntoAsyncCallback) return; |
967 DCHECK(m_targetContextGroupId); | 948 DCHECK(m_targetContextGroupId); |
968 if (currentContextGroupId() != m_targetContextGroupId) return; | 949 if (currentContextGroupId() != m_targetContextGroupId) return; |
969 m_taskWithScheduledBreak = task; | 950 m_taskWithScheduledBreak = task; |
(...skipping 16 matching lines...) Expand all Loading... |
986 } | 967 } |
987 | 968 |
988 void V8Debugger::asyncTaskCanceledForStepping(void* task) { | 969 void V8Debugger::asyncTaskCanceledForStepping(void* task) { |
989 if (task != m_taskWithScheduledBreak) return; | 970 if (task != m_taskWithScheduledBreak) return; |
990 m_taskWithScheduledBreak = nullptr; | 971 m_taskWithScheduledBreak = nullptr; |
991 } | 972 } |
992 | 973 |
993 void V8Debugger::allAsyncTasksCanceled() { | 974 void V8Debugger::allAsyncTasksCanceled() { |
994 m_asyncTaskStacks.clear(); | 975 m_asyncTaskStacks.clear(); |
995 m_recurringTasks.clear(); | 976 m_recurringTasks.clear(); |
996 m_currentStacks.clear(); | 977 m_currentAsyncParent.clear(); |
997 m_currentCreationStacks.clear(); | 978 m_currentAsyncCreation.clear(); |
998 m_currentTasks.clear(); | 979 m_currentTasks.clear(); |
999 m_parentTask.clear(); | 980 m_parentTask.clear(); |
1000 m_asyncTaskCreationStacks.clear(); | 981 m_asyncTaskCreationStacks.clear(); |
1001 m_idToTask.clear(); | 982 |
1002 m_taskToId.clear(); | 983 m_allAsyncStacks.clear(); |
1003 m_lastTaskId = 0; | 984 m_asyncStacksCount = 0; |
1004 } | 985 } |
1005 | 986 |
1006 void V8Debugger::muteScriptParsedEvents() { | 987 void V8Debugger::muteScriptParsedEvents() { |
1007 ++m_ignoreScriptParsedEventsCounter; | 988 ++m_ignoreScriptParsedEventsCounter; |
1008 } | 989 } |
1009 | 990 |
1010 void V8Debugger::unmuteScriptParsedEvents() { | 991 void V8Debugger::unmuteScriptParsedEvents() { |
1011 --m_ignoreScriptParsedEventsCounter; | 992 --m_ignoreScriptParsedEventsCounter; |
1012 DCHECK_GE(m_ignoreScriptParsedEventsCounter, 0); | 993 DCHECK_GE(m_ignoreScriptParsedEventsCounter, 0); |
1013 } | 994 } |
1014 | 995 |
1015 std::unique_ptr<V8StackTraceImpl> V8Debugger::captureStackTrace( | 996 std::unique_ptr<V8StackTraceImpl> V8Debugger::captureStackTrace( |
1016 bool fullStack) { | 997 bool fullStack) { |
1017 if (!m_isolate->InContext()) return nullptr; | 998 if (!m_isolate->InContext()) return nullptr; |
1018 | 999 |
1019 v8::HandleScope handles(m_isolate); | 1000 v8::HandleScope handles(m_isolate); |
1020 int contextGroupId = currentContextGroupId(); | 1001 int contextGroupId = currentContextGroupId(); |
1021 if (!contextGroupId) return nullptr; | 1002 if (!contextGroupId) return nullptr; |
1022 | 1003 |
1023 size_t stackSize = | 1004 int stackSize = 1; |
1024 fullStack ? V8StackTraceImpl::maxCallStackSizeToCapture : 1; | 1005 if (fullStack || m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) { |
1025 if (m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) | |
1026 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; | 1006 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; |
1027 | 1007 } |
1028 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); | 1008 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); |
1029 } | 1009 } |
1030 | 1010 |
1031 int V8Debugger::currentContextGroupId() { | 1011 int V8Debugger::currentContextGroupId() { |
1032 if (!m_isolate->InContext()) return 0; | 1012 if (!m_isolate->InContext()) return 0; |
1033 return m_inspector->contextGroupId(m_isolate->GetCurrentContext()); | 1013 return m_inspector->contextGroupId(m_isolate->GetCurrentContext()); |
1034 } | 1014 } |
1035 | 1015 |
| 1016 void V8Debugger::collectOldAsyncStacksIfNeeded() { |
| 1017 if (m_asyncStacksCount <= m_maxAsyncCallStacks) return; |
| 1018 int halfOfLimitRoundedUp = |
| 1019 m_maxAsyncCallStacks / 2 + m_maxAsyncCallStacks % 2; |
| 1020 while (m_asyncStacksCount > halfOfLimitRoundedUp) { |
| 1021 m_allAsyncStacks.pop_front(); |
| 1022 --m_asyncStacksCount; |
| 1023 } |
| 1024 removeOldAsyncTasks(m_asyncTaskStacks); |
| 1025 removeOldAsyncTasks(m_asyncTaskCreationStacks); |
| 1026 } |
| 1027 |
| 1028 void V8Debugger::removeOldAsyncTasks(AsyncTaskToStackTrace& map) { |
| 1029 AsyncTaskToStackTrace cleanCopy; |
| 1030 for (auto it : map) { |
| 1031 if (!it.second.expired()) cleanCopy.insert(it); |
| 1032 } |
| 1033 map.swap(cleanCopy); |
| 1034 } |
| 1035 |
| 1036 void V8Debugger::setMaxAsyncTaskStacksForTest(int limit) { |
| 1037 m_maxAsyncCallStacks = 0; |
| 1038 collectOldAsyncStacksIfNeeded(); |
| 1039 m_maxAsyncCallStacks = limit; |
| 1040 } |
| 1041 |
1036 } // namespace v8_inspector | 1042 } // namespace v8_inspector |
OLD | NEW |