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, this); | 71 v8::debug::SetDebugDelegate(m_isolate, this); |
| 72 v8::debug::SetOutOfMemoryCallback(m_isolate, &V8Debugger::v8OOMCallback, | 72 v8::debug::SetOutOfMemoryCallback(m_isolate, &V8Debugger::v8OOMCallback, |
| 73 this); | 73 this); |
| 74 m_debuggerContext.Reset(m_isolate, v8::debug::GetDebugContext(m_isolate)); | 74 m_debuggerContext.Reset(m_isolate, v8::debug::GetDebugContext(m_isolate)); |
| 75 v8::debug::ChangeBreakOnException(m_isolate, v8::debug::NoBreakOnException); | 75 v8::debug::ChangeBreakOnException(m_isolate, v8::debug::NoBreakOnException); |
| 76 m_pauseOnExceptionsState = v8::debug::NoBreakOnException; | 76 m_pauseOnExceptionsState = v8::debug::NoBreakOnException; |
| 77 compileDebuggerScript(); | 77 compileDebuggerScript(); |
| 78 } | 78 } |
| 79 | 79 |
| 80 void V8Debugger::disable() { | 80 void V8Debugger::disable() { |
| 81 if (--m_enableCount) return; | 81 if (--m_enableCount) return; |
| 82 DCHECK(enabled()); | 82 DCHECK(enabled()); |
| 83 clearBreakpoints(); | 83 clearBreakpoints(); |
| 84 m_debuggerScript.Reset(); | 84 m_debuggerScript.Reset(); |
| 85 m_debuggerContext.Reset(); | 85 m_debuggerContext.Reset(); |
| 86 allAsyncTasksCanceled(); | 86 allAsyncTasksCanceled(); |
| 87 m_wasmTranslation.Clear(); | 87 m_wasmTranslation.Clear(); |
| 88 v8::debug::SetDebugEventListener(m_isolate, nullptr); | 88 v8::debug::SetDebugDelegate(m_isolate, nullptr); |
| 89 v8::debug::SetOutOfMemoryCallback(m_isolate, nullptr, nullptr); | 89 v8::debug::SetOutOfMemoryCallback(m_isolate, nullptr, nullptr); |
| 90 m_isolate->RestoreOriginalHeapLimit(); | 90 m_isolate->RestoreOriginalHeapLimit(); |
| 91 } | 91 } |
| 92 | 92 |
| 93 bool V8Debugger::enabled() const { return !m_debuggerScript.IsEmpty(); } | 93 bool V8Debugger::enabled() const { return !m_debuggerScript.IsEmpty(); } |
| 94 | 94 |
| 95 void V8Debugger::getCompiledScripts( | 95 void V8Debugger::getCompiledScripts( |
| 96 int contextGroupId, | 96 int contextGroupId, |
| 97 std::vector<std::unique_ptr<V8DebuggerScript>>& result) { | 97 std::vector<std::unique_ptr<V8DebuggerScript>>& result) { |
| 98 v8::HandleScope scope(m_isolate); | 98 v8::HandleScope scope(m_isolate); |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 236 void V8Debugger::setPauseOnNextStatement(bool pause) { | 236 void V8Debugger::setPauseOnNextStatement(bool pause) { |
| 237 if (m_runningNestedMessageLoop) return; | 237 if (m_runningNestedMessageLoop) return; |
| 238 if (pause) | 238 if (pause) |
| 239 v8::debug::DebugBreak(m_isolate); | 239 v8::debug::DebugBreak(m_isolate); |
| 240 else | 240 else |
| 241 v8::debug::CancelDebugBreak(m_isolate); | 241 v8::debug::CancelDebugBreak(m_isolate); |
| 242 } | 242 } |
| 243 | 243 |
| 244 bool V8Debugger::canBreakProgram() { | 244 bool V8Debugger::canBreakProgram() { |
| 245 if (!m_breakpointsActivated) return false; | 245 if (!m_breakpointsActivated) return false; |
| 246 return m_isolate->InContext(); | 246 return v8::debug::HasNonBlackboxedFrameOnStack(m_isolate); |
| 247 } | 247 } |
| 248 | 248 |
| 249 void V8Debugger::breakProgram() { | 249 void V8Debugger::breakProgram() { |
| 250 if (isPaused()) { | 250 if (isPaused()) { |
| 251 DCHECK(!m_runningNestedMessageLoop); | 251 DCHECK(!m_runningNestedMessageLoop); |
| 252 v8::Local<v8::Value> exception; | 252 v8::Local<v8::Value> exception; |
| 253 v8::Local<v8::Array> hitBreakpoints; | 253 v8::Local<v8::Array> hitBreakpoints; |
| 254 handleProgramBreak(m_pausedContext, m_executionState, exception, | 254 handleProgramBreak(m_pausedContext, m_executionState, exception, |
| 255 hitBreakpoints); | 255 hitBreakpoints); |
| 256 return; | 256 return; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 289 continueProgram(); | 289 continueProgram(); |
| 290 } | 290 } |
| 291 | 291 |
| 292 void V8Debugger::stepOutOfFunction() { | 292 void V8Debugger::stepOutOfFunction() { |
| 293 DCHECK(isPaused()); | 293 DCHECK(isPaused()); |
| 294 DCHECK(!m_executionState.IsEmpty()); | 294 DCHECK(!m_executionState.IsEmpty()); |
| 295 v8::debug::PrepareStep(m_isolate, v8::debug::StepOut); | 295 v8::debug::PrepareStep(m_isolate, v8::debug::StepOut); |
| 296 continueProgram(); | 296 continueProgram(); |
| 297 } | 297 } |
| 298 | 298 |
| 299 void V8Debugger::clearStepping() { | |
| 300 DCHECK(enabled()); | |
| 301 v8::debug::ClearStepping(m_isolate); | |
| 302 } | |
| 303 | |
| 304 Response V8Debugger::setScriptSource( | 299 Response V8Debugger::setScriptSource( |
| 305 const String16& sourceID, v8::Local<v8::String> newSource, bool dryRun, | 300 const String16& sourceID, v8::Local<v8::String> newSource, bool dryRun, |
| 306 Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails, | 301 Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails, |
| 307 JavaScriptCallFrames* newCallFrames, Maybe<bool>* stackChanged, | 302 JavaScriptCallFrames* newCallFrames, Maybe<bool>* stackChanged, |
| 308 bool* compileError) { | 303 bool* compileError) { |
| 309 class EnableLiveEditScope { | 304 class EnableLiveEditScope { |
| 310 public: | 305 public: |
| 311 explicit EnableLiveEditScope(v8::Isolate* isolate) : m_isolate(isolate) { | 306 explicit EnableLiveEditScope(v8::Isolate* isolate) : m_isolate(isolate) { |
| 312 v8::debug::SetLiveEditEnabled(m_isolate, true); | 307 v8::debug::SetLiveEditEnabled(m_isolate, true); |
| 313 inLiveEditScope = true; | 308 inLiveEditScope = true; |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 473 v8::Local<v8::Value> hitBreakpointNumber = | 468 v8::Local<v8::Value> hitBreakpointNumber = |
| 474 hitBreakpointNumbers->Get(debuggerContext(), i).ToLocalChecked(); | 469 hitBreakpointNumbers->Get(debuggerContext(), i).ToLocalChecked(); |
| 475 DCHECK(hitBreakpointNumber->IsInt32()); | 470 DCHECK(hitBreakpointNumber->IsInt32()); |
| 476 breakpointIds.push_back(String16::fromInteger( | 471 breakpointIds.push_back(String16::fromInteger( |
| 477 hitBreakpointNumber->Int32Value(debuggerContext()).FromJust())); | 472 hitBreakpointNumber->Int32Value(debuggerContext()).FromJust())); |
| 478 } | 473 } |
| 479 } | 474 } |
| 480 | 475 |
| 481 m_pausedContext = pausedContext; | 476 m_pausedContext = pausedContext; |
| 482 m_executionState = executionState; | 477 m_executionState = executionState; |
| 483 V8DebuggerAgentImpl::SkipPauseRequest result = | 478 bool shouldPause = |
| 484 agent->didPause(pausedContext, exception, breakpointIds, | 479 agent->didPause(pausedContext, exception, breakpointIds, |
| 485 isPromiseRejection, isUncaught, m_scheduledOOMBreak); | 480 isPromiseRejection, isUncaught, m_scheduledOOMBreak); |
| 486 if (result == V8DebuggerAgentImpl::RequestNoSkip) { | 481 if (shouldPause) { |
| 487 m_runningNestedMessageLoop = true; | 482 m_runningNestedMessageLoop = true; |
| 488 int groupId = m_inspector->contextGroupId(pausedContext); | 483 int groupId = m_inspector->contextGroupId(pausedContext); |
| 489 DCHECK(groupId); | 484 DCHECK(groupId); |
| 490 v8::Context::Scope scope(pausedContext); | 485 v8::Context::Scope scope(pausedContext); |
| 491 v8::Local<v8::Context> context = m_isolate->GetCurrentContext(); | 486 v8::Local<v8::Context> context = m_isolate->GetCurrentContext(); |
| 492 CHECK(!context.IsEmpty() && | 487 CHECK(!context.IsEmpty() && |
| 493 context != v8::debug::GetDebugContext(m_isolate)); | 488 context != v8::debug::GetDebugContext(m_isolate)); |
| 494 m_inspector->client()->runMessageLoopOnPause(groupId); | 489 m_inspector->client()->runMessageLoopOnPause(groupId); |
| 495 // The agent may have been removed in the nested loop. | 490 // The agent may have been removed in the nested loop. |
| 496 agent = m_inspector->enabledDebuggerAgentForGroup( | 491 agent = m_inspector->enabledDebuggerAgentForGroup( |
| 497 m_inspector->contextGroupId(pausedContext)); | 492 m_inspector->contextGroupId(pausedContext)); |
| 498 if (agent) agent->didContinue(); | 493 if (agent) agent->didContinue(); |
| 499 m_runningNestedMessageLoop = false; | 494 m_runningNestedMessageLoop = false; |
| 500 } | 495 } |
| 501 if (m_scheduledOOMBreak) m_isolate->RestoreOriginalHeapLimit(); | 496 if (m_scheduledOOMBreak) m_isolate->RestoreOriginalHeapLimit(); |
| 502 m_scheduledOOMBreak = false; | 497 m_scheduledOOMBreak = false; |
| 503 m_pausedContext.Clear(); | 498 m_pausedContext.Clear(); |
| 504 m_executionState.Clear(); | 499 m_executionState.Clear(); |
| 505 | |
| 506 if (result == V8DebuggerAgentImpl::RequestStepFrame) { | |
| 507 v8::debug::PrepareStep(m_isolate, v8::debug::StepFrame); | |
| 508 } else if (result == V8DebuggerAgentImpl::RequestStepInto) { | |
| 509 v8::debug::PrepareStep(m_isolate, v8::debug::StepIn); | |
| 510 } else if (result == V8DebuggerAgentImpl::RequestStepOut) { | |
| 511 v8::debug::PrepareStep(m_isolate, v8::debug::StepOut); | |
| 512 } | |
| 513 } | 500 } |
| 514 | 501 |
| 515 void V8Debugger::v8OOMCallback(void* data) { | 502 void V8Debugger::v8OOMCallback(void* data) { |
| 516 V8Debugger* thisPtr = static_cast<V8Debugger*>(data); | 503 V8Debugger* thisPtr = static_cast<V8Debugger*>(data); |
| 517 thisPtr->m_isolate->IncreaseHeapLimitForDebugging(); | 504 thisPtr->m_isolate->IncreaseHeapLimitForDebugging(); |
| 518 thisPtr->m_scheduledOOMBreak = true; | 505 thisPtr->m_scheduledOOMBreak = true; |
| 519 thisPtr->setPauseOnNextStatement(true); | 506 thisPtr->setPauseOnNextStatement(true); |
| 520 } | 507 } |
| 521 | 508 |
| 509 namespace { | |
|
dgozman
2017/01/24 00:12:08
nit: put all helpers in the namespace at the top.
kozy
2017/01/24 01:11:52
Done.
| |
| 510 V8DebuggerAgentImpl* agentForScript(V8InspectorImpl* inspector, | |
| 511 v8::Local<v8::debug::Script> script) { | |
| 512 v8::Local<v8::Value> contextData; | |
| 513 if (!script->ContextData().ToLocal(&contextData) || !contextData->IsInt32()) { | |
| 514 return nullptr; | |
| 515 } | |
| 516 int contextId = static_cast<int>(contextData.As<v8::Int32>()->Value()); | |
| 517 int contextGroupId = inspector->contextGroupId(contextId); | |
| 518 if (!contextGroupId) return nullptr; | |
| 519 return inspector->enabledDebuggerAgentForGroup(contextGroupId); | |
| 520 } | |
| 521 } // namespace | |
| 522 | |
| 522 void V8Debugger::ScriptCompiled(v8::Local<v8::debug::Script> script, | 523 void V8Debugger::ScriptCompiled(v8::Local<v8::debug::Script> script, |
| 523 bool has_compile_error) { | 524 bool has_compile_error) { |
| 524 v8::Local<v8::Value> contextData; | 525 V8DebuggerAgentImpl* agent = agentForScript(m_inspector, script); |
| 525 if (!script->ContextData().ToLocal(&contextData) || !contextData->IsInt32()) { | |
| 526 return; | |
| 527 } | |
| 528 int contextId = static_cast<int>(contextData.As<v8::Int32>()->Value()); | |
| 529 int contextGroupId = m_inspector->contextGroupId(contextId); | |
| 530 if (!contextGroupId) return; | |
| 531 V8DebuggerAgentImpl* agent = | |
| 532 m_inspector->enabledDebuggerAgentForGroup(contextGroupId); | |
| 533 if (!agent) return; | 526 if (!agent) return; |
| 534 if (script->IsWasm()) { | 527 if (script->IsWasm()) { |
| 535 m_wasmTranslation.AddScript(script.As<v8::debug::WasmScript>(), agent); | 528 m_wasmTranslation.AddScript(script.As<v8::debug::WasmScript>(), agent); |
| 536 } else if (m_ignoreScriptParsedEventsCounter == 0) { | 529 } else if (m_ignoreScriptParsedEventsCounter == 0) { |
| 537 agent->didParseSource( | 530 agent->didParseSource( |
| 538 V8DebuggerScript::Create(m_isolate, script, inLiveEditScope), | 531 V8DebuggerScript::Create(m_isolate, script, inLiveEditScope), |
| 539 !has_compile_error); | 532 !has_compile_error); |
| 540 } | 533 } |
| 541 } | 534 } |
| 542 | 535 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 555 } | 548 } |
| 556 | 549 |
| 557 void V8Debugger::ExceptionThrown(v8::Local<v8::Context> pausedContext, | 550 void V8Debugger::ExceptionThrown(v8::Local<v8::Context> pausedContext, |
| 558 v8::Local<v8::Object> execState, | 551 v8::Local<v8::Object> execState, |
| 559 v8::Local<v8::Value> exception, | 552 v8::Local<v8::Value> exception, |
| 560 bool isPromiseRejection, bool isUncaught) { | 553 bool isPromiseRejection, bool isUncaught) { |
| 561 handleProgramBreak(pausedContext, execState, exception, | 554 handleProgramBreak(pausedContext, execState, exception, |
| 562 v8::Local<v8::Array>(), isPromiseRejection, isUncaught); | 555 v8::Local<v8::Array>(), isPromiseRejection, isUncaught); |
| 563 } | 556 } |
| 564 | 557 |
| 558 bool V8Debugger::IsBlackboxed(v8::Local<v8::debug::Script> script, | |
| 559 const v8::debug::Location& start, | |
| 560 const v8::debug::Location& end) { | |
| 561 V8DebuggerAgentImpl* agent = agentForScript(m_inspector, script); | |
| 562 if (!agent) return false; | |
| 563 return agent->isBlackboxed(String16::fromInteger(script->Id()), start, end); | |
| 564 } | |
| 565 | |
| 565 void V8Debugger::PromiseEventOccurred(v8::debug::PromiseDebugActionType type, | 566 void V8Debugger::PromiseEventOccurred(v8::debug::PromiseDebugActionType type, |
| 566 int id) { | 567 int id) { |
| 567 if (!m_maxAsyncCallStackDepth) return; | 568 if (!m_maxAsyncCallStackDepth) return; |
| 568 // Async task events from Promises are given misaligned pointers to prevent | 569 // Async task events from Promises are given misaligned pointers to prevent |
| 569 // from overlapping with other Blink task identifiers. There is a single | 570 // from overlapping with other Blink task identifiers. There is a single |
| 570 // namespace of such ids, managed by src/js/promise.js. | 571 // namespace of such ids, managed by src/js/promise.js. |
| 571 void* ptr = reinterpret_cast<void*>(id * 2 + 1); | 572 void* ptr = reinterpret_cast<void*>(id * 2 + 1); |
| 572 switch (type) { | 573 switch (type) { |
| 573 case v8::debug::kDebugEnqueueAsyncFunction: | 574 case v8::debug::kDebugEnqueueAsyncFunction: |
| 574 asyncTaskScheduled("async function", ptr, true); | 575 asyncTaskScheduled("async function", ptr, true); |
| (...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 962 | 963 |
| 963 size_t stackSize = | 964 size_t stackSize = |
| 964 fullStack ? V8StackTraceImpl::maxCallStackSizeToCapture : 1; | 965 fullStack ? V8StackTraceImpl::maxCallStackSizeToCapture : 1; |
| 965 if (m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) | 966 if (m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) |
| 966 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; | 967 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; |
| 967 | 968 |
| 968 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); | 969 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); |
| 969 } | 970 } |
| 970 | 971 |
| 971 } // namespace v8_inspector | 972 } // namespace v8_inspector |
| OLD | NEW |