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