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 static const char v8AsyncTaskEventEnqueue[] = "enqueue"; | 23 static const char v8AsyncTaskEventEnqueue[] = "enqueue"; |
24 static const char v8AsyncTaskEventEnqueueRecurring[] = "enqueueRecurring"; | 24 static const char v8AsyncTaskEventEnqueueRecurring[] = "enqueueRecurring"; |
25 static const char v8AsyncTaskEventWillHandle[] = "willHandle"; | 25 static const char v8AsyncTaskEventWillHandle[] = "willHandle"; |
26 static const char v8AsyncTaskEventDidHandle[] = "didHandle"; | 26 static const char v8AsyncTaskEventDidHandle[] = "didHandle"; |
27 static const char v8AsyncTaskEventCancel[] = "cancel"; | 27 static const char v8AsyncTaskEventCancel[] = "cancel"; |
28 | 28 |
| 29 // Based on DevTools frontend measurement, with asyncCallStackDepth = 4, |
| 30 // average async call stack tail requires ~1 Kb. Let's reserve ~ 128 Mb |
| 31 // for async stacks. |
| 32 static const int kMaxAsyncTaskStacks = 128 * 1024; |
| 33 |
29 inline v8::Local<v8::Boolean> v8Boolean(bool value, v8::Isolate* isolate) { | 34 inline v8::Local<v8::Boolean> v8Boolean(bool value, v8::Isolate* isolate) { |
30 return value ? v8::True(isolate) : v8::False(isolate); | 35 return value ? v8::True(isolate) : v8::False(isolate); |
31 } | 36 } |
32 | 37 |
33 } // namespace | 38 } // namespace |
34 | 39 |
35 static bool inLiveEditScope = false; | 40 static bool inLiveEditScope = false; |
36 | 41 |
37 v8::MaybeLocal<v8::Value> V8Debugger::callDebuggerMethod( | 42 v8::MaybeLocal<v8::Value> V8Debugger::callDebuggerMethod( |
38 const char* functionName, int argc, v8::Local<v8::Value> argv[]) { | 43 const char* functionName, int argc, v8::Local<v8::Value> argv[]) { |
39 v8::MicrotasksScope microtasks(m_isolate, | 44 v8::MicrotasksScope microtasks(m_isolate, |
40 v8::MicrotasksScope::kDoNotRunMicrotasks); | 45 v8::MicrotasksScope::kDoNotRunMicrotasks); |
41 DCHECK(m_isolate->InContext()); | 46 DCHECK(m_isolate->InContext()); |
42 v8::Local<v8::Context> context = m_isolate->GetCurrentContext(); | 47 v8::Local<v8::Context> context = m_isolate->GetCurrentContext(); |
43 v8::Local<v8::Object> debuggerScript = m_debuggerScript.Get(m_isolate); | 48 v8::Local<v8::Object> debuggerScript = m_debuggerScript.Get(m_isolate); |
44 v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast( | 49 v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast( |
45 debuggerScript | 50 debuggerScript |
46 ->Get(context, toV8StringInternalized(m_isolate, functionName)) | 51 ->Get(context, toV8StringInternalized(m_isolate, functionName)) |
47 .ToLocalChecked()); | 52 .ToLocalChecked()); |
48 return function->Call(context, debuggerScript, argc, argv); | 53 return function->Call(context, debuggerScript, argc, argv); |
49 } | 54 } |
50 | 55 |
51 V8Debugger::V8Debugger(v8::Isolate* isolate, V8InspectorImpl* inspector) | 56 V8Debugger::V8Debugger(v8::Isolate* isolate, V8InspectorImpl* inspector) |
52 : m_isolate(isolate), | 57 : m_isolate(isolate), |
53 m_inspector(inspector), | 58 m_inspector(inspector), |
54 m_enableCount(0), | 59 m_enableCount(0), |
55 m_breakpointsActivated(true), | 60 m_breakpointsActivated(true), |
56 m_runningNestedMessageLoop(false), | 61 m_runningNestedMessageLoop(false), |
57 m_ignoreScriptParsedEventsCounter(0), | 62 m_ignoreScriptParsedEventsCounter(0), |
| 63 m_maxAsyncCallStacks(kMaxAsyncTaskStacks), |
| 64 m_lastTaskId(0), |
58 m_maxAsyncCallStackDepth(0), | 65 m_maxAsyncCallStackDepth(0), |
59 m_pauseOnExceptionsState(v8::debug::NoBreakOnException), | 66 m_pauseOnExceptionsState(v8::debug::NoBreakOnException), |
60 m_wasmTranslation(isolate) {} | 67 m_wasmTranslation(isolate) {} |
61 | 68 |
62 V8Debugger::~V8Debugger() {} | 69 V8Debugger::~V8Debugger() {} |
63 | 70 |
64 void V8Debugger::enable() { | 71 void V8Debugger::enable() { |
65 if (m_enableCount++) return; | 72 if (m_enableCount++) return; |
66 DCHECK(!enabled()); | 73 DCHECK(!enabled()); |
67 v8::HandleScope scope(m_isolate); | 74 v8::HandleScope scope(m_isolate); |
(...skipping 826 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
894 int contextGroupId = | 901 int contextGroupId = |
895 m_isolate->InContext() | 902 m_isolate->InContext() |
896 ? m_inspector->contextGroupId(m_isolate->GetCurrentContext()) | 903 ? m_inspector->contextGroupId(m_isolate->GetCurrentContext()) |
897 : 0; | 904 : 0; |
898 std::unique_ptr<V8StackTraceImpl> chain = V8StackTraceImpl::capture( | 905 std::unique_ptr<V8StackTraceImpl> chain = V8StackTraceImpl::capture( |
899 this, contextGroupId, V8StackTraceImpl::maxCallStackSizeToCapture, | 906 this, contextGroupId, V8StackTraceImpl::maxCallStackSizeToCapture, |
900 taskName); | 907 taskName); |
901 if (chain) { | 908 if (chain) { |
902 m_asyncTaskStacks[task] = std::move(chain); | 909 m_asyncTaskStacks[task] = std::move(chain); |
903 if (recurring) m_recurringTasks.insert(task); | 910 if (recurring) m_recurringTasks.insert(task); |
| 911 int id = ++m_lastTaskId; |
| 912 m_taskToId[task] = id; |
| 913 m_idToTask[id] = task; |
| 914 if (static_cast<int>(m_idToTask.size()) > m_maxAsyncCallStacks) { |
| 915 void* taskToRemove = m_idToTask.begin()->second; |
| 916 asyncTaskCanceled(taskToRemove); |
| 917 } |
904 } | 918 } |
905 } | 919 } |
906 | 920 |
907 void V8Debugger::asyncTaskCanceled(void* task) { | 921 void V8Debugger::asyncTaskCanceled(void* task) { |
908 if (!m_maxAsyncCallStackDepth) return; | 922 if (!m_maxAsyncCallStackDepth) return; |
909 m_asyncTaskStacks.erase(task); | 923 m_asyncTaskStacks.erase(task); |
910 m_recurringTasks.erase(task); | 924 m_recurringTasks.erase(task); |
| 925 auto it = m_taskToId.find(task); |
| 926 if (it == m_taskToId.end()) return; |
| 927 m_idToTask.erase(it->second); |
| 928 m_taskToId.erase(it); |
911 } | 929 } |
912 | 930 |
913 void V8Debugger::asyncTaskStarted(void* task) { | 931 void V8Debugger::asyncTaskStarted(void* task) { |
914 if (!m_maxAsyncCallStackDepth) return; | 932 if (!m_maxAsyncCallStackDepth) return; |
915 m_currentTasks.push_back(task); | 933 m_currentTasks.push_back(task); |
916 AsyncTaskToStackTrace::iterator stackIt = m_asyncTaskStacks.find(task); | 934 AsyncTaskToStackTrace::iterator stackIt = m_asyncTaskStacks.find(task); |
917 // Needs to support following order of events: | 935 // Needs to support following order of events: |
918 // - asyncTaskScheduled | 936 // - asyncTaskScheduled |
919 // <-- attached here --> | 937 // <-- attached here --> |
920 // - asyncTaskStarted | 938 // - asyncTaskStarted |
921 // - asyncTaskCanceled <-- canceled before finished | 939 // - asyncTaskCanceled <-- canceled before finished |
922 // <-- async stack requested here --> | 940 // <-- async stack requested here --> |
923 // - asyncTaskFinished | 941 // - asyncTaskFinished |
924 std::unique_ptr<V8StackTraceImpl> stack; | 942 std::unique_ptr<V8StackTraceImpl> stack; |
925 if (stackIt != m_asyncTaskStacks.end() && stackIt->second) | 943 if (stackIt != m_asyncTaskStacks.end() && stackIt->second) |
926 stack = stackIt->second->cloneImpl(); | 944 stack = stackIt->second->cloneImpl(); |
927 m_currentStacks.push_back(std::move(stack)); | 945 m_currentStacks.push_back(std::move(stack)); |
928 } | 946 } |
929 | 947 |
930 void V8Debugger::asyncTaskFinished(void* task) { | 948 void V8Debugger::asyncTaskFinished(void* task) { |
931 if (!m_maxAsyncCallStackDepth) return; | 949 if (!m_maxAsyncCallStackDepth) return; |
932 // We could start instrumenting half way and the stack is empty. | 950 // We could start instrumenting half way and the stack is empty. |
933 if (!m_currentStacks.size()) return; | 951 if (!m_currentStacks.size()) return; |
934 | 952 |
935 DCHECK(m_currentTasks.back() == task); | 953 DCHECK(m_currentTasks.back() == task); |
936 m_currentTasks.pop_back(); | 954 m_currentTasks.pop_back(); |
937 | 955 |
938 m_currentStacks.pop_back(); | 956 m_currentStacks.pop_back(); |
939 if (m_recurringTasks.find(task) == m_recurringTasks.end()) | 957 if (m_recurringTasks.find(task) == m_recurringTasks.end()) { |
940 m_asyncTaskStacks.erase(task); | 958 m_asyncTaskStacks.erase(task); |
| 959 auto it = m_taskToId.find(task); |
| 960 if (it == m_taskToId.end()) return; |
| 961 m_idToTask.erase(it->second); |
| 962 m_taskToId.erase(it); |
| 963 } |
941 } | 964 } |
942 | 965 |
943 void V8Debugger::allAsyncTasksCanceled() { | 966 void V8Debugger::allAsyncTasksCanceled() { |
944 m_asyncTaskStacks.clear(); | 967 m_asyncTaskStacks.clear(); |
945 m_recurringTasks.clear(); | 968 m_recurringTasks.clear(); |
946 m_currentStacks.clear(); | 969 m_currentStacks.clear(); |
947 m_currentTasks.clear(); | 970 m_currentTasks.clear(); |
| 971 m_idToTask.clear(); |
| 972 m_taskToId.clear(); |
| 973 m_lastTaskId = 0; |
948 } | 974 } |
949 | 975 |
950 void V8Debugger::muteScriptParsedEvents() { | 976 void V8Debugger::muteScriptParsedEvents() { |
951 ++m_ignoreScriptParsedEventsCounter; | 977 ++m_ignoreScriptParsedEventsCounter; |
952 } | 978 } |
953 | 979 |
954 void V8Debugger::unmuteScriptParsedEvents() { | 980 void V8Debugger::unmuteScriptParsedEvents() { |
955 --m_ignoreScriptParsedEventsCounter; | 981 --m_ignoreScriptParsedEventsCounter; |
956 DCHECK_GE(m_ignoreScriptParsedEventsCounter, 0); | 982 DCHECK_GE(m_ignoreScriptParsedEventsCounter, 0); |
957 } | 983 } |
958 | 984 |
959 std::unique_ptr<V8StackTraceImpl> V8Debugger::captureStackTrace( | 985 std::unique_ptr<V8StackTraceImpl> V8Debugger::captureStackTrace( |
960 bool fullStack) { | 986 bool fullStack) { |
961 if (!m_isolate->InContext()) return nullptr; | 987 if (!m_isolate->InContext()) return nullptr; |
962 | 988 |
963 v8::HandleScope handles(m_isolate); | 989 v8::HandleScope handles(m_isolate); |
964 int contextGroupId = | 990 int contextGroupId = |
965 m_inspector->contextGroupId(m_isolate->GetCurrentContext()); | 991 m_inspector->contextGroupId(m_isolate->GetCurrentContext()); |
966 if (!contextGroupId) return nullptr; | 992 if (!contextGroupId) return nullptr; |
967 | 993 |
968 size_t stackSize = | 994 size_t stackSize = |
969 fullStack ? V8StackTraceImpl::maxCallStackSizeToCapture : 1; | 995 fullStack ? V8StackTraceImpl::maxCallStackSizeToCapture : 1; |
970 if (m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) | 996 if (m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) |
971 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; | 997 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; |
972 | 998 |
973 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); | 999 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); |
974 } | 1000 } |
975 | 1001 |
976 } // namespace v8_inspector | 1002 } // namespace v8_inspector |
OLD | NEW |