| 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-inspector-session-impl.h" |
| 14 #include "src/inspector/v8-internal-value-type.h" | 15 #include "src/inspector/v8-internal-value-type.h" |
| 16 #include "src/inspector/v8-runtime-agent-impl.h" |
| 15 #include "src/inspector/v8-stack-trace-impl.h" | 17 #include "src/inspector/v8-stack-trace-impl.h" |
| 16 #include "src/inspector/v8-value-copier.h" | 18 #include "src/inspector/v8-value-copier.h" |
| 17 | 19 |
| 18 #include "include/v8-util.h" | 20 #include "include/v8-util.h" |
| 19 | 21 |
| 20 namespace v8_inspector { | 22 namespace v8_inspector { |
| 21 | 23 |
| 22 namespace { | 24 namespace { |
| 23 | 25 |
| 24 static const int kMaxAsyncTaskStacks = 128 * 1024; | 26 static const int kMaxAsyncTaskStacks = 128 * 1024; |
| 25 | 27 |
| 26 inline v8::Local<v8::Boolean> v8Boolean(bool value, v8::Isolate* isolate) { | 28 inline v8::Local<v8::Boolean> v8Boolean(bool value, v8::Isolate* isolate) { |
| 27 return value ? v8::True(isolate) : v8::False(isolate); | 29 return value ? v8::True(isolate) : v8::False(isolate); |
| 28 } | 30 } |
| 29 | 31 |
| 30 V8DebuggerAgentImpl* agentForScript(V8InspectorImpl* inspector, | |
| 31 v8::Local<v8::debug::Script> script) { | |
| 32 int contextId; | |
| 33 if (!script->ContextId().To(&contextId)) return nullptr; | |
| 34 int contextGroupId = inspector->contextGroupId(contextId); | |
| 35 if (!contextGroupId) return nullptr; | |
| 36 return inspector->enabledDebuggerAgentForGroup(contextGroupId); | |
| 37 } | |
| 38 | |
| 39 v8::MaybeLocal<v8::Array> collectionsEntries(v8::Local<v8::Context> context, | 32 v8::MaybeLocal<v8::Array> collectionsEntries(v8::Local<v8::Context> context, |
| 40 v8::Local<v8::Value> value) { | 33 v8::Local<v8::Value> value) { |
| 41 v8::Isolate* isolate = context->GetIsolate(); | 34 v8::Isolate* isolate = context->GetIsolate(); |
| 42 v8::Local<v8::Array> entries; | 35 v8::Local<v8::Array> entries; |
| 43 bool isKeyValue = false; | 36 bool isKeyValue = false; |
| 44 if (!v8::debug::EntriesPreview(isolate, value, &isKeyValue).ToLocal(&entries)) | 37 if (!v8::debug::EntriesPreview(isolate, value, &isKeyValue).ToLocal(&entries)) |
| 45 return v8::MaybeLocal<v8::Array>(); | 38 return v8::MaybeLocal<v8::Array>(); |
| 46 | 39 |
| 47 v8::Local<v8::Array> wrappedEntries = v8::Array::New(isolate); | 40 v8::Local<v8::Array> wrappedEntries = v8::Array::New(isolate); |
| 48 CHECK(!isKeyValue || wrappedEntries->Length() % 2 == 0); | 41 CHECK(!isKeyValue || wrappedEntries->Length() % 2 == 0); |
| (...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 354 return !v8::debug::AllFramesOnStackAreBlackboxed(m_isolate); | 347 return !v8::debug::AllFramesOnStackAreBlackboxed(m_isolate); |
| 355 } | 348 } |
| 356 | 349 |
| 357 bool V8Debugger::breakProgram(int targetContextGroupId) { | 350 bool V8Debugger::breakProgram(int targetContextGroupId) { |
| 358 // Don't allow nested breaks. | 351 // Don't allow nested breaks. |
| 359 if (isPaused()) return true; | 352 if (isPaused()) return true; |
| 360 if (!canBreakProgram()) return true; | 353 if (!canBreakProgram()) return true; |
| 361 DCHECK(targetContextGroupId); | 354 DCHECK(targetContextGroupId); |
| 362 m_targetContextGroupId = targetContextGroupId; | 355 m_targetContextGroupId = targetContextGroupId; |
| 363 v8::debug::BreakRightNow(m_isolate); | 356 v8::debug::BreakRightNow(m_isolate); |
| 364 return m_inspector->enabledDebuggerAgentForGroup(targetContextGroupId); | 357 V8InspectorSessionImpl* session = |
| 358 m_inspector->sessionForContextGroup(targetContextGroupId); |
| 359 return session && session->debuggerAgent()->enabled(); |
| 365 } | 360 } |
| 366 | 361 |
| 367 void V8Debugger::continueProgram(int targetContextGroupId) { | 362 void V8Debugger::continueProgram(int targetContextGroupId) { |
| 368 if (m_pausedContextGroupId != targetContextGroupId) return; | 363 if (m_pausedContextGroupId != targetContextGroupId) return; |
| 369 if (isPaused()) m_inspector->client()->quitMessageLoopOnPause(); | 364 if (isPaused()) m_inspector->client()->quitMessageLoopOnPause(); |
| 370 m_pausedContext.Clear(); | 365 m_pausedContext.Clear(); |
| 371 m_executionState.Clear(); | 366 m_executionState.Clear(); |
| 372 } | 367 } |
| 373 | 368 |
| 374 void V8Debugger::stepIntoStatement(int targetContextGroupId) { | 369 void V8Debugger::stepIntoStatement(int targetContextGroupId) { |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 598 v8::debug::PrepareStep(m_isolate, v8::debug::StepOut); | 593 v8::debug::PrepareStep(m_isolate, v8::debug::StepOut); |
| 599 return; | 594 return; |
| 600 } | 595 } |
| 601 m_targetContextGroupId = 0; | 596 m_targetContextGroupId = 0; |
| 602 if (m_stepIntoAsyncCallback) { | 597 if (m_stepIntoAsyncCallback) { |
| 603 m_stepIntoAsyncCallback->sendFailure( | 598 m_stepIntoAsyncCallback->sendFailure( |
| 604 Response::Error("No async tasks were scheduled before pause.")); | 599 Response::Error("No async tasks were scheduled before pause.")); |
| 605 m_stepIntoAsyncCallback.reset(); | 600 m_stepIntoAsyncCallback.reset(); |
| 606 } | 601 } |
| 607 m_breakRequested = false; | 602 m_breakRequested = false; |
| 608 V8DebuggerAgentImpl* agent = m_inspector->enabledDebuggerAgentForGroup( | 603 V8InspectorSessionImpl* session = |
| 609 m_inspector->contextGroupId(pausedContext)); | 604 m_inspector->sessionForContextGroup(contextGroupId); |
| 610 if (!agent || (agent->skipAllPauses() && !m_scheduledOOMBreak)) return; | 605 if (!session || !session->debuggerAgent()->enabled()) return; |
| 606 if (!m_scheduledOOMBreak && session->debuggerAgent()->skipAllPauses()) return; |
| 611 | 607 |
| 612 std::vector<String16> breakpointIds; | 608 std::vector<String16> breakpointIds; |
| 613 if (!hitBreakpointNumbers.IsEmpty()) { | 609 if (!hitBreakpointNumbers.IsEmpty()) { |
| 614 breakpointIds.reserve(hitBreakpointNumbers->Length()); | 610 breakpointIds.reserve(hitBreakpointNumbers->Length()); |
| 615 for (uint32_t i = 0; i < hitBreakpointNumbers->Length(); i++) { | 611 for (uint32_t i = 0; i < hitBreakpointNumbers->Length(); i++) { |
| 616 v8::Local<v8::Value> hitBreakpointNumber = | 612 v8::Local<v8::Value> hitBreakpointNumber = |
| 617 hitBreakpointNumbers->Get(debuggerContext(), i).ToLocalChecked(); | 613 hitBreakpointNumbers->Get(debuggerContext(), i).ToLocalChecked(); |
| 618 DCHECK(hitBreakpointNumber->IsInt32()); | 614 DCHECK(hitBreakpointNumber->IsInt32()); |
| 619 breakpointIds.push_back(String16::fromInteger( | 615 breakpointIds.push_back(String16::fromInteger( |
| 620 hitBreakpointNumber->Int32Value(debuggerContext()).FromJust())); | 616 hitBreakpointNumber->Int32Value(debuggerContext()).FromJust())); |
| 621 } | 617 } |
| 622 if (breakpointIds.size() == 1 && | 618 if (breakpointIds.size() == 1 && |
| 623 breakpointIds[0] == m_continueToLocationBreakpointId) { | 619 breakpointIds[0] == m_continueToLocationBreakpointId) { |
| 624 v8::Context::Scope contextScope(pausedContext); | 620 v8::Context::Scope contextScope(pausedContext); |
| 625 if (!shouldContinueToCurrentLocation()) return; | 621 if (!shouldContinueToCurrentLocation()) return; |
| 626 } | 622 } |
| 627 } | 623 } |
| 628 clearContinueToLocation(); | 624 clearContinueToLocation(); |
| 629 | 625 |
| 626 DCHECK(contextGroupId); |
| 630 m_pausedContext = pausedContext; | 627 m_pausedContext = pausedContext; |
| 631 m_executionState = executionState; | 628 m_executionState = executionState; |
| 632 m_pausedContextGroupId = contextGroupId; | 629 m_pausedContextGroupId = contextGroupId; |
| 633 agent->didPause(InspectedContext::contextId(pausedContext), exception, | 630 session->debuggerAgent()->didPause( |
| 634 breakpointIds, isPromiseRejection, isUncaught, | 631 InspectedContext::contextId(pausedContext), exception, breakpointIds, |
| 635 m_scheduledOOMBreak); | 632 isPromiseRejection, isUncaught, m_scheduledOOMBreak); |
| 636 int groupId = m_inspector->contextGroupId(pausedContext); | |
| 637 DCHECK(groupId); | |
| 638 { | 633 { |
| 639 v8::Context::Scope scope(pausedContext); | 634 v8::Context::Scope scope(pausedContext); |
| 640 v8::Local<v8::Context> context = m_isolate->GetCurrentContext(); | 635 v8::Local<v8::Context> context = m_isolate->GetCurrentContext(); |
| 641 CHECK(!context.IsEmpty() && | 636 CHECK(!context.IsEmpty() && |
| 642 context != v8::debug::GetDebugContext(m_isolate)); | 637 context != v8::debug::GetDebugContext(m_isolate)); |
| 643 m_inspector->client()->runMessageLoopOnPause(groupId); | 638 m_inspector->client()->runMessageLoopOnPause(contextGroupId); |
| 644 m_pausedContextGroupId = 0; | 639 m_pausedContextGroupId = 0; |
| 645 } | 640 } |
| 646 // The agent may have been removed in the nested loop. | 641 // The agent may have been removed in the nested loop. |
| 647 agent = m_inspector->enabledDebuggerAgentForGroup(groupId); | 642 session = m_inspector->sessionForContextGroup(contextGroupId); |
| 648 if (agent) agent->didContinue(); | 643 if (session && session->debuggerAgent()->enabled()) |
| 644 session->debuggerAgent()->didContinue(); |
| 649 if (m_scheduledOOMBreak) m_isolate->RestoreOriginalHeapLimit(); | 645 if (m_scheduledOOMBreak) m_isolate->RestoreOriginalHeapLimit(); |
| 650 m_scheduledOOMBreak = false; | 646 m_scheduledOOMBreak = false; |
| 651 m_pausedContext.Clear(); | 647 m_pausedContext.Clear(); |
| 652 m_executionState.Clear(); | 648 m_executionState.Clear(); |
| 653 } | 649 } |
| 654 | 650 |
| 655 void V8Debugger::v8OOMCallback(void* data) { | 651 void V8Debugger::v8OOMCallback(void* data) { |
| 656 V8Debugger* thisPtr = static_cast<V8Debugger*>(data); | 652 V8Debugger* thisPtr = static_cast<V8Debugger*>(data); |
| 657 thisPtr->m_isolate->IncreaseHeapLimitForDebugging(); | 653 thisPtr->m_isolate->IncreaseHeapLimitForDebugging(); |
| 658 thisPtr->m_scheduledOOMBreak = true; | 654 thisPtr->m_scheduledOOMBreak = true; |
| 659 v8::Local<v8::Context> context = thisPtr->m_isolate->GetEnteredContext(); | 655 v8::Local<v8::Context> context = thisPtr->m_isolate->GetEnteredContext(); |
| 660 DCHECK(!context.IsEmpty()); | 656 DCHECK(!context.IsEmpty()); |
| 661 thisPtr->setPauseOnNextStatement( | 657 thisPtr->setPauseOnNextStatement( |
| 662 true, thisPtr->m_inspector->contextGroupId(context)); | 658 true, thisPtr->m_inspector->contextGroupId(context)); |
| 663 } | 659 } |
| 664 | 660 |
| 665 void V8Debugger::ScriptCompiled(v8::Local<v8::debug::Script> script, | 661 void V8Debugger::ScriptCompiled(v8::Local<v8::debug::Script> script, |
| 666 bool has_compile_error) { | 662 bool has_compile_error) { |
| 667 V8DebuggerAgentImpl* agent = agentForScript(m_inspector, script); | 663 int contextId; |
| 668 if (!agent) return; | 664 if (!script->ContextId().To(&contextId)) return; |
| 665 V8InspectorSessionImpl* session = m_inspector->sessionForContextGroup( |
| 666 m_inspector->contextGroupId(contextId)); |
| 667 if (!session || !session->debuggerAgent()->enabled()) return; |
| 669 if (script->IsWasm()) { | 668 if (script->IsWasm()) { |
| 670 m_wasmTranslation.AddScript(script.As<v8::debug::WasmScript>(), agent); | 669 m_wasmTranslation.AddScript(script.As<v8::debug::WasmScript>(), |
| 670 session->debuggerAgent()); |
| 671 } else if (m_ignoreScriptParsedEventsCounter == 0) { | 671 } else if (m_ignoreScriptParsedEventsCounter == 0) { |
| 672 agent->didParseSource( | 672 session->debuggerAgent()->didParseSource( |
| 673 V8DebuggerScript::Create(m_isolate, script, inLiveEditScope), | 673 V8DebuggerScript::Create(m_isolate, script, inLiveEditScope), |
| 674 !has_compile_error); | 674 !has_compile_error); |
| 675 } | 675 } |
| 676 } | 676 } |
| 677 | 677 |
| 678 void V8Debugger::BreakProgramRequested(v8::Local<v8::Context> pausedContext, | 678 void V8Debugger::BreakProgramRequested(v8::Local<v8::Context> pausedContext, |
| 679 v8::Local<v8::Object> execState, | 679 v8::Local<v8::Object> execState, |
| 680 v8::Local<v8::Value> breakPointsHit) { | 680 v8::Local<v8::Value> breakPointsHit) { |
| 681 v8::Local<v8::Value> argv[] = {breakPointsHit}; | 681 v8::Local<v8::Value> argv[] = {breakPointsHit}; |
| 682 v8::Local<v8::Value> hitBreakpoints; | 682 v8::Local<v8::Value> hitBreakpoints; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 695 v8::Local<v8::Value> promise, | 695 v8::Local<v8::Value> promise, |
| 696 bool isUncaught) { | 696 bool isUncaught) { |
| 697 bool isPromiseRejection = promise->IsPromise(); | 697 bool isPromiseRejection = promise->IsPromise(); |
| 698 handleProgramBreak(pausedContext, execState, exception, | 698 handleProgramBreak(pausedContext, execState, exception, |
| 699 v8::Local<v8::Array>(), isPromiseRejection, isUncaught); | 699 v8::Local<v8::Array>(), isPromiseRejection, isUncaught); |
| 700 } | 700 } |
| 701 | 701 |
| 702 bool V8Debugger::IsFunctionBlackboxed(v8::Local<v8::debug::Script> script, | 702 bool V8Debugger::IsFunctionBlackboxed(v8::Local<v8::debug::Script> script, |
| 703 const v8::debug::Location& start, | 703 const v8::debug::Location& start, |
| 704 const v8::debug::Location& end) { | 704 const v8::debug::Location& end) { |
| 705 V8DebuggerAgentImpl* agent = agentForScript(m_inspector, script); | 705 int contextId; |
| 706 if (!agent) return false; | 706 if (!script->ContextId().To(&contextId)) return false; |
| 707 return agent->isFunctionBlackboxed(String16::fromInteger(script->Id()), start, | 707 V8InspectorSessionImpl* session = m_inspector->sessionForContextGroup( |
| 708 end); | 708 m_inspector->contextGroupId(contextId)); |
| 709 if (!session || !session->debuggerAgent()->enabled()) return false; |
| 710 return session->debuggerAgent()->isFunctionBlackboxed( |
| 711 String16::fromInteger(script->Id()), start, end); |
| 709 } | 712 } |
| 710 | 713 |
| 711 void V8Debugger::PromiseEventOccurred(v8::debug::PromiseDebugActionType type, | 714 void V8Debugger::PromiseEventOccurred(v8::debug::PromiseDebugActionType type, |
| 712 int id, int parentId, | 715 int id, int parentId, |
| 713 bool createdByUser) { | 716 bool createdByUser) { |
| 714 // Async task events from Promises are given misaligned pointers to prevent | 717 // Async task events from Promises are given misaligned pointers to prevent |
| 715 // from overlapping with other Blink task identifiers. | 718 // from overlapping with other Blink task identifiers. |
| 716 void* task = reinterpret_cast<void*>(id * 2 + 1); | 719 void* task = reinterpret_cast<void*>(id * 2 + 1); |
| 717 void* parentTask = | 720 void* parentTask = |
| 718 parentId ? reinterpret_cast<void*>(parentId * 2 + 1) : nullptr; | 721 parentId ? reinterpret_cast<void*>(parentId * 2 + 1) : nullptr; |
| (...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1074 | 1077 |
| 1075 std::unique_ptr<V8StackTraceImpl> V8Debugger::captureStackTrace( | 1078 std::unique_ptr<V8StackTraceImpl> V8Debugger::captureStackTrace( |
| 1076 bool fullStack) { | 1079 bool fullStack) { |
| 1077 if (!m_isolate->InContext()) return nullptr; | 1080 if (!m_isolate->InContext()) return nullptr; |
| 1078 | 1081 |
| 1079 v8::HandleScope handles(m_isolate); | 1082 v8::HandleScope handles(m_isolate); |
| 1080 int contextGroupId = currentContextGroupId(); | 1083 int contextGroupId = currentContextGroupId(); |
| 1081 if (!contextGroupId) return nullptr; | 1084 if (!contextGroupId) return nullptr; |
| 1082 | 1085 |
| 1083 int stackSize = 1; | 1086 int stackSize = 1; |
| 1084 if (fullStack || m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) { | 1087 V8InspectorSessionImpl* session = |
| 1088 m_inspector->sessionForContextGroup(contextGroupId); |
| 1089 if (fullStack || (session && session->runtimeAgent()->enabled())) { |
| 1085 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; | 1090 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; |
| 1086 } | 1091 } |
| 1087 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); | 1092 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); |
| 1088 } | 1093 } |
| 1089 | 1094 |
| 1090 int V8Debugger::currentContextGroupId() { | 1095 int V8Debugger::currentContextGroupId() { |
| 1091 if (!m_isolate->InContext()) return 0; | 1096 if (!m_isolate->InContext()) return 0; |
| 1092 return m_inspector->contextGroupId(m_isolate->GetCurrentContext()); | 1097 return m_inspector->contextGroupId(m_isolate->GetCurrentContext()); |
| 1093 } | 1098 } |
| 1094 | 1099 |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1150 fprintf(stdout, "Async stacks count: %d\n", m_asyncStacksCount); | 1155 fprintf(stdout, "Async stacks count: %d\n", m_asyncStacksCount); |
| 1151 fprintf(stdout, "Scheduled async tasks: %zu\n", m_asyncTaskStacks.size()); | 1156 fprintf(stdout, "Scheduled async tasks: %zu\n", m_asyncTaskStacks.size()); |
| 1152 fprintf(stdout, "Created async tasks: %zu\n", | 1157 fprintf(stdout, "Created async tasks: %zu\n", |
| 1153 m_asyncTaskCreationStacks.size()); | 1158 m_asyncTaskCreationStacks.size()); |
| 1154 fprintf(stdout, "Async tasks with parent: %zu\n", m_parentTask.size()); | 1159 fprintf(stdout, "Async tasks with parent: %zu\n", m_parentTask.size()); |
| 1155 fprintf(stdout, "Recurring async tasks: %zu\n", m_recurringTasks.size()); | 1160 fprintf(stdout, "Recurring async tasks: %zu\n", m_recurringTasks.size()); |
| 1156 fprintf(stdout, "\n"); | 1161 fprintf(stdout, "\n"); |
| 1157 } | 1162 } |
| 1158 | 1163 |
| 1159 } // namespace v8_inspector | 1164 } // namespace v8_inspector |
| OLD | NEW |