Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(154)

Side by Side Diff: src/inspector/v8-debugger.cc

Issue 2655253004: [inspector] introduced stepIntoAsync for chained callbacks (Closed)
Patch Set: addressed Yang's comment Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698