| 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 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 61 m_maxAsyncCallStackDepth(0), | 61 m_maxAsyncCallStackDepth(0), |
| 62 m_pauseOnExceptionsState(v8::debug::NoBreakOnException), | 62 m_pauseOnExceptionsState(v8::debug::NoBreakOnException), |
| 63 m_wasmTranslation(isolate) {} | 63 m_wasmTranslation(isolate) {} |
| 64 | 64 |
| 65 V8Debugger::~V8Debugger() {} | 65 V8Debugger::~V8Debugger() {} |
| 66 | 66 |
| 67 void V8Debugger::enable() { | 67 void V8Debugger::enable() { |
| 68 if (m_enableCount++) return; | 68 if (m_enableCount++) return; |
| 69 DCHECK(!enabled()); | 69 DCHECK(!enabled()); |
| 70 v8::HandleScope scope(m_isolate); | 70 v8::HandleScope scope(m_isolate); |
| 71 v8::debug::SetDebugEventListener(m_isolate, &V8Debugger::v8DebugEventCallback, | 71 v8::debug::SetDebugEventListener(m_isolate, this); |
| 72 v8::External::New(m_isolate, this)); | |
| 73 v8::debug::SetAsyncTaskListener(m_isolate, &V8Debugger::v8AsyncTaskListener, | |
| 74 this); | |
| 75 v8::debug::SetCompileEventListener(m_isolate, | |
| 76 &V8Debugger::v8CompileEventListener, this); | |
| 77 v8::debug::SetOutOfMemoryCallback(m_isolate, &V8Debugger::v8OOMCallback, | 72 v8::debug::SetOutOfMemoryCallback(m_isolate, &V8Debugger::v8OOMCallback, |
| 78 this); | 73 this); |
| 79 m_debuggerContext.Reset(m_isolate, v8::debug::GetDebugContext(m_isolate)); | 74 m_debuggerContext.Reset(m_isolate, v8::debug::GetDebugContext(m_isolate)); |
| 80 v8::debug::ChangeBreakOnException(m_isolate, v8::debug::NoBreakOnException); | 75 v8::debug::ChangeBreakOnException(m_isolate, v8::debug::NoBreakOnException); |
| 81 m_pauseOnExceptionsState = v8::debug::NoBreakOnException; | 76 m_pauseOnExceptionsState = v8::debug::NoBreakOnException; |
| 82 compileDebuggerScript(); | 77 compileDebuggerScript(); |
| 83 } | 78 } |
| 84 | 79 |
| 85 void V8Debugger::disable() { | 80 void V8Debugger::disable() { |
| 86 if (--m_enableCount) return; | 81 if (--m_enableCount) return; |
| 87 DCHECK(enabled()); | 82 DCHECK(enabled()); |
| 88 clearBreakpoints(); | 83 clearBreakpoints(); |
| 89 m_debuggerScript.Reset(); | 84 m_debuggerScript.Reset(); |
| 90 m_debuggerContext.Reset(); | 85 m_debuggerContext.Reset(); |
| 91 allAsyncTasksCanceled(); | 86 allAsyncTasksCanceled(); |
| 92 m_wasmTranslation.Clear(); | 87 m_wasmTranslation.Clear(); |
| 93 v8::debug::SetDebugEventListener(m_isolate, nullptr); | 88 v8::debug::SetDebugEventListener(m_isolate, nullptr); |
| 94 v8::debug::SetAsyncTaskListener(m_isolate, nullptr, nullptr); | |
| 95 v8::debug::SetCompileEventListener(m_isolate, nullptr, nullptr); | |
| 96 v8::debug::SetOutOfMemoryCallback(m_isolate, nullptr, nullptr); | 89 v8::debug::SetOutOfMemoryCallback(m_isolate, nullptr, nullptr); |
| 97 m_isolate->RestoreOriginalHeapLimit(); | 90 m_isolate->RestoreOriginalHeapLimit(); |
| 98 } | 91 } |
| 99 | 92 |
| 100 bool V8Debugger::enabled() const { return !m_debuggerScript.IsEmpty(); } | 93 bool V8Debugger::enabled() const { return !m_debuggerScript.IsEmpty(); } |
| 101 | 94 |
| 102 void V8Debugger::getCompiledScripts( | 95 void V8Debugger::getCompiledScripts( |
| 103 int contextGroupId, | 96 int contextGroupId, |
| 104 std::vector<std::unique_ptr<V8DebuggerScript>>& result) { | 97 std::vector<std::unique_ptr<V8DebuggerScript>>& result) { |
| 105 v8::HandleScope scope(m_isolate); | 98 v8::HandleScope scope(m_isolate); |
| (...skipping 413 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 519 } | 512 } |
| 520 } | 513 } |
| 521 | 514 |
| 522 void V8Debugger::v8OOMCallback(void* data) { | 515 void V8Debugger::v8OOMCallback(void* data) { |
| 523 V8Debugger* thisPtr = static_cast<V8Debugger*>(data); | 516 V8Debugger* thisPtr = static_cast<V8Debugger*>(data); |
| 524 thisPtr->m_isolate->IncreaseHeapLimitForDebugging(); | 517 thisPtr->m_isolate->IncreaseHeapLimitForDebugging(); |
| 525 thisPtr->m_scheduledOOMBreak = true; | 518 thisPtr->m_scheduledOOMBreak = true; |
| 526 thisPtr->setPauseOnNextStatement(true); | 519 thisPtr->setPauseOnNextStatement(true); |
| 527 } | 520 } |
| 528 | 521 |
| 529 void V8Debugger::v8DebugEventCallback( | 522 void V8Debugger::ScriptCompiled(v8::Local<v8::debug::Script> script, |
| 530 const v8::debug::EventDetails& eventDetails) { | 523 bool has_compile_error) { |
| 531 V8Debugger* thisPtr = toV8Debugger(eventDetails.GetCallbackData()); | |
| 532 thisPtr->handleV8DebugEvent(eventDetails); | |
| 533 } | |
| 534 | |
| 535 v8::Local<v8::Value> V8Debugger::callInternalGetterFunction( | |
| 536 v8::Local<v8::Object> object, const char* functionName) { | |
| 537 v8::MicrotasksScope microtasks(m_isolate, | |
| 538 v8::MicrotasksScope::kDoNotRunMicrotasks); | |
| 539 v8::Local<v8::Value> getterValue = | |
| 540 object | |
| 541 ->Get(m_isolate->GetCurrentContext(), | |
| 542 toV8StringInternalized(m_isolate, functionName)) | |
| 543 .ToLocalChecked(); | |
| 544 DCHECK(!getterValue.IsEmpty() && getterValue->IsFunction()); | |
| 545 return v8::Local<v8::Function>::Cast(getterValue) | |
| 546 ->Call(m_isolate->GetCurrentContext(), object, 0, nullptr) | |
| 547 .ToLocalChecked(); | |
| 548 } | |
| 549 | |
| 550 void V8Debugger::handleV8DebugEvent( | |
| 551 const v8::debug::EventDetails& eventDetails) { | |
| 552 if (!enabled()) return; | |
| 553 v8::HandleScope scope(m_isolate); | |
| 554 | |
| 555 v8::DebugEvent event = eventDetails.GetEvent(); | |
| 556 if (event != v8::Break && event != v8::Exception) return; | |
| 557 | |
| 558 v8::Local<v8::Context> eventContext = eventDetails.GetEventContext(); | |
| 559 DCHECK(!eventContext.IsEmpty()); | |
| 560 V8DebuggerAgentImpl* agent = m_inspector->enabledDebuggerAgentForGroup( | |
| 561 m_inspector->contextGroupId(eventContext)); | |
| 562 if (!agent) return; | |
| 563 | |
| 564 if (event == v8::Exception) { | |
| 565 v8::Local<v8::Context> context = debuggerContext(); | |
| 566 v8::Local<v8::Object> eventData = eventDetails.GetEventData(); | |
| 567 v8::Local<v8::Value> exception = | |
| 568 callInternalGetterFunction(eventData, "exception"); | |
| 569 v8::Local<v8::Value> promise = | |
| 570 callInternalGetterFunction(eventData, "promise"); | |
| 571 bool isPromiseRejection = !promise.IsEmpty() && promise->IsObject(); | |
| 572 v8::Local<v8::Value> uncaught = | |
| 573 callInternalGetterFunction(eventData, "uncaught"); | |
| 574 bool isUncaught = uncaught->BooleanValue(context).FromJust(); | |
| 575 handleProgramBreak(eventContext, eventDetails.GetExecutionState(), | |
| 576 exception, v8::Local<v8::Array>(), isPromiseRejection, | |
| 577 isUncaught); | |
| 578 } else if (event == v8::Break) { | |
| 579 v8::Local<v8::Value> argv[] = {eventDetails.GetEventData()}; | |
| 580 v8::Local<v8::Value> hitBreakpoints; | |
| 581 if (!callDebuggerMethod("getBreakpointNumbers", 1, argv) | |
| 582 .ToLocal(&hitBreakpoints)) | |
| 583 return; | |
| 584 DCHECK(hitBreakpoints->IsArray()); | |
| 585 handleProgramBreak(eventContext, eventDetails.GetExecutionState(), | |
| 586 v8::Local<v8::Value>(), hitBreakpoints.As<v8::Array>()); | |
| 587 } | |
| 588 } | |
| 589 | |
| 590 void V8Debugger::v8CompileEventListener(v8::Local<v8::debug::Script> script, | |
| 591 bool has_compile_error, void* data) { | |
| 592 V8Debugger* debugger = static_cast<V8Debugger*>(data); | |
| 593 v8::Local<v8::Value> contextData; | 524 v8::Local<v8::Value> contextData; |
| 594 if (!script->ContextData().ToLocal(&contextData) || !contextData->IsInt32()) { | 525 if (!script->ContextData().ToLocal(&contextData) || !contextData->IsInt32()) { |
| 595 return; | 526 return; |
| 596 } | 527 } |
| 597 int contextId = static_cast<int>(contextData.As<v8::Int32>()->Value()); | 528 int contextId = static_cast<int>(contextData.As<v8::Int32>()->Value()); |
| 598 int contextGroupId = debugger->m_inspector->contextGroupId(contextId); | 529 int contextGroupId = m_inspector->contextGroupId(contextId); |
| 599 if (!contextGroupId) return; | 530 if (!contextGroupId) return; |
| 600 V8DebuggerAgentImpl* agent = | 531 V8DebuggerAgentImpl* agent = |
| 601 debugger->m_inspector->enabledDebuggerAgentForGroup(contextGroupId); | 532 m_inspector->enabledDebuggerAgentForGroup(contextGroupId); |
| 602 if (!agent) return; | 533 if (!agent) return; |
| 603 if (script->IsWasm()) { | 534 if (script->IsWasm()) { |
| 604 debugger->m_wasmTranslation.AddScript(script.As<v8::debug::WasmScript>(), | 535 m_wasmTranslation.AddScript(script.As<v8::debug::WasmScript>(), agent); |
| 605 agent); | 536 } else if (m_ignoreScriptParsedEventsCounter == 0) { |
| 606 } else if (debugger->m_ignoreScriptParsedEventsCounter == 0) { | |
| 607 agent->didParseSource( | 537 agent->didParseSource( |
| 608 V8DebuggerScript::Create(debugger->m_isolate, script, inLiveEditScope), | 538 V8DebuggerScript::Create(m_isolate, script, inLiveEditScope), |
| 609 !has_compile_error); | 539 !has_compile_error); |
| 610 } | 540 } |
| 611 } | 541 } |
| 612 | 542 |
| 613 void V8Debugger::v8AsyncTaskListener(v8::debug::PromiseDebugActionType type, | 543 void V8Debugger::BreakProgramRequested(v8::Local<v8::Context> pausedContext, |
| 614 int id, void* data) { | 544 v8::Local<v8::Object> execState, |
| 615 V8Debugger* debugger = static_cast<V8Debugger*>(data); | 545 v8::Local<v8::Value> breakPointsHit) { |
| 616 if (!debugger->m_maxAsyncCallStackDepth) return; | 546 v8::Local<v8::Value> argv[] = {breakPointsHit}; |
| 547 v8::Local<v8::Value> hitBreakpoints; |
| 548 if (!callDebuggerMethod("getBreakpointNumbers", 1, argv) |
| 549 .ToLocal(&hitBreakpoints)) { |
| 550 return; |
| 551 } |
| 552 DCHECK(hitBreakpoints->IsArray()); |
| 553 handleProgramBreak(pausedContext, execState, v8::Local<v8::Value>(), |
| 554 hitBreakpoints.As<v8::Array>()); |
| 555 } |
| 556 |
| 557 void V8Debugger::ExceptionThrown(v8::Local<v8::Context> pausedContext, |
| 558 v8::Local<v8::Object> execState, |
| 559 v8::Local<v8::Value> exception, |
| 560 bool isPromiseRejection, bool isUncaught) { |
| 561 handleProgramBreak(pausedContext, execState, exception, |
| 562 v8::Local<v8::Array>(), isPromiseRejection, isUncaught); |
| 563 } |
| 564 |
| 565 void V8Debugger::PromiseEventOccurred(v8::debug::PromiseDebugActionType type, |
| 566 int id) { |
| 567 if (!m_maxAsyncCallStackDepth) return; |
| 617 // Async task events from Promises are given misaligned pointers to prevent | 568 // Async task events from Promises are given misaligned pointers to prevent |
| 618 // from overlapping with other Blink task identifiers. There is a single | 569 // from overlapping with other Blink task identifiers. There is a single |
| 619 // namespace of such ids, managed by src/js/promise.js. | 570 // namespace of such ids, managed by src/js/promise.js. |
| 620 void* ptr = reinterpret_cast<void*>(id * 2 + 1); | 571 void* ptr = reinterpret_cast<void*>(id * 2 + 1); |
| 621 switch (type) { | 572 switch (type) { |
| 622 case v8::debug::kDebugEnqueueAsyncFunction: | 573 case v8::debug::kDebugEnqueueAsyncFunction: |
| 623 debugger->asyncTaskScheduled("async function", ptr, true); | 574 asyncTaskScheduled("async function", ptr, true); |
| 624 break; | 575 break; |
| 625 case v8::debug::kDebugEnqueuePromiseResolve: | 576 case v8::debug::kDebugEnqueuePromiseResolve: |
| 626 debugger->asyncTaskScheduled("Promise.resolve", ptr, true); | 577 asyncTaskScheduled("Promise.resolve", ptr, true); |
| 627 break; | 578 break; |
| 628 case v8::debug::kDebugEnqueuePromiseReject: | 579 case v8::debug::kDebugEnqueuePromiseReject: |
| 629 debugger->asyncTaskScheduled("Promise.reject", ptr, true); | 580 asyncTaskScheduled("Promise.reject", ptr, true); |
| 630 break; | 581 break; |
| 631 case v8::debug::kDebugEnqueuePromiseResolveThenableJob: | 582 case v8::debug::kDebugEnqueuePromiseResolveThenableJob: |
| 632 debugger->asyncTaskScheduled("PromiseResolveThenableJob", ptr, true); | 583 asyncTaskScheduled("PromiseResolveThenableJob", ptr, true); |
| 633 break; | 584 break; |
| 634 case v8::debug::kDebugPromiseCollected: | 585 case v8::debug::kDebugPromiseCollected: |
| 635 debugger->asyncTaskCanceled(ptr); | 586 asyncTaskCanceled(ptr); |
| 636 break; | 587 break; |
| 637 case v8::debug::kDebugWillHandle: | 588 case v8::debug::kDebugWillHandle: |
| 638 debugger->asyncTaskStarted(ptr); | 589 asyncTaskStarted(ptr); |
| 639 break; | 590 break; |
| 640 case v8::debug::kDebugDidHandle: | 591 case v8::debug::kDebugDidHandle: |
| 641 debugger->asyncTaskFinished(ptr); | 592 asyncTaskFinished(ptr); |
| 642 break; | 593 break; |
| 643 } | 594 } |
| 644 } | 595 } |
| 645 | 596 |
| 646 V8StackTraceImpl* V8Debugger::currentAsyncCallChain() { | 597 V8StackTraceImpl* V8Debugger::currentAsyncCallChain() { |
| 647 if (!m_currentStacks.size()) return nullptr; | 598 if (!m_currentStacks.size()) return nullptr; |
| 648 return m_currentStacks.back().get(); | 599 return m_currentStacks.back().get(); |
| 649 } | 600 } |
| 650 | 601 |
| 651 void V8Debugger::compileDebuggerScript() { | 602 void V8Debugger::compileDebuggerScript() { |
| (...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1011 | 962 |
| 1012 size_t stackSize = | 963 size_t stackSize = |
| 1013 fullStack ? V8StackTraceImpl::maxCallStackSizeToCapture : 1; | 964 fullStack ? V8StackTraceImpl::maxCallStackSizeToCapture : 1; |
| 1014 if (m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) | 965 if (m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) |
| 1015 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; | 966 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; |
| 1016 | 967 |
| 1017 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); | 968 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); |
| 1018 } | 969 } |
| 1019 | 970 |
| 1020 } // namespace v8_inspector | 971 } // namespace v8_inspector |
| OLD | NEW |