| 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 |