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 329 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
340 v8::debug::DebugBreak(m_isolate); | 340 v8::debug::DebugBreak(m_isolate); |
341 else | 341 else |
342 v8::debug::CancelDebugBreak(m_isolate); | 342 v8::debug::CancelDebugBreak(m_isolate); |
343 } | 343 } |
344 | 344 |
345 bool V8Debugger::canBreakProgram() { | 345 bool V8Debugger::canBreakProgram() { |
346 if (!m_breakpointsActivated) return false; | 346 if (!m_breakpointsActivated) return false; |
347 return !v8::debug::AllFramesOnStackAreBlackboxed(m_isolate); | 347 return !v8::debug::AllFramesOnStackAreBlackboxed(m_isolate); |
348 } | 348 } |
349 | 349 |
350 bool V8Debugger::breakProgram(int targetContextGroupId) { | 350 void V8Debugger::breakProgram(int targetContextGroupId) { |
351 // Don't allow nested breaks. | 351 // Don't allow nested breaks. |
352 if (isPaused()) return true; | 352 if (isPaused()) return; |
353 if (!canBreakProgram()) return true; | 353 if (!canBreakProgram()) return; |
354 DCHECK(targetContextGroupId); | 354 DCHECK(targetContextGroupId); |
355 m_targetContextGroupId = targetContextGroupId; | 355 m_targetContextGroupId = targetContextGroupId; |
356 v8::debug::BreakRightNow(m_isolate); | 356 v8::debug::BreakRightNow(m_isolate); |
357 V8InspectorSessionImpl* session = | |
358 m_inspector->sessionForContextGroup(targetContextGroupId); | |
359 return session && session->debuggerAgent()->enabled(); | |
360 } | 357 } |
361 | 358 |
362 void V8Debugger::continueProgram(int targetContextGroupId) { | 359 void V8Debugger::continueProgram(int targetContextGroupId) { |
363 if (m_pausedContextGroupId != targetContextGroupId) return; | 360 if (m_pausedContextGroupId != targetContextGroupId) return; |
364 if (isPaused()) m_inspector->client()->quitMessageLoopOnPause(); | 361 if (isPaused()) m_inspector->client()->quitMessageLoopOnPause(); |
365 m_pausedContext.Clear(); | 362 m_pausedContext.Clear(); |
366 m_executionState.Clear(); | 363 m_executionState.Clear(); |
367 } | 364 } |
368 | 365 |
369 void V8Debugger::stepIntoStatement(int targetContextGroupId) { | 366 void V8Debugger::stepIntoStatement(int targetContextGroupId) { |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
593 v8::debug::PrepareStep(m_isolate, v8::debug::StepOut); | 590 v8::debug::PrepareStep(m_isolate, v8::debug::StepOut); |
594 return; | 591 return; |
595 } | 592 } |
596 m_targetContextGroupId = 0; | 593 m_targetContextGroupId = 0; |
597 if (m_stepIntoAsyncCallback) { | 594 if (m_stepIntoAsyncCallback) { |
598 m_stepIntoAsyncCallback->sendFailure( | 595 m_stepIntoAsyncCallback->sendFailure( |
599 Response::Error("No async tasks were scheduled before pause.")); | 596 Response::Error("No async tasks were scheduled before pause.")); |
600 m_stepIntoAsyncCallback.reset(); | 597 m_stepIntoAsyncCallback.reset(); |
601 } | 598 } |
602 m_breakRequested = false; | 599 m_breakRequested = false; |
603 V8InspectorSessionImpl* session = | 600 |
604 m_inspector->sessionForContextGroup(contextGroupId); | 601 bool scheduledOOMBreak = m_scheduledOOMBreak; |
605 if (!session || !session->debuggerAgent()->enabled()) return; | 602 auto agentCheck = [&scheduledOOMBreak](V8DebuggerAgentImpl* agent) { |
606 if (!m_scheduledOOMBreak && session->debuggerAgent()->skipAllPauses()) return; | 603 return agent->enabled() && (scheduledOOMBreak || !agent->skipAllPauses()); |
| 604 }; |
| 605 |
| 606 bool hasAgents = false; |
| 607 m_inspector->forEachSession( |
| 608 contextGroupId, |
| 609 [&agentCheck, &hasAgents](V8InspectorSessionImpl* session) { |
| 610 if (agentCheck(session->debuggerAgent())) hasAgents = true; |
| 611 }); |
| 612 if (!hasAgents) return; |
607 | 613 |
608 std::vector<String16> breakpointIds; | 614 std::vector<String16> breakpointIds; |
609 if (!hitBreakpointNumbers.IsEmpty()) { | 615 if (!hitBreakpointNumbers.IsEmpty()) { |
610 breakpointIds.reserve(hitBreakpointNumbers->Length()); | 616 breakpointIds.reserve(hitBreakpointNumbers->Length()); |
611 for (uint32_t i = 0; i < hitBreakpointNumbers->Length(); i++) { | 617 for (uint32_t i = 0; i < hitBreakpointNumbers->Length(); i++) { |
612 v8::Local<v8::Value> hitBreakpointNumber = | 618 v8::Local<v8::Value> hitBreakpointNumber = |
613 hitBreakpointNumbers->Get(debuggerContext(), i).ToLocalChecked(); | 619 hitBreakpointNumbers->Get(debuggerContext(), i).ToLocalChecked(); |
614 DCHECK(hitBreakpointNumber->IsInt32()); | 620 DCHECK(hitBreakpointNumber->IsInt32()); |
615 breakpointIds.push_back(String16::fromInteger( | 621 breakpointIds.push_back(String16::fromInteger( |
616 hitBreakpointNumber->Int32Value(debuggerContext()).FromJust())); | 622 hitBreakpointNumber->Int32Value(debuggerContext()).FromJust())); |
617 } | 623 } |
618 if (breakpointIds.size() == 1 && | 624 if (breakpointIds.size() == 1 && |
619 breakpointIds[0] == m_continueToLocationBreakpointId) { | 625 breakpointIds[0] == m_continueToLocationBreakpointId) { |
620 v8::Context::Scope contextScope(pausedContext); | 626 v8::Context::Scope contextScope(pausedContext); |
621 if (!shouldContinueToCurrentLocation()) return; | 627 if (!shouldContinueToCurrentLocation()) return; |
622 } | 628 } |
623 } | 629 } |
624 clearContinueToLocation(); | 630 clearContinueToLocation(); |
625 | 631 |
626 DCHECK(contextGroupId); | 632 DCHECK(contextGroupId); |
627 m_pausedContext = pausedContext; | 633 m_pausedContext = pausedContext; |
628 m_executionState = executionState; | 634 m_executionState = executionState; |
629 m_pausedContextGroupId = contextGroupId; | 635 m_pausedContextGroupId = contextGroupId; |
630 session->debuggerAgent()->didPause( | 636 |
631 InspectedContext::contextId(pausedContext), exception, breakpointIds, | 637 m_inspector->forEachSession( |
632 isPromiseRejection, isUncaught, m_scheduledOOMBreak); | 638 contextGroupId, [&agentCheck, &pausedContext, &exception, &breakpointIds, |
| 639 &isPromiseRejection, &isUncaught, |
| 640 &scheduledOOMBreak](V8InspectorSessionImpl* session) { |
| 641 if (agentCheck(session->debuggerAgent())) { |
| 642 session->debuggerAgent()->didPause( |
| 643 InspectedContext::contextId(pausedContext), exception, |
| 644 breakpointIds, isPromiseRejection, isUncaught, scheduledOOMBreak); |
| 645 } |
| 646 }); |
633 { | 647 { |
634 v8::Context::Scope scope(pausedContext); | 648 v8::Context::Scope scope(pausedContext); |
635 v8::Local<v8::Context> context = m_isolate->GetCurrentContext(); | 649 v8::Local<v8::Context> context = m_isolate->GetCurrentContext(); |
636 CHECK(!context.IsEmpty() && | 650 CHECK(!context.IsEmpty() && |
637 context != v8::debug::GetDebugContext(m_isolate)); | 651 context != v8::debug::GetDebugContext(m_isolate)); |
638 m_inspector->client()->runMessageLoopOnPause(contextGroupId); | 652 m_inspector->client()->runMessageLoopOnPause(contextGroupId); |
639 m_pausedContextGroupId = 0; | 653 m_pausedContextGroupId = 0; |
640 } | 654 } |
641 // The agent may have been removed in the nested loop. | 655 m_inspector->forEachSession(contextGroupId, |
642 session = m_inspector->sessionForContextGroup(contextGroupId); | 656 [](V8InspectorSessionImpl* session) { |
643 if (session && session->debuggerAgent()->enabled()) | 657 if (session->debuggerAgent()->enabled()) |
644 session->debuggerAgent()->didContinue(); | 658 session->debuggerAgent()->didContinue(); |
| 659 }); |
| 660 |
645 if (m_scheduledOOMBreak) m_isolate->RestoreOriginalHeapLimit(); | 661 if (m_scheduledOOMBreak) m_isolate->RestoreOriginalHeapLimit(); |
646 m_scheduledOOMBreak = false; | 662 m_scheduledOOMBreak = false; |
647 m_pausedContext.Clear(); | 663 m_pausedContext.Clear(); |
648 m_executionState.Clear(); | 664 m_executionState.Clear(); |
649 } | 665 } |
650 | 666 |
651 void V8Debugger::v8OOMCallback(void* data) { | 667 void V8Debugger::v8OOMCallback(void* data) { |
652 V8Debugger* thisPtr = static_cast<V8Debugger*>(data); | 668 V8Debugger* thisPtr = static_cast<V8Debugger*>(data); |
653 thisPtr->m_isolate->IncreaseHeapLimitForDebugging(); | 669 thisPtr->m_isolate->IncreaseHeapLimitForDebugging(); |
654 thisPtr->m_scheduledOOMBreak = true; | 670 thisPtr->m_scheduledOOMBreak = true; |
655 v8::Local<v8::Context> context = thisPtr->m_isolate->GetEnteredContext(); | 671 v8::Local<v8::Context> context = thisPtr->m_isolate->GetEnteredContext(); |
656 DCHECK(!context.IsEmpty()); | 672 DCHECK(!context.IsEmpty()); |
657 thisPtr->setPauseOnNextStatement( | 673 thisPtr->setPauseOnNextStatement( |
658 true, thisPtr->m_inspector->contextGroupId(context)); | 674 true, thisPtr->m_inspector->contextGroupId(context)); |
659 } | 675 } |
660 | 676 |
661 void V8Debugger::ScriptCompiled(v8::Local<v8::debug::Script> script, | 677 void V8Debugger::ScriptCompiled(v8::Local<v8::debug::Script> script, |
662 bool has_compile_error) { | 678 bool has_compile_error) { |
663 int contextId; | 679 int contextId; |
664 if (!script->ContextId().To(&contextId)) return; | 680 if (!script->ContextId().To(&contextId)) return; |
665 V8InspectorSessionImpl* session = m_inspector->sessionForContextGroup( | |
666 m_inspector->contextGroupId(contextId)); | |
667 if (!session || !session->debuggerAgent()->enabled()) return; | |
668 if (script->IsWasm()) { | 681 if (script->IsWasm()) { |
669 m_wasmTranslation.AddScript(script.As<v8::debug::WasmScript>(), | 682 WasmTranslation* wasmTranslation = &m_wasmTranslation; |
670 session->debuggerAgent()); | 683 m_inspector->forEachSession( |
| 684 m_inspector->contextGroupId(contextId), |
| 685 [&script, &wasmTranslation](V8InspectorSessionImpl* session) { |
| 686 if (!session->debuggerAgent()->enabled()) return; |
| 687 wasmTranslation->AddScript(script.As<v8::debug::WasmScript>(), |
| 688 session->debuggerAgent()); |
| 689 }); |
671 } else if (m_ignoreScriptParsedEventsCounter == 0) { | 690 } else if (m_ignoreScriptParsedEventsCounter == 0) { |
672 session->debuggerAgent()->didParseSource( | 691 v8::Isolate* isolate = m_isolate; |
673 V8DebuggerScript::Create(m_isolate, script, inLiveEditScope), | 692 m_inspector->forEachSession( |
674 !has_compile_error); | 693 m_inspector->contextGroupId(contextId), |
| 694 [&isolate, &script, |
| 695 &has_compile_error](V8InspectorSessionImpl* session) { |
| 696 if (!session->debuggerAgent()->enabled()) return; |
| 697 session->debuggerAgent()->didParseSource( |
| 698 V8DebuggerScript::Create(isolate, script, inLiveEditScope), |
| 699 !has_compile_error); |
| 700 }); |
675 } | 701 } |
676 } | 702 } |
677 | 703 |
678 void V8Debugger::BreakProgramRequested(v8::Local<v8::Context> pausedContext, | 704 void V8Debugger::BreakProgramRequested(v8::Local<v8::Context> pausedContext, |
679 v8::Local<v8::Object> execState, | 705 v8::Local<v8::Object> execState, |
680 v8::Local<v8::Value> breakPointsHit) { | 706 v8::Local<v8::Value> breakPointsHit) { |
681 v8::Local<v8::Value> argv[] = {breakPointsHit}; | 707 v8::Local<v8::Value> argv[] = {breakPointsHit}; |
682 v8::Local<v8::Value> hitBreakpoints; | 708 v8::Local<v8::Value> hitBreakpoints; |
683 if (!callDebuggerMethod("getBreakpointNumbers", 1, argv, true) | 709 if (!callDebuggerMethod("getBreakpointNumbers", 1, argv, true) |
684 .ToLocal(&hitBreakpoints)) { | 710 .ToLocal(&hitBreakpoints)) { |
(...skipping 12 matching lines...) Expand all Loading... |
697 bool isPromiseRejection = promise->IsPromise(); | 723 bool isPromiseRejection = promise->IsPromise(); |
698 handleProgramBreak(pausedContext, execState, exception, | 724 handleProgramBreak(pausedContext, execState, exception, |
699 v8::Local<v8::Array>(), isPromiseRejection, isUncaught); | 725 v8::Local<v8::Array>(), isPromiseRejection, isUncaught); |
700 } | 726 } |
701 | 727 |
702 bool V8Debugger::IsFunctionBlackboxed(v8::Local<v8::debug::Script> script, | 728 bool V8Debugger::IsFunctionBlackboxed(v8::Local<v8::debug::Script> script, |
703 const v8::debug::Location& start, | 729 const v8::debug::Location& start, |
704 const v8::debug::Location& end) { | 730 const v8::debug::Location& end) { |
705 int contextId; | 731 int contextId; |
706 if (!script->ContextId().To(&contextId)) return false; | 732 if (!script->ContextId().To(&contextId)) return false; |
707 V8InspectorSessionImpl* session = m_inspector->sessionForContextGroup( | 733 bool hasAgents = false; |
708 m_inspector->contextGroupId(contextId)); | 734 bool allBlackboxed = true; |
709 if (!session || !session->debuggerAgent()->enabled()) return false; | 735 String16 scriptId = String16::fromInteger(script->Id()); |
710 return session->debuggerAgent()->isFunctionBlackboxed( | 736 m_inspector->forEachSession( |
711 String16::fromInteger(script->Id()), start, end); | 737 m_inspector->contextGroupId(contextId), |
| 738 [&hasAgents, &allBlackboxed, &scriptId, &start, |
| 739 &end](V8InspectorSessionImpl* session) { |
| 740 V8DebuggerAgentImpl* agent = session->debuggerAgent(); |
| 741 if (!agent->enabled()) return; |
| 742 hasAgents = true; |
| 743 allBlackboxed &= agent->isFunctionBlackboxed(scriptId, start, end); |
| 744 }); |
| 745 return hasAgents && allBlackboxed; |
712 } | 746 } |
713 | 747 |
714 void V8Debugger::PromiseEventOccurred(v8::debug::PromiseDebugActionType type, | 748 void V8Debugger::PromiseEventOccurred(v8::debug::PromiseDebugActionType type, |
715 int id, int parentId, | 749 int id, int parentId, |
716 bool createdByUser) { | 750 bool createdByUser) { |
717 // Async task events from Promises are given misaligned pointers to prevent | 751 // Async task events from Promises are given misaligned pointers to prevent |
718 // from overlapping with other Blink task identifiers. | 752 // from overlapping with other Blink task identifiers. |
719 void* task = reinterpret_cast<void*>(id * 2 + 1); | 753 void* task = reinterpret_cast<void*>(id * 2 + 1); |
720 void* parentTask = | 754 void* parentTask = |
721 parentId ? reinterpret_cast<void*>(parentId * 2 + 1) : nullptr; | 755 parentId ? reinterpret_cast<void*>(parentId * 2 + 1) : nullptr; |
(...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1077 | 1111 |
1078 std::unique_ptr<V8StackTraceImpl> V8Debugger::captureStackTrace( | 1112 std::unique_ptr<V8StackTraceImpl> V8Debugger::captureStackTrace( |
1079 bool fullStack) { | 1113 bool fullStack) { |
1080 if (!m_isolate->InContext()) return nullptr; | 1114 if (!m_isolate->InContext()) return nullptr; |
1081 | 1115 |
1082 v8::HandleScope handles(m_isolate); | 1116 v8::HandleScope handles(m_isolate); |
1083 int contextGroupId = currentContextGroupId(); | 1117 int contextGroupId = currentContextGroupId(); |
1084 if (!contextGroupId) return nullptr; | 1118 if (!contextGroupId) return nullptr; |
1085 | 1119 |
1086 int stackSize = 1; | 1120 int stackSize = 1; |
1087 V8InspectorSessionImpl* session = | 1121 if (fullStack) { |
1088 m_inspector->sessionForContextGroup(contextGroupId); | |
1089 if (fullStack || (session && session->runtimeAgent()->enabled())) { | |
1090 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; | 1122 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; |
| 1123 } else { |
| 1124 m_inspector->forEachSession( |
| 1125 contextGroupId, [&stackSize](V8InspectorSessionImpl* session) { |
| 1126 if (session->runtimeAgent()->enabled()) |
| 1127 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; |
| 1128 }); |
1091 } | 1129 } |
1092 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); | 1130 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); |
1093 } | 1131 } |
1094 | 1132 |
1095 int V8Debugger::currentContextGroupId() { | 1133 int V8Debugger::currentContextGroupId() { |
1096 if (!m_isolate->InContext()) return 0; | 1134 if (!m_isolate->InContext()) return 0; |
1097 return m_inspector->contextGroupId(m_isolate->GetCurrentContext()); | 1135 return m_inspector->contextGroupId(m_isolate->GetCurrentContext()); |
1098 } | 1136 } |
1099 | 1137 |
1100 void V8Debugger::collectOldAsyncStacksIfNeeded() { | 1138 void V8Debugger::collectOldAsyncStacksIfNeeded() { |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1155 fprintf(stdout, "Async stacks count: %d\n", m_asyncStacksCount); | 1193 fprintf(stdout, "Async stacks count: %d\n", m_asyncStacksCount); |
1156 fprintf(stdout, "Scheduled async tasks: %zu\n", m_asyncTaskStacks.size()); | 1194 fprintf(stdout, "Scheduled async tasks: %zu\n", m_asyncTaskStacks.size()); |
1157 fprintf(stdout, "Created async tasks: %zu\n", | 1195 fprintf(stdout, "Created async tasks: %zu\n", |
1158 m_asyncTaskCreationStacks.size()); | 1196 m_asyncTaskCreationStacks.size()); |
1159 fprintf(stdout, "Async tasks with parent: %zu\n", m_parentTask.size()); | 1197 fprintf(stdout, "Async tasks with parent: %zu\n", m_parentTask.size()); |
1160 fprintf(stdout, "Recurring async tasks: %zu\n", m_recurringTasks.size()); | 1198 fprintf(stdout, "Recurring async tasks: %zu\n", m_recurringTasks.size()); |
1161 fprintf(stdout, "\n"); | 1199 fprintf(stdout, "\n"); |
1162 } | 1200 } |
1163 | 1201 |
1164 } // namespace v8_inspector | 1202 } // namespace v8_inspector |
OLD | NEW |