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 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
560 bool V8Debugger::IsFunctionBlackboxed(v8::Local<v8::debug::Script> script, | 572 bool V8Debugger::IsFunctionBlackboxed(v8::Local<v8::debug::Script> script, |
561 const v8::debug::Location& start, | 573 const v8::debug::Location& start, |
562 const v8::debug::Location& end) { | 574 const v8::debug::Location& end) { |
563 V8DebuggerAgentImpl* agent = agentForScript(m_inspector, script); | 575 V8DebuggerAgentImpl* agent = agentForScript(m_inspector, script); |
564 if (!agent) return false; | 576 if (!agent) return false; |
565 return agent->isFunctionBlackboxed(String16::fromInteger(script->Id()), start, | 577 return agent->isFunctionBlackboxed(String16::fromInteger(script->Id()), start, |
566 end); | 578 end); |
567 } | 579 } |
568 | 580 |
569 void V8Debugger::PromiseEventOccurred(v8::debug::PromiseDebugActionType type, | 581 void V8Debugger::PromiseEventOccurred(v8::debug::PromiseDebugActionType type, |
570 int id, int parentId) { | 582 int id) { |
571 if (!m_maxAsyncCallStackDepth) return; | 583 if (!m_maxAsyncCallStackDepth) return; |
572 // Async task events from Promises are given misaligned pointers to prevent | 584 // Async task events from Promises are given misaligned pointers to prevent |
573 // from overlapping with other Blink task identifiers. There is a single | 585 // from overlapping with other Blink task identifiers. There is a single |
574 // namespace of such ids, managed by src/js/promise.js. | 586 // namespace of such ids, managed by src/js/promise.js. |
575 void* ptr = reinterpret_cast<void*>(id * 2 + 1); | 587 void* ptr = reinterpret_cast<void*>(id * 2 + 1); |
576 switch (type) { | 588 switch (type) { |
577 case v8::debug::kDebugPromiseCreated: | |
578 asyncTaskCreated( | |
579 ptr, parentId ? reinterpret_cast<void*>(parentId * 2 + 1) : nullptr); | |
580 break; | |
581 case v8::debug::kDebugEnqueueAsyncFunction: | 589 case v8::debug::kDebugEnqueueAsyncFunction: |
582 asyncTaskScheduled("async function", ptr, true); | 590 asyncTaskScheduled("async function", ptr, true); |
583 break; | 591 break; |
584 case v8::debug::kDebugEnqueuePromiseResolve: | 592 case v8::debug::kDebugEnqueuePromiseResolve: |
585 asyncTaskScheduled("Promise.resolve", ptr, true); | 593 asyncTaskScheduled("Promise.resolve", ptr, true); |
586 break; | 594 break; |
587 case v8::debug::kDebugEnqueuePromiseReject: | 595 case v8::debug::kDebugEnqueuePromiseReject: |
588 asyncTaskScheduled("Promise.reject", ptr, true); | 596 asyncTaskScheduled("Promise.reject", ptr, true); |
589 break; | 597 break; |
590 case v8::debug::kDebugPromiseCollected: | 598 case v8::debug::kDebugPromiseCollected: |
591 asyncTaskCanceled(ptr); | 599 asyncTaskCanceled(ptr); |
592 break; | 600 break; |
593 case v8::debug::kDebugWillHandle: | 601 case v8::debug::kDebugWillHandle: |
594 asyncTaskStarted(ptr); | 602 asyncTaskStarted(ptr); |
595 break; | 603 break; |
596 case v8::debug::kDebugDidHandle: | 604 case v8::debug::kDebugDidHandle: |
597 asyncTaskFinished(ptr); | 605 asyncTaskFinished(ptr); |
598 break; | 606 break; |
599 } | 607 } |
600 } | 608 } |
601 | 609 |
610 void V8Debugger::PromiseCreatedEvent(int id, int parentId, bool isBreakable) { | |
611 if (!m_maxAsyncCallStackDepth) return; | |
612 void* task = reinterpret_cast<void*>(id * 2 + 1); | |
Yang
2017/01/30 19:40:33
why is this void* and not intptr_t?
| |
613 void* parentTask = | |
614 parentId ? reinterpret_cast<void*>(parentId * 2 + 1) : nullptr; | |
615 if (parentTask) m_parentTask[task] = parentTask; | |
616 v8::HandleScope scope(m_isolate); | |
617 // We don't need to pass context group id here because we gets this callback | |
Yang
2017/01/30 19:40:33
s/gets/get/
kozy
2017/02/15 01:00:54
Done.
| |
618 // from V8 for promise events only. | |
619 // Passing one as maxStackSize forces no async chain for the new stack and | |
620 // allows us to not grow exponentially. | |
621 std::unique_ptr<V8StackTraceImpl> creationStack = | |
622 V8StackTraceImpl::capture(this, 0, 1, String16()); | |
623 if (creationStack && !creationStack->isEmpty()) { | |
624 m_asyncTaskCreationStacks[task] = std::move(creationStack); | |
625 registerAsyncTaskIfNeeded(task); | |
626 } | |
627 if (!parentTask || !isBreakable) return; | |
628 V8DebuggerAgentImpl* agent = | |
629 m_inspector->enabledDebuggerAgentForGroup(currentContextGroupId()); | |
630 if (!agent) return; | |
631 m_currentCreatedAsyncTask = task; | |
632 agent->asyncTaskCreated(); | |
633 m_currentCreatedAsyncTask = nullptr; | |
634 } | |
635 | |
602 V8StackTraceImpl* V8Debugger::currentAsyncCallChain() { | 636 V8StackTraceImpl* V8Debugger::currentAsyncCallChain() { |
603 if (!m_currentStacks.size()) return nullptr; | 637 if (!m_currentStacks.size()) return nullptr; |
604 return m_currentStacks.back().get(); | 638 return m_currentStacks.back().get(); |
605 } | 639 } |
606 | 640 |
607 void V8Debugger::compileDebuggerScript() { | 641 void V8Debugger::compileDebuggerScript() { |
608 if (!m_debuggerScript.IsEmpty()) { | 642 if (!m_debuggerScript.IsEmpty()) { |
609 UNREACHABLE(); | 643 UNREACHABLE(); |
610 return; | 644 return; |
611 } | 645 } |
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
830 return v8::Null(m_isolate); | 864 return v8::Null(m_isolate); |
831 if (!markAsInternal(context, location, V8InternalValueType::kLocation)) | 865 if (!markAsInternal(context, location, V8InternalValueType::kLocation)) |
832 return v8::Null(m_isolate); | 866 return v8::Null(m_isolate); |
833 return location; | 867 return location; |
834 } | 868 } |
835 | 869 |
836 bool V8Debugger::isPaused() { return !m_pausedContext.IsEmpty(); } | 870 bool V8Debugger::isPaused() { return !m_pausedContext.IsEmpty(); } |
837 | 871 |
838 std::unique_ptr<V8StackTraceImpl> V8Debugger::createStackTrace( | 872 std::unique_ptr<V8StackTraceImpl> V8Debugger::createStackTrace( |
839 v8::Local<v8::StackTrace> stackTrace) { | 873 v8::Local<v8::StackTrace> stackTrace) { |
840 int contextGroupId = | 874 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); | 875 V8StackTraceImpl::maxCallStackSizeToCapture); |
846 } | 876 } |
847 | 877 |
848 void V8Debugger::setAsyncCallStackDepth(V8DebuggerAgentImpl* agent, int depth) { | 878 void V8Debugger::setAsyncCallStackDepth(V8DebuggerAgentImpl* agent, int depth) { |
849 if (depth <= 0) | 879 if (depth <= 0) |
850 m_maxAsyncCallStackDepthMap.erase(agent); | 880 m_maxAsyncCallStackDepthMap.erase(agent); |
851 else | 881 else |
852 m_maxAsyncCallStackDepthMap[agent] = depth; | 882 m_maxAsyncCallStackDepthMap[agent] = depth; |
853 | 883 |
854 int maxAsyncCallStackDepth = 0; | 884 int maxAsyncCallStackDepth = 0; |
(...skipping 12 matching lines...) Expand all Loading... | |
867 | 897 |
868 int id = ++m_lastTaskId; | 898 int id = ++m_lastTaskId; |
869 m_taskToId[task] = id; | 899 m_taskToId[task] = id; |
870 m_idToTask[id] = task; | 900 m_idToTask[id] = task; |
871 if (static_cast<int>(m_idToTask.size()) > m_maxAsyncCallStacks) { | 901 if (static_cast<int>(m_idToTask.size()) > m_maxAsyncCallStacks) { |
872 void* taskToRemove = m_idToTask.begin()->second; | 902 void* taskToRemove = m_idToTask.begin()->second; |
873 asyncTaskCanceled(taskToRemove); | 903 asyncTaskCanceled(taskToRemove); |
874 } | 904 } |
875 } | 905 } |
876 | 906 |
877 void V8Debugger::asyncTaskCreated(void* task, void* parentTask) { | |
878 if (!m_maxAsyncCallStackDepth) return; | |
879 if (parentTask) m_parentTask[task] = parentTask; | |
880 v8::HandleScope scope(m_isolate); | |
881 // We don't need to pass context group id here because we gets this callback | |
882 // from V8 for promise events only. | |
883 // Passing one as maxStackSize forces no async chain for the new stack and | |
884 // allows us to not grow exponentially. | |
885 std::unique_ptr<V8StackTraceImpl> creationStack = | |
886 V8StackTraceImpl::capture(this, 0, 1, String16()); | |
887 if (creationStack && !creationStack->isEmpty()) { | |
888 m_asyncTaskCreationStacks[task] = std::move(creationStack); | |
889 registerAsyncTaskIfNeeded(task); | |
890 } | |
891 } | |
892 | |
893 void V8Debugger::asyncTaskScheduled(const StringView& taskName, void* task, | 907 void V8Debugger::asyncTaskScheduled(const StringView& taskName, void* task, |
894 bool recurring) { | 908 bool recurring) { |
895 if (!m_maxAsyncCallStackDepth) return; | 909 if (!m_maxAsyncCallStackDepth) return; |
896 asyncTaskScheduled(toString16(taskName), task, recurring); | 910 asyncTaskScheduled(toString16(taskName), task, recurring); |
897 } | 911 } |
898 | 912 |
899 void V8Debugger::asyncTaskScheduled(const String16& taskName, void* task, | 913 void V8Debugger::asyncTaskScheduled(const String16& taskName, void* task, |
900 bool recurring) { | 914 bool recurring) { |
901 if (!m_maxAsyncCallStackDepth) return; | 915 if (!m_maxAsyncCallStackDepth) return; |
902 v8::HandleScope scope(m_isolate); | 916 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( | 917 std::unique_ptr<V8StackTraceImpl> chain = V8StackTraceImpl::capture( |
908 this, contextGroupId, V8StackTraceImpl::maxCallStackSizeToCapture, | 918 this, currentContextGroupId(), |
909 taskName); | 919 V8StackTraceImpl::maxCallStackSizeToCapture, taskName); |
910 if (chain) { | 920 if (chain) { |
911 m_asyncTaskStacks[task] = std::move(chain); | 921 m_asyncTaskStacks[task] = std::move(chain); |
912 if (recurring) m_recurringTasks.insert(task); | 922 if (recurring) m_recurringTasks.insert(task); |
913 registerAsyncTaskIfNeeded(task); | 923 registerAsyncTaskIfNeeded(task); |
914 } | 924 } |
915 } | 925 } |
916 | 926 |
917 void V8Debugger::asyncTaskCanceled(void* task) { | 927 void V8Debugger::asyncTaskCanceled(void* task) { |
918 if (!m_maxAsyncCallStackDepth) return; | 928 if (!m_maxAsyncCallStackDepth) return; |
919 m_asyncTaskStacks.erase(task); | 929 m_asyncTaskStacks.erase(task); |
920 m_recurringTasks.erase(task); | 930 m_recurringTasks.erase(task); |
921 m_parentTask.erase(task); | 931 m_parentTask.erase(task); |
922 m_asyncTaskCreationStacks.erase(task); | 932 m_asyncTaskCreationStacks.erase(task); |
933 if (m_currentCreatedAsyncTask == task) m_currentCreatedAsyncTask = nullptr; | |
934 m_asyncTasksWithScheduledBreak.erase(task); | |
923 auto it = m_taskToId.find(task); | 935 auto it = m_taskToId.find(task); |
924 if (it == m_taskToId.end()) return; | 936 if (it == m_taskToId.end()) return; |
925 m_idToTask.erase(it->second); | 937 m_idToTask.erase(it->second); |
926 m_taskToId.erase(it); | 938 m_taskToId.erase(it); |
927 } | 939 } |
928 | 940 |
929 void V8Debugger::asyncTaskStarted(void* task) { | 941 void V8Debugger::asyncTaskStarted(void* task) { |
930 if (!m_maxAsyncCallStackDepth) return; | 942 if (!m_maxAsyncCallStackDepth) return; |
931 m_currentTasks.push_back(task); | 943 m_currentTasks.push_back(task); |
932 auto parentIt = m_parentTask.find(task); | 944 auto parentIt = m_parentTask.find(task); |
933 AsyncTaskToStackTrace::iterator stackIt = m_asyncTaskStacks.find( | 945 AsyncTaskToStackTrace::iterator stackIt = m_asyncTaskStacks.find( |
934 parentIt == m_parentTask.end() ? task : parentIt->second); | 946 parentIt == m_parentTask.end() ? task : parentIt->second); |
935 // Needs to support following order of events: | 947 // Needs to support following order of events: |
936 // - asyncTaskScheduled | 948 // - asyncTaskScheduled |
937 // <-- attached here --> | 949 // <-- attached here --> |
938 // - asyncTaskStarted | 950 // - asyncTaskStarted |
939 // - asyncTaskCanceled <-- canceled before finished | 951 // - asyncTaskCanceled <-- canceled before finished |
940 // <-- async stack requested here --> | 952 // <-- async stack requested here --> |
941 // - asyncTaskFinished | 953 // - asyncTaskFinished |
942 std::unique_ptr<V8StackTraceImpl> stack; | 954 std::unique_ptr<V8StackTraceImpl> stack; |
943 if (stackIt != m_asyncTaskStacks.end() && stackIt->second) | 955 if (stackIt != m_asyncTaskStacks.end() && stackIt->second) |
944 stack = stackIt->second->cloneImpl(); | 956 stack = stackIt->second->cloneImpl(); |
945 auto itCreation = m_asyncTaskCreationStacks.find(task); | 957 auto itCreation = m_asyncTaskCreationStacks.find(task); |
946 if (stack && itCreation != m_asyncTaskCreationStacks.end()) { | 958 if (stack && itCreation != m_asyncTaskCreationStacks.end()) { |
947 stack->setCreation(itCreation->second->cloneImpl()); | 959 stack->setCreation(itCreation->second->cloneImpl()); |
948 } | 960 } |
949 m_currentStacks.push_back(std::move(stack)); | 961 m_currentStacks.push_back(std::move(stack)); |
962 if (m_asyncTasksWithScheduledBreak.find(task) == | |
963 m_asyncTasksWithScheduledBreak.end()) | |
964 return; | |
965 V8DebuggerAgentImpl* agent = | |
966 m_inspector->enabledDebuggerAgentForGroup(currentContextGroupId()); | |
967 if (!agent) return; | |
968 agent->asyncTaskStarted(); | |
950 } | 969 } |
951 | 970 |
952 void V8Debugger::asyncTaskFinished(void* task) { | 971 void V8Debugger::asyncTaskFinished(void* task) { |
953 if (!m_maxAsyncCallStackDepth) return; | 972 if (!m_maxAsyncCallStackDepth) return; |
954 // We could start instrumenting half way and the stack is empty. | 973 // We could start instrumenting half way and the stack is empty. |
955 if (!m_currentStacks.size()) return; | 974 if (!m_currentStacks.size()) return; |
956 | 975 |
957 DCHECK(m_currentTasks.back() == task); | 976 DCHECK(m_currentTasks.back() == task); |
958 m_currentTasks.pop_back(); | 977 m_currentTasks.pop_back(); |
959 | 978 |
960 m_currentStacks.pop_back(); | 979 m_currentStacks.pop_back(); |
980 if (m_asyncTasksWithScheduledBreak.find(task) != | |
981 m_asyncTasksWithScheduledBreak.end()) { | |
982 V8DebuggerAgentImpl* agent = | |
983 m_inspector->enabledDebuggerAgentForGroup(currentContextGroupId()); | |
984 if (!agent) return; | |
985 agent->asyncTaskFinished(); | |
986 m_asyncTasksWithScheduledBreak.erase(task); | |
987 } | |
988 | |
961 if (m_recurringTasks.find(task) == m_recurringTasks.end()) { | 989 if (m_recurringTasks.find(task) == m_recurringTasks.end()) { |
962 asyncTaskCanceled(task); | 990 asyncTaskCanceled(task); |
963 } | 991 } |
964 } | 992 } |
965 | 993 |
966 void V8Debugger::allAsyncTasksCanceled() { | 994 void V8Debugger::allAsyncTasksCanceled() { |
967 m_asyncTaskStacks.clear(); | 995 m_asyncTaskStacks.clear(); |
968 m_recurringTasks.clear(); | 996 m_recurringTasks.clear(); |
969 m_currentStacks.clear(); | 997 m_currentStacks.clear(); |
970 m_currentTasks.clear(); | 998 m_currentTasks.clear(); |
971 m_parentTask.clear(); | 999 m_parentTask.clear(); |
972 m_asyncTaskCreationStacks.clear(); | 1000 m_asyncTaskCreationStacks.clear(); |
1001 m_currentCreatedAsyncTask = nullptr; | |
1002 m_asyncTasksWithScheduledBreak.clear(); | |
973 m_idToTask.clear(); | 1003 m_idToTask.clear(); |
974 m_taskToId.clear(); | 1004 m_taskToId.clear(); |
975 m_lastTaskId = 0; | 1005 m_lastTaskId = 0; |
976 } | 1006 } |
977 | 1007 |
978 void V8Debugger::muteScriptParsedEvents() { | 1008 void V8Debugger::muteScriptParsedEvents() { |
979 ++m_ignoreScriptParsedEventsCounter; | 1009 ++m_ignoreScriptParsedEventsCounter; |
980 } | 1010 } |
981 | 1011 |
982 void V8Debugger::unmuteScriptParsedEvents() { | 1012 void V8Debugger::unmuteScriptParsedEvents() { |
983 --m_ignoreScriptParsedEventsCounter; | 1013 --m_ignoreScriptParsedEventsCounter; |
984 DCHECK_GE(m_ignoreScriptParsedEventsCounter, 0); | 1014 DCHECK_GE(m_ignoreScriptParsedEventsCounter, 0); |
985 } | 1015 } |
986 | 1016 |
987 std::unique_ptr<V8StackTraceImpl> V8Debugger::captureStackTrace( | 1017 std::unique_ptr<V8StackTraceImpl> V8Debugger::captureStackTrace( |
988 bool fullStack) { | 1018 bool fullStack) { |
989 if (!m_isolate->InContext()) return nullptr; | 1019 int contextGroupId = currentContextGroupId(); |
1020 if (!contextGroupId) return nullptr; | |
990 | 1021 |
991 v8::HandleScope handles(m_isolate); | 1022 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 = | 1023 size_t stackSize = |
997 fullStack ? V8StackTraceImpl::maxCallStackSizeToCapture : 1; | 1024 fullStack ? V8StackTraceImpl::maxCallStackSizeToCapture : 1; |
998 if (m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) | 1025 if (m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) |
999 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; | 1026 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; |
1000 | 1027 |
1001 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); | 1028 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); |
1002 } | 1029 } |
1003 | 1030 |
1031 int V8Debugger::currentContextGroupId() { | |
1032 if (!m_isolate->InContext()) return 0; | |
1033 return m_inspector->contextGroupId(m_isolate->GetCurrentContext()); | |
1034 } | |
1035 | |
1004 } // namespace v8_inspector | 1036 } // namespace v8_inspector |
OLD | NEW |