Chromium Code Reviews| 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, | |
| 72 v8::External::New(m_isolate, this)); | |
| 73 v8::debug::SetAsyncTaskListener(m_isolate, &V8Debugger::v8AsyncTaskListener, | 71 v8::debug::SetAsyncTaskListener(m_isolate, &V8Debugger::v8AsyncTaskListener, |
| 74 this); | 72 this); |
| 75 v8::debug::SetCompileEventListener(m_isolate, | 73 v8::debug::SetCompileEventListener(m_isolate, |
| 76 &V8Debugger::v8CompileEventListener, this); | 74 &V8Debugger::v8CompileEventListener, this); |
| 75 v8::debug::SetBreakEventListener(m_isolate, &V8Debugger::v8BreakEventListener, | |
| 76 this); | |
| 77 v8::debug::SetExceptionEventListener( | |
| 78 m_isolate, &V8Debugger::v8ExceptionEventListener, this); | |
| 77 m_debuggerContext.Reset(m_isolate, v8::debug::GetDebugContext(m_isolate)); | 79 m_debuggerContext.Reset(m_isolate, v8::debug::GetDebugContext(m_isolate)); |
| 78 v8::debug::ChangeBreakOnException(m_isolate, v8::debug::NoBreakOnException); | 80 v8::debug::ChangeBreakOnException(m_isolate, v8::debug::NoBreakOnException); |
| 79 m_pauseOnExceptionsState = v8::debug::NoBreakOnException; | 81 m_pauseOnExceptionsState = v8::debug::NoBreakOnException; |
| 80 compileDebuggerScript(); | 82 compileDebuggerScript(); |
| 81 } | 83 } |
| 82 | 84 |
| 83 void V8Debugger::disable() { | 85 void V8Debugger::disable() { |
| 84 if (--m_enableCount) return; | 86 if (--m_enableCount) return; |
| 85 DCHECK(enabled()); | 87 DCHECK(enabled()); |
| 86 clearBreakpoints(); | 88 clearBreakpoints(); |
| 87 m_debuggerScript.Reset(); | 89 m_debuggerScript.Reset(); |
| 88 m_debuggerContext.Reset(); | 90 m_debuggerContext.Reset(); |
| 89 allAsyncTasksCanceled(); | 91 allAsyncTasksCanceled(); |
| 90 m_wasmTranslation.Clear(); | 92 m_wasmTranslation.Clear(); |
| 91 v8::debug::SetDebugEventListener(m_isolate, nullptr); | |
| 92 v8::debug::SetAsyncTaskListener(m_isolate, nullptr, nullptr); | 93 v8::debug::SetAsyncTaskListener(m_isolate, nullptr, nullptr); |
| 93 v8::debug::SetCompileEventListener(m_isolate, nullptr, nullptr); | 94 v8::debug::SetCompileEventListener(m_isolate, nullptr, nullptr); |
| 95 v8::debug::SetBreakEventListener(m_isolate, nullptr, nullptr); | |
| 96 v8::debug::SetExceptionEventListener(m_isolate, nullptr, nullptr); | |
| 97 v8::debug::SetBreakEventListener(m_isolate, nullptr, nullptr); | |
|
jgruber
2017/01/17 08:55:11
Double copy-and-paste
| |
| 98 v8::debug::SetExceptionEventListener(m_isolate, nullptr, nullptr); | |
| 94 } | 99 } |
| 95 | 100 |
| 96 bool V8Debugger::enabled() const { return !m_debuggerScript.IsEmpty(); } | 101 bool V8Debugger::enabled() const { return !m_debuggerScript.IsEmpty(); } |
| 97 | 102 |
| 98 void V8Debugger::getCompiledScripts( | 103 void V8Debugger::getCompiledScripts( |
| 99 int contextGroupId, | 104 int contextGroupId, |
| 100 std::vector<std::unique_ptr<V8DebuggerScript>>& result) { | 105 std::vector<std::unique_ptr<V8DebuggerScript>>& result) { |
| 101 v8::HandleScope scope(m_isolate); | 106 v8::HandleScope scope(m_isolate); |
| 102 v8::PersistentValueVector<v8::debug::Script> scripts(m_isolate); | 107 v8::PersistentValueVector<v8::debug::Script> scripts(m_isolate); |
| 103 v8::debug::GetLoadedScripts(m_isolate, scripts); | 108 v8::debug::GetLoadedScripts(m_isolate, scripts); |
| (...skipping 401 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 505 | 510 |
| 506 if (result == V8DebuggerAgentImpl::RequestStepFrame) { | 511 if (result == V8DebuggerAgentImpl::RequestStepFrame) { |
| 507 v8::debug::PrepareStep(m_isolate, v8::debug::StepFrame); | 512 v8::debug::PrepareStep(m_isolate, v8::debug::StepFrame); |
| 508 } else if (result == V8DebuggerAgentImpl::RequestStepInto) { | 513 } else if (result == V8DebuggerAgentImpl::RequestStepInto) { |
| 509 v8::debug::PrepareStep(m_isolate, v8::debug::StepIn); | 514 v8::debug::PrepareStep(m_isolate, v8::debug::StepIn); |
| 510 } else if (result == V8DebuggerAgentImpl::RequestStepOut) { | 515 } else if (result == V8DebuggerAgentImpl::RequestStepOut) { |
| 511 v8::debug::PrepareStep(m_isolate, v8::debug::StepOut); | 516 v8::debug::PrepareStep(m_isolate, v8::debug::StepOut); |
| 512 } | 517 } |
| 513 } | 518 } |
| 514 | 519 |
| 515 void V8Debugger::v8DebugEventCallback( | |
| 516 const v8::debug::EventDetails& eventDetails) { | |
| 517 V8Debugger* thisPtr = toV8Debugger(eventDetails.GetCallbackData()); | |
| 518 thisPtr->handleV8DebugEvent(eventDetails); | |
| 519 } | |
| 520 | |
| 521 v8::Local<v8::Value> V8Debugger::callInternalGetterFunction( | |
| 522 v8::Local<v8::Object> object, const char* functionName) { | |
| 523 v8::MicrotasksScope microtasks(m_isolate, | |
| 524 v8::MicrotasksScope::kDoNotRunMicrotasks); | |
| 525 v8::Local<v8::Value> getterValue = | |
| 526 object | |
| 527 ->Get(m_isolate->GetCurrentContext(), | |
| 528 toV8StringInternalized(m_isolate, functionName)) | |
| 529 .ToLocalChecked(); | |
| 530 DCHECK(!getterValue.IsEmpty() && getterValue->IsFunction()); | |
| 531 return v8::Local<v8::Function>::Cast(getterValue) | |
| 532 ->Call(m_isolate->GetCurrentContext(), object, 0, nullptr) | |
| 533 .ToLocalChecked(); | |
| 534 } | |
| 535 | |
| 536 void V8Debugger::handleV8DebugEvent( | |
| 537 const v8::debug::EventDetails& eventDetails) { | |
| 538 if (!enabled()) return; | |
| 539 v8::HandleScope scope(m_isolate); | |
| 540 | |
| 541 v8::DebugEvent event = eventDetails.GetEvent(); | |
| 542 if (event != v8::Break && event != v8::Exception) return; | |
| 543 | |
| 544 v8::Local<v8::Context> eventContext = eventDetails.GetEventContext(); | |
| 545 DCHECK(!eventContext.IsEmpty()); | |
| 546 V8DebuggerAgentImpl* agent = m_inspector->enabledDebuggerAgentForGroup( | |
| 547 m_inspector->contextGroupId(eventContext)); | |
| 548 if (!agent) return; | |
| 549 | |
| 550 if (event == v8::Exception) { | |
| 551 v8::Local<v8::Context> context = debuggerContext(); | |
| 552 v8::Local<v8::Object> eventData = eventDetails.GetEventData(); | |
| 553 v8::Local<v8::Value> exception = | |
| 554 callInternalGetterFunction(eventData, "exception"); | |
| 555 v8::Local<v8::Value> promise = | |
| 556 callInternalGetterFunction(eventData, "promise"); | |
| 557 bool isPromiseRejection = !promise.IsEmpty() && promise->IsObject(); | |
| 558 v8::Local<v8::Value> uncaught = | |
| 559 callInternalGetterFunction(eventData, "uncaught"); | |
| 560 bool isUncaught = uncaught->BooleanValue(context).FromJust(); | |
| 561 handleProgramBreak(eventContext, eventDetails.GetExecutionState(), | |
| 562 exception, v8::Local<v8::Array>(), isPromiseRejection, | |
| 563 isUncaught); | |
| 564 } else if (event == v8::Break) { | |
| 565 v8::Local<v8::Value> argv[] = {eventDetails.GetEventData()}; | |
| 566 v8::Local<v8::Value> hitBreakpoints; | |
| 567 if (!callDebuggerMethod("getBreakpointNumbers", 1, argv) | |
| 568 .ToLocal(&hitBreakpoints)) | |
| 569 return; | |
| 570 DCHECK(hitBreakpoints->IsArray()); | |
| 571 handleProgramBreak(eventContext, eventDetails.GetExecutionState(), | |
| 572 v8::Local<v8::Value>(), hitBreakpoints.As<v8::Array>()); | |
| 573 } | |
| 574 } | |
| 575 | |
| 576 void V8Debugger::v8CompileEventListener(v8::Local<v8::debug::Script> script, | 520 void V8Debugger::v8CompileEventListener(v8::Local<v8::debug::Script> script, |
| 577 bool has_compile_error, void* data) { | 521 bool has_compile_error, void* data) { |
| 578 V8Debugger* debugger = static_cast<V8Debugger*>(data); | 522 V8Debugger* debugger = static_cast<V8Debugger*>(data); |
| 579 v8::Local<v8::Value> contextData; | 523 v8::Local<v8::Value> contextData; |
| 580 if (!script->ContextData().ToLocal(&contextData) || !contextData->IsInt32()) { | 524 if (!script->ContextData().ToLocal(&contextData) || !contextData->IsInt32()) { |
| 581 return; | 525 return; |
| 582 } | 526 } |
| 583 int contextId = static_cast<int>(contextData.As<v8::Int32>()->Value()); | 527 int contextId = static_cast<int>(contextData.As<v8::Int32>()->Value()); |
| 584 V8DebuggerAgentImpl* agent = | 528 V8DebuggerAgentImpl* agent = |
| 585 debugger->m_inspector->enabledDebuggerAgentForGroup(contextId); | 529 debugger->m_inspector->enabledDebuggerAgentForGroup(contextId); |
| 586 if (!agent) return; | 530 if (!agent) return; |
| 587 if (script->IsWasm()) { | 531 if (script->IsWasm()) { |
| 588 debugger->m_wasmTranslation.AddScript(script.As<v8::debug::WasmScript>(), | 532 debugger->m_wasmTranslation.AddScript(script.As<v8::debug::WasmScript>(), |
| 589 agent); | 533 agent); |
| 590 } else if (debugger->m_ignoreScriptParsedEventsCounter == 0) { | 534 } else if (debugger->m_ignoreScriptParsedEventsCounter == 0) { |
| 591 agent->didParseSource( | 535 agent->didParseSource( |
| 592 V8DebuggerScript::Create(debugger->m_isolate, script, inLiveEditScope), | 536 V8DebuggerScript::Create(debugger->m_isolate, script, inLiveEditScope), |
| 593 !has_compile_error); | 537 !has_compile_error); |
| 594 } | 538 } |
| 595 } | 539 } |
| 596 | 540 |
| 541 void V8Debugger::v8BreakEventListener(v8::Local<v8::Context> pausedContext, | |
| 542 v8::Local<v8::Object> execState, | |
| 543 v8::Local<v8::Value> breakPointsHit, | |
| 544 void* data) { | |
| 545 V8Debugger* debugger = static_cast<V8Debugger*>(data); | |
| 546 v8::Local<v8::Value> argv[] = {breakPointsHit}; | |
| 547 v8::Local<v8::Value> hitBreakpoints; | |
| 548 if (!debugger->callDebuggerMethod("getBreakpointNumbers", 1, argv) | |
| 549 .ToLocal(&hitBreakpoints)) { | |
| 550 return; | |
| 551 } | |
| 552 DCHECK(hitBreakpoints->IsArray()); | |
| 553 debugger->handleProgramBreak(pausedContext, execState, v8::Local<v8::Value>(), | |
| 554 hitBreakpoints.As<v8::Array>()); | |
| 555 } | |
| 556 | |
| 557 void V8Debugger::v8ExceptionEventListener(v8::Local<v8::Context> pausedContext, | |
| 558 v8::Local<v8::Object> execState, | |
| 559 v8::Local<v8::Value> exception, | |
| 560 bool isPromiseRejection, | |
| 561 bool isUncaught, void* data) { | |
| 562 V8Debugger* debugger = static_cast<V8Debugger*>(data); | |
| 563 debugger->handleProgramBreak(pausedContext, execState, exception, | |
| 564 v8::Local<v8::Array>(), isPromiseRejection, | |
| 565 isUncaught); | |
| 566 } | |
| 567 | |
| 597 void V8Debugger::v8AsyncTaskListener(v8::debug::PromiseDebugActionType type, | 568 void V8Debugger::v8AsyncTaskListener(v8::debug::PromiseDebugActionType type, |
| 598 int id, void* data) { | 569 int id, void* data) { |
| 599 V8Debugger* debugger = static_cast<V8Debugger*>(data); | 570 V8Debugger* debugger = static_cast<V8Debugger*>(data); |
| 600 if (!debugger->m_maxAsyncCallStackDepth) return; | 571 if (!debugger->m_maxAsyncCallStackDepth) return; |
| 601 // Async task events from Promises are given misaligned pointers to prevent | 572 // Async task events from Promises are given misaligned pointers to prevent |
| 602 // from overlapping with other Blink task identifiers. There is a single | 573 // from overlapping with other Blink task identifiers. There is a single |
| 603 // namespace of such ids, managed by src/js/promise.js. | 574 // namespace of such ids, managed by src/js/promise.js. |
| 604 void* ptr = reinterpret_cast<void*>(id * 2 + 1); | 575 void* ptr = reinterpret_cast<void*>(id * 2 + 1); |
| 605 switch (type) { | 576 switch (type) { |
| 606 case v8::debug::kDebugEnqueueAsyncFunction: | 577 case v8::debug::kDebugEnqueueAsyncFunction: |
| (...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 995 | 966 |
| 996 size_t stackSize = | 967 size_t stackSize = |
| 997 fullStack ? V8StackTraceImpl::maxCallStackSizeToCapture : 1; | 968 fullStack ? V8StackTraceImpl::maxCallStackSizeToCapture : 1; |
| 998 if (m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) | 969 if (m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) |
| 999 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; | 970 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; |
| 1000 | 971 |
| 1001 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); | 972 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); |
| 1002 } | 973 } |
| 1003 | 974 |
| 1004 } // namespace v8_inspector | 975 } // namespace v8_inspector |
| OLD | NEW |