| 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 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 291 m_executionState.Clear(); | 291 m_executionState.Clear(); |
| 292 } | 292 } |
| 293 | 293 |
| 294 void V8Debugger::stepIntoStatement() { | 294 void V8Debugger::stepIntoStatement() { |
| 295 DCHECK(isPaused()); | 295 DCHECK(isPaused()); |
| 296 DCHECK(!m_executionState.IsEmpty()); | 296 DCHECK(!m_executionState.IsEmpty()); |
| 297 v8::debug::PrepareStep(m_isolate, v8::debug::StepIn); | 297 v8::debug::PrepareStep(m_isolate, v8::debug::StepIn); |
| 298 continueProgram(); | 298 continueProgram(); |
| 299 } | 299 } |
| 300 | 300 |
| 301 Response V8Debugger::stepIntoAsync() { |
| 302 DCHECK(isPaused()); |
| 303 DCHECK(!m_executionState.IsEmpty()); |
| 304 if (!m_currentCreatedAsyncTask) { |
| 305 return Response::Error("No scheduled chained callback"); |
| 306 } |
| 307 m_asyncTasksWithScheduledBreak.insert(m_currentCreatedAsyncTask); |
| 308 v8::debug::ClearStepping(m_isolate); |
| 309 continueProgram(); |
| 310 return Response::OK(); |
| 311 } |
| 312 |
| 301 void V8Debugger::stepOverStatement() { | 313 void V8Debugger::stepOverStatement() { |
| 302 DCHECK(isPaused()); | 314 DCHECK(isPaused()); |
| 303 DCHECK(!m_executionState.IsEmpty()); | 315 DCHECK(!m_executionState.IsEmpty()); |
| 304 v8::debug::PrepareStep(m_isolate, v8::debug::StepNext); | 316 v8::debug::PrepareStep(m_isolate, v8::debug::StepNext); |
| 305 continueProgram(); | 317 continueProgram(); |
| 306 } | 318 } |
| 307 | 319 |
| 308 void V8Debugger::stepOutOfFunction() { | 320 void V8Debugger::stepOutOfFunction() { |
| 309 DCHECK(isPaused()); | 321 DCHECK(isPaused()); |
| 310 DCHECK(!m_executionState.IsEmpty()); | 322 DCHECK(!m_executionState.IsEmpty()); |
| (...skipping 519 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 830 return v8::Null(m_isolate); | 842 return v8::Null(m_isolate); |
| 831 if (!markAsInternal(context, location, V8InternalValueType::kLocation)) | 843 if (!markAsInternal(context, location, V8InternalValueType::kLocation)) |
| 832 return v8::Null(m_isolate); | 844 return v8::Null(m_isolate); |
| 833 return location; | 845 return location; |
| 834 } | 846 } |
| 835 | 847 |
| 836 bool V8Debugger::isPaused() { return !m_pausedContext.IsEmpty(); } | 848 bool V8Debugger::isPaused() { return !m_pausedContext.IsEmpty(); } |
| 837 | 849 |
| 838 std::unique_ptr<V8StackTraceImpl> V8Debugger::createStackTrace( | 850 std::unique_ptr<V8StackTraceImpl> V8Debugger::createStackTrace( |
| 839 v8::Local<v8::StackTrace> stackTrace) { | 851 v8::Local<v8::StackTrace> stackTrace) { |
| 840 int contextGroupId = | 852 return V8StackTraceImpl::create(this, currentContextGroupId(), stackTrace, |
| 841 m_isolate->InContext() | |
| 842 ? m_inspector->contextGroupId(m_isolate->GetCurrentContext()) | |
| 843 : 0; | |
| 844 return V8StackTraceImpl::create(this, contextGroupId, stackTrace, | |
| 845 V8StackTraceImpl::maxCallStackSizeToCapture); | 853 V8StackTraceImpl::maxCallStackSizeToCapture); |
| 846 } | 854 } |
| 847 | 855 |
| 848 void V8Debugger::setAsyncCallStackDepth(V8DebuggerAgentImpl* agent, int depth) { | 856 void V8Debugger::setAsyncCallStackDepth(V8DebuggerAgentImpl* agent, int depth) { |
| 849 if (depth <= 0) | 857 if (depth <= 0) |
| 850 m_maxAsyncCallStackDepthMap.erase(agent); | 858 m_maxAsyncCallStackDepthMap.erase(agent); |
| 851 else | 859 else |
| 852 m_maxAsyncCallStackDepthMap[agent] = depth; | 860 m_maxAsyncCallStackDepthMap[agent] = depth; |
| 853 | 861 |
| 854 int maxAsyncCallStackDepth = 0; | 862 int maxAsyncCallStackDepth = 0; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 881 // We don't need to pass context group id here because we gets this callback | 889 // We don't need to pass context group id here because we gets this callback |
| 882 // from V8 for promise events only. | 890 // from V8 for promise events only. |
| 883 // Passing one as maxStackSize forces no async chain for the new stack and | 891 // Passing one as maxStackSize forces no async chain for the new stack and |
| 884 // allows us to not grow exponentially. | 892 // allows us to not grow exponentially. |
| 885 std::unique_ptr<V8StackTraceImpl> creationStack = | 893 std::unique_ptr<V8StackTraceImpl> creationStack = |
| 886 V8StackTraceImpl::capture(this, 0, 1, String16()); | 894 V8StackTraceImpl::capture(this, 0, 1, String16()); |
| 887 if (creationStack && !creationStack->isEmpty()) { | 895 if (creationStack && !creationStack->isEmpty()) { |
| 888 m_asyncTaskCreationStacks[task] = std::move(creationStack); | 896 m_asyncTaskCreationStacks[task] = std::move(creationStack); |
| 889 registerAsyncTaskIfNeeded(task); | 897 registerAsyncTaskIfNeeded(task); |
| 890 } | 898 } |
| 899 if (!parentTask) return; |
| 900 V8DebuggerAgentImpl* agent = |
| 901 m_inspector->enabledDebuggerAgentForGroup(currentContextGroupId()); |
| 902 if (!agent) return; |
| 903 m_currentCreatedAsyncTask = task; |
| 904 agent->asyncTaskCreated(); |
| 905 m_currentCreatedAsyncTask = nullptr; |
| 891 } | 906 } |
| 892 | 907 |
| 893 void V8Debugger::asyncTaskScheduled(const StringView& taskName, void* task, | 908 void V8Debugger::asyncTaskScheduled(const StringView& taskName, void* task, |
| 894 bool recurring) { | 909 bool recurring) { |
| 895 if (!m_maxAsyncCallStackDepth) return; | 910 if (!m_maxAsyncCallStackDepth) return; |
| 896 asyncTaskScheduled(toString16(taskName), task, recurring); | 911 asyncTaskScheduled(toString16(taskName), task, recurring); |
| 897 } | 912 } |
| 898 | 913 |
| 899 void V8Debugger::asyncTaskScheduled(const String16& taskName, void* task, | 914 void V8Debugger::asyncTaskScheduled(const String16& taskName, void* task, |
| 900 bool recurring) { | 915 bool recurring) { |
| 901 if (!m_maxAsyncCallStackDepth) return; | 916 if (!m_maxAsyncCallStackDepth) return; |
| 902 v8::HandleScope scope(m_isolate); | 917 v8::HandleScope scope(m_isolate); |
| 903 int contextGroupId = | |
| 904 m_isolate->InContext() | |
| 905 ? m_inspector->contextGroupId(m_isolate->GetCurrentContext()) | |
| 906 : 0; | |
| 907 std::unique_ptr<V8StackTraceImpl> chain = V8StackTraceImpl::capture( | 918 std::unique_ptr<V8StackTraceImpl> chain = V8StackTraceImpl::capture( |
| 908 this, contextGroupId, V8StackTraceImpl::maxCallStackSizeToCapture, | 919 this, currentContextGroupId(), |
| 909 taskName); | 920 V8StackTraceImpl::maxCallStackSizeToCapture, taskName); |
| 910 if (chain) { | 921 if (chain) { |
| 911 m_asyncTaskStacks[task] = std::move(chain); | 922 m_asyncTaskStacks[task] = std::move(chain); |
| 912 if (recurring) m_recurringTasks.insert(task); | 923 if (recurring) m_recurringTasks.insert(task); |
| 913 registerAsyncTaskIfNeeded(task); | 924 registerAsyncTaskIfNeeded(task); |
| 914 } | 925 } |
| 915 } | 926 } |
| 916 | 927 |
| 917 void V8Debugger::asyncTaskCanceled(void* task) { | 928 void V8Debugger::asyncTaskCanceled(void* task) { |
| 918 if (!m_maxAsyncCallStackDepth) return; | 929 if (!m_maxAsyncCallStackDepth) return; |
| 919 m_asyncTaskStacks.erase(task); | 930 m_asyncTaskStacks.erase(task); |
| 920 m_recurringTasks.erase(task); | 931 m_recurringTasks.erase(task); |
| 921 m_parentTask.erase(task); | 932 m_parentTask.erase(task); |
| 922 m_asyncTaskCreationStacks.erase(task); | 933 m_asyncTaskCreationStacks.erase(task); |
| 934 if (m_currentCreatedAsyncTask == task) m_currentCreatedAsyncTask = nullptr; |
| 935 m_asyncTasksWithScheduledBreak.erase(task); |
| 923 auto it = m_taskToId.find(task); | 936 auto it = m_taskToId.find(task); |
| 924 if (it == m_taskToId.end()) return; | 937 if (it == m_taskToId.end()) return; |
| 925 m_idToTask.erase(it->second); | 938 m_idToTask.erase(it->second); |
| 926 m_taskToId.erase(it); | 939 m_taskToId.erase(it); |
| 927 } | 940 } |
| 928 | 941 |
| 929 void V8Debugger::asyncTaskStarted(void* task) { | 942 void V8Debugger::asyncTaskStarted(void* task) { |
| 930 if (!m_maxAsyncCallStackDepth) return; | 943 if (!m_maxAsyncCallStackDepth) return; |
| 931 m_currentTasks.push_back(task); | 944 m_currentTasks.push_back(task); |
| 932 auto parentIt = m_parentTask.find(task); | 945 auto parentIt = m_parentTask.find(task); |
| 933 AsyncTaskToStackTrace::iterator stackIt = m_asyncTaskStacks.find( | 946 AsyncTaskToStackTrace::iterator stackIt = m_asyncTaskStacks.find( |
| 934 parentIt == m_parentTask.end() ? task : parentIt->second); | 947 parentIt == m_parentTask.end() ? task : parentIt->second); |
| 935 // Needs to support following order of events: | 948 // Needs to support following order of events: |
| 936 // - asyncTaskScheduled | 949 // - asyncTaskScheduled |
| 937 // <-- attached here --> | 950 // <-- attached here --> |
| 938 // - asyncTaskStarted | 951 // - asyncTaskStarted |
| 939 // - asyncTaskCanceled <-- canceled before finished | 952 // - asyncTaskCanceled <-- canceled before finished |
| 940 // <-- async stack requested here --> | 953 // <-- async stack requested here --> |
| 941 // - asyncTaskFinished | 954 // - asyncTaskFinished |
| 942 std::unique_ptr<V8StackTraceImpl> stack; | 955 std::unique_ptr<V8StackTraceImpl> stack; |
| 943 if (stackIt != m_asyncTaskStacks.end() && stackIt->second) | 956 if (stackIt != m_asyncTaskStacks.end() && stackIt->second) |
| 944 stack = stackIt->second->cloneImpl(); | 957 stack = stackIt->second->cloneImpl(); |
| 945 auto itCreation = m_asyncTaskCreationStacks.find(task); | 958 auto itCreation = m_asyncTaskCreationStacks.find(task); |
| 946 if (stack && itCreation != m_asyncTaskCreationStacks.end()) { | 959 if (stack && itCreation != m_asyncTaskCreationStacks.end()) { |
| 947 stack->setCreation(itCreation->second->cloneImpl()); | 960 stack->setCreation(itCreation->second->cloneImpl()); |
| 948 } | 961 } |
| 949 m_currentStacks.push_back(std::move(stack)); | 962 m_currentStacks.push_back(std::move(stack)); |
| 963 if (m_asyncTasksWithScheduledBreak.find(task) == |
| 964 m_asyncTasksWithScheduledBreak.end()) |
| 965 return; |
| 966 V8DebuggerAgentImpl* agent = |
| 967 m_inspector->enabledDebuggerAgentForGroup(currentContextGroupId()); |
| 968 if (!agent) return; |
| 969 agent->asyncTaskStarted(); |
| 950 } | 970 } |
| 951 | 971 |
| 952 void V8Debugger::asyncTaskFinished(void* task) { | 972 void V8Debugger::asyncTaskFinished(void* task) { |
| 953 if (!m_maxAsyncCallStackDepth) return; | 973 if (!m_maxAsyncCallStackDepth) return; |
| 954 // We could start instrumenting half way and the stack is empty. | 974 // We could start instrumenting half way and the stack is empty. |
| 955 if (!m_currentStacks.size()) return; | 975 if (!m_currentStacks.size()) return; |
| 956 | 976 |
| 957 DCHECK(m_currentTasks.back() == task); | 977 DCHECK(m_currentTasks.back() == task); |
| 958 m_currentTasks.pop_back(); | 978 m_currentTasks.pop_back(); |
| 959 | 979 |
| 960 m_currentStacks.pop_back(); | 980 m_currentStacks.pop_back(); |
| 981 if (m_asyncTasksWithScheduledBreak.find(task) != |
| 982 m_asyncTasksWithScheduledBreak.end()) { |
| 983 V8DebuggerAgentImpl* agent = |
| 984 m_inspector->enabledDebuggerAgentForGroup(currentContextGroupId()); |
| 985 if (!agent) return; |
| 986 agent->asyncTaskFinished(); |
| 987 m_asyncTasksWithScheduledBreak.erase(task); |
| 988 } |
| 989 |
| 961 if (m_recurringTasks.find(task) == m_recurringTasks.end()) { | 990 if (m_recurringTasks.find(task) == m_recurringTasks.end()) { |
| 962 asyncTaskCanceled(task); | 991 asyncTaskCanceled(task); |
| 963 } | 992 } |
| 964 } | 993 } |
| 965 | 994 |
| 966 void V8Debugger::allAsyncTasksCanceled() { | 995 void V8Debugger::allAsyncTasksCanceled() { |
| 967 m_asyncTaskStacks.clear(); | 996 m_asyncTaskStacks.clear(); |
| 968 m_recurringTasks.clear(); | 997 m_recurringTasks.clear(); |
| 969 m_currentStacks.clear(); | 998 m_currentStacks.clear(); |
| 970 m_currentTasks.clear(); | 999 m_currentTasks.clear(); |
| 971 m_parentTask.clear(); | 1000 m_parentTask.clear(); |
| 972 m_asyncTaskCreationStacks.clear(); | 1001 m_asyncTaskCreationStacks.clear(); |
| 1002 m_currentCreatedAsyncTask = nullptr; |
| 1003 m_asyncTasksWithScheduledBreak.clear(); |
| 973 m_idToTask.clear(); | 1004 m_idToTask.clear(); |
| 974 m_taskToId.clear(); | 1005 m_taskToId.clear(); |
| 975 m_lastTaskId = 0; | 1006 m_lastTaskId = 0; |
| 976 } | 1007 } |
| 977 | 1008 |
| 978 void V8Debugger::muteScriptParsedEvents() { | 1009 void V8Debugger::muteScriptParsedEvents() { |
| 979 ++m_ignoreScriptParsedEventsCounter; | 1010 ++m_ignoreScriptParsedEventsCounter; |
| 980 } | 1011 } |
| 981 | 1012 |
| 982 void V8Debugger::unmuteScriptParsedEvents() { | 1013 void V8Debugger::unmuteScriptParsedEvents() { |
| 983 --m_ignoreScriptParsedEventsCounter; | 1014 --m_ignoreScriptParsedEventsCounter; |
| 984 DCHECK_GE(m_ignoreScriptParsedEventsCounter, 0); | 1015 DCHECK_GE(m_ignoreScriptParsedEventsCounter, 0); |
| 985 } | 1016 } |
| 986 | 1017 |
| 987 std::unique_ptr<V8StackTraceImpl> V8Debugger::captureStackTrace( | 1018 std::unique_ptr<V8StackTraceImpl> V8Debugger::captureStackTrace( |
| 988 bool fullStack) { | 1019 bool fullStack) { |
| 989 if (!m_isolate->InContext()) return nullptr; | 1020 int contextGroupId = currentContextGroupId(); |
| 1021 if (!contextGroupId) return nullptr; |
| 990 | 1022 |
| 991 v8::HandleScope handles(m_isolate); | 1023 v8::HandleScope handles(m_isolate); |
| 992 int contextGroupId = | |
| 993 m_inspector->contextGroupId(m_isolate->GetCurrentContext()); | |
| 994 if (!contextGroupId) return nullptr; | |
| 995 | |
| 996 size_t stackSize = | 1024 size_t stackSize = |
| 997 fullStack ? V8StackTraceImpl::maxCallStackSizeToCapture : 1; | 1025 fullStack ? V8StackTraceImpl::maxCallStackSizeToCapture : 1; |
| 998 if (m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) | 1026 if (m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) |
| 999 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; | 1027 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; |
| 1000 | 1028 |
| 1001 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); | 1029 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); |
| 1002 } | 1030 } |
| 1003 | 1031 |
| 1032 int V8Debugger::currentContextGroupId() { |
| 1033 if (!m_isolate->InContext()) return 0; |
| 1034 return m_inspector->contextGroupId(m_isolate->GetCurrentContext()); |
| 1035 } |
| 1036 |
| 1004 } // namespace v8_inspector | 1037 } // namespace v8_inspector |
| OLD | NEW |