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 |