| 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 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 183 this); | 183 this); |
| 184 m_debuggerContext.Reset(m_isolate, v8::debug::GetDebugContext(m_isolate)); | 184 m_debuggerContext.Reset(m_isolate, v8::debug::GetDebugContext(m_isolate)); |
| 185 v8::debug::ChangeBreakOnException(m_isolate, v8::debug::NoBreakOnException); | 185 v8::debug::ChangeBreakOnException(m_isolate, v8::debug::NoBreakOnException); |
| 186 m_pauseOnExceptionsState = v8::debug::NoBreakOnException; | 186 m_pauseOnExceptionsState = v8::debug::NoBreakOnException; |
| 187 compileDebuggerScript(); | 187 compileDebuggerScript(); |
| 188 } | 188 } |
| 189 | 189 |
| 190 void V8Debugger::disable() { | 190 void V8Debugger::disable() { |
| 191 if (--m_enableCount) return; | 191 if (--m_enableCount) return; |
| 192 DCHECK(enabled()); | 192 DCHECK(enabled()); |
| 193 clearBreakpoints(); | |
| 194 m_debuggerScript.Reset(); | 193 m_debuggerScript.Reset(); |
| 195 m_debuggerContext.Reset(); | 194 m_debuggerContext.Reset(); |
| 196 allAsyncTasksCanceled(); | 195 allAsyncTasksCanceled(); |
| 197 m_wasmTranslation.Clear(); | 196 m_wasmTranslation.Clear(); |
| 198 v8::debug::SetDebugDelegate(m_isolate, nullptr); | 197 v8::debug::SetDebugDelegate(m_isolate, nullptr); |
| 199 v8::debug::SetOutOfMemoryCallback(m_isolate, nullptr, nullptr); | 198 v8::debug::SetOutOfMemoryCallback(m_isolate, nullptr, nullptr); |
| 200 m_isolate->RestoreOriginalHeapLimit(); | 199 m_isolate->RestoreOriginalHeapLimit(); |
| 201 } | 200 } |
| 202 | 201 |
| 203 bool V8Debugger::enabled() const { return !m_debuggerScript.IsEmpty(); } | 202 bool V8Debugger::enabled() const { return !m_debuggerScript.IsEmpty(); } |
| 204 | 203 |
| 205 void V8Debugger::getCompiledScripts( | 204 void V8Debugger::getCompiledScripts( |
| 206 int contextGroupId, | 205 int contextGroupId, |
| 207 std::vector<std::unique_ptr<V8DebuggerScript>>& result) { | 206 std::vector<std::unique_ptr<V8DebuggerScript>>& result) { |
| 208 v8::HandleScope scope(m_isolate); | 207 v8::HandleScope scope(m_isolate); |
| 209 v8::PersistentValueVector<v8::debug::Script> scripts(m_isolate); | 208 v8::PersistentValueVector<v8::debug::Script> scripts(m_isolate); |
| 210 v8::debug::GetLoadedScripts(m_isolate, scripts); | 209 v8::debug::GetLoadedScripts(m_isolate, scripts); |
| 211 for (size_t i = 0; i < scripts.Size(); ++i) { | 210 for (size_t i = 0; i < scripts.Size(); ++i) { |
| 212 v8::Local<v8::debug::Script> script = scripts.Get(i); | 211 v8::Local<v8::debug::Script> script = scripts.Get(i); |
| 213 if (!script->WasCompiled()) continue; | 212 if (!script->WasCompiled()) continue; |
| 214 v8::Local<v8::Value> contextData; | 213 v8::Local<v8::Value> contextData; |
| 215 if (!script->ContextData().ToLocal(&contextData) || !contextData->IsInt32()) | 214 if (!script->ContextData().ToLocal(&contextData) || !contextData->IsInt32()) |
| 216 continue; | 215 continue; |
| 217 int contextId = static_cast<int>(contextData.As<v8::Int32>()->Value()); | 216 int contextId = static_cast<int>(contextData.As<v8::Int32>()->Value()); |
| 218 if (m_inspector->contextGroupId(contextId) != contextGroupId) continue; | 217 if (m_inspector->contextGroupId(contextId) != contextGroupId) continue; |
| 219 result.push_back(V8DebuggerScript::Create(m_isolate, script, false)); | 218 result.push_back(V8DebuggerScript::Create(m_isolate, script, false)); |
| 220 } | 219 } |
| 221 } | 220 } |
| 222 | 221 |
| 223 String16 V8Debugger::setBreakpoint(const ScriptBreakpoint& breakpoint, | |
| 224 int* actualLineNumber, | |
| 225 int* actualColumnNumber) { | |
| 226 v8::HandleScope scope(m_isolate); | |
| 227 v8::Local<v8::Context> context = debuggerContext(); | |
| 228 v8::Context::Scope contextScope(context); | |
| 229 | |
| 230 v8::Local<v8::Object> info = v8::Object::New(m_isolate); | |
| 231 bool success = false; | |
| 232 success = info->Set(context, toV8StringInternalized(m_isolate, "sourceID"), | |
| 233 toV8String(m_isolate, breakpoint.script_id)) | |
| 234 .FromMaybe(false); | |
| 235 DCHECK(success); | |
| 236 success = info->Set(context, toV8StringInternalized(m_isolate, "lineNumber"), | |
| 237 v8::Integer::New(m_isolate, breakpoint.line_number)) | |
| 238 .FromMaybe(false); | |
| 239 DCHECK(success); | |
| 240 success = | |
| 241 info->Set(context, toV8StringInternalized(m_isolate, "columnNumber"), | |
| 242 v8::Integer::New(m_isolate, breakpoint.column_number)) | |
| 243 .FromMaybe(false); | |
| 244 DCHECK(success); | |
| 245 success = info->Set(context, toV8StringInternalized(m_isolate, "condition"), | |
| 246 toV8String(m_isolate, breakpoint.condition)) | |
| 247 .FromMaybe(false); | |
| 248 DCHECK(success); | |
| 249 USE(success); | |
| 250 | |
| 251 v8::Local<v8::Function> setBreakpointFunction = v8::Local<v8::Function>::Cast( | |
| 252 m_debuggerScript.Get(m_isolate) | |
| 253 ->Get(context, toV8StringInternalized(m_isolate, "setBreakpoint")) | |
| 254 .ToLocalChecked()); | |
| 255 v8::Local<v8::Value> breakpointId = | |
| 256 v8::debug::Call(debuggerContext(), setBreakpointFunction, info) | |
| 257 .ToLocalChecked(); | |
| 258 if (!breakpointId->IsString()) return ""; | |
| 259 *actualLineNumber = | |
| 260 info->Get(context, toV8StringInternalized(m_isolate, "lineNumber")) | |
| 261 .ToLocalChecked() | |
| 262 ->Int32Value(context) | |
| 263 .FromJust(); | |
| 264 *actualColumnNumber = | |
| 265 info->Get(context, toV8StringInternalized(m_isolate, "columnNumber")) | |
| 266 .ToLocalChecked() | |
| 267 ->Int32Value(context) | |
| 268 .FromJust(); | |
| 269 return toProtocolString(breakpointId.As<v8::String>()); | |
| 270 } | |
| 271 | |
| 272 void V8Debugger::removeBreakpoint(const String16& breakpointId) { | |
| 273 v8::HandleScope scope(m_isolate); | |
| 274 v8::Local<v8::Context> context = debuggerContext(); | |
| 275 v8::Context::Scope contextScope(context); | |
| 276 | |
| 277 v8::Local<v8::Object> info = v8::Object::New(m_isolate); | |
| 278 bool success = false; | |
| 279 success = | |
| 280 info->Set(context, toV8StringInternalized(m_isolate, "breakpointId"), | |
| 281 toV8String(m_isolate, breakpointId)) | |
| 282 .FromMaybe(false); | |
| 283 DCHECK(success); | |
| 284 USE(success); | |
| 285 | |
| 286 v8::Local<v8::Function> removeBreakpointFunction = | |
| 287 v8::Local<v8::Function>::Cast( | |
| 288 m_debuggerScript.Get(m_isolate) | |
| 289 ->Get(context, | |
| 290 toV8StringInternalized(m_isolate, "removeBreakpoint")) | |
| 291 .ToLocalChecked()); | |
| 292 v8::debug::Call(debuggerContext(), removeBreakpointFunction, info) | |
| 293 .ToLocalChecked(); | |
| 294 } | |
| 295 | |
| 296 void V8Debugger::clearBreakpoints() { | |
| 297 v8::HandleScope scope(m_isolate); | |
| 298 v8::Local<v8::Context> context = debuggerContext(); | |
| 299 v8::Context::Scope contextScope(context); | |
| 300 | |
| 301 v8::Local<v8::Function> clearBreakpoints = v8::Local<v8::Function>::Cast( | |
| 302 m_debuggerScript.Get(m_isolate) | |
| 303 ->Get(context, toV8StringInternalized(m_isolate, "clearBreakpoints")) | |
| 304 .ToLocalChecked()); | |
| 305 v8::debug::Call(debuggerContext(), clearBreakpoints).ToLocalChecked(); | |
| 306 } | |
| 307 | |
| 308 void V8Debugger::setBreakpointsActivated(bool activated) { | 222 void V8Debugger::setBreakpointsActivated(bool activated) { |
| 309 if (!enabled()) { | 223 if (!enabled()) { |
| 310 UNREACHABLE(); | 224 UNREACHABLE(); |
| 311 return; | 225 return; |
| 312 } | 226 } |
| 313 v8::debug::SetBreakPointsActive(m_isolate, activated); | 227 v8::debug::SetBreakPointsActive(m_isolate, activated); |
| 314 m_breakpointsActivated = activated; | 228 m_breakpointsActivated = activated; |
| 315 } | 229 } |
| 316 | 230 |
| 317 v8::debug::ExceptionBreakState V8Debugger::getPauseOnExceptionsState() { | 231 v8::debug::ExceptionBreakState V8Debugger::getPauseOnExceptionsState() { |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 510 } | 424 } |
| 511 | 425 |
| 512 void V8Debugger::breakProgramCallback( | 426 void V8Debugger::breakProgramCallback( |
| 513 const v8::FunctionCallbackInfo<v8::Value>& info) { | 427 const v8::FunctionCallbackInfo<v8::Value>& info) { |
| 514 DCHECK_EQ(info.Length(), 2); | 428 DCHECK_EQ(info.Length(), 2); |
| 515 V8Debugger* thisPtr = toV8Debugger(info.Data()); | 429 V8Debugger* thisPtr = toV8Debugger(info.Data()); |
| 516 if (!thisPtr->enabled()) return; | 430 if (!thisPtr->enabled()) return; |
| 517 v8::Local<v8::Context> pausedContext = | 431 v8::Local<v8::Context> pausedContext = |
| 518 thisPtr->m_isolate->GetCurrentContext(); | 432 thisPtr->m_isolate->GetCurrentContext(); |
| 519 v8::Local<v8::Value> exception; | 433 v8::Local<v8::Value> exception; |
| 520 v8::Local<v8::Array> hitBreakpoints; | 434 v8::PersistentValueVector<v8::debug::BreakPoint> hitBreakpoints( |
| 435 thisPtr->m_isolate); |
| 521 thisPtr->handleProgramBreak(pausedContext, | 436 thisPtr->handleProgramBreak(pausedContext, |
| 522 v8::Local<v8::Object>::Cast(info[0]), exception, | 437 v8::Local<v8::Object>::Cast(info[0]), exception, |
| 523 hitBreakpoints); | 438 hitBreakpoints); |
| 524 } | 439 } |
| 525 | 440 |
| 526 void V8Debugger::handleProgramBreak(v8::Local<v8::Context> pausedContext, | 441 void V8Debugger::handleProgramBreak( |
| 527 v8::Local<v8::Object> executionState, | 442 v8::Local<v8::Context> pausedContext, v8::Local<v8::Object> executionState, |
| 528 v8::Local<v8::Value> exception, | 443 v8::Local<v8::Value> exception, |
| 529 v8::Local<v8::Array> hitBreakpointNumbers, | 444 const v8::PersistentValueVector<v8::debug::BreakPoint>& hitBreakPoints, |
| 530 bool isPromiseRejection, bool isUncaught) { | 445 bool isPromiseRejection, bool isUncaught) { |
| 531 // Don't allow nested breaks. | 446 // Don't allow nested breaks. |
| 532 if (isPaused()) return; | 447 if (isPaused()) return; |
| 533 | 448 |
| 534 V8DebuggerAgentImpl* agent = m_inspector->enabledDebuggerAgentForGroup( | 449 V8DebuggerAgentImpl* agent = m_inspector->enabledDebuggerAgentForGroup( |
| 535 m_inspector->contextGroupId(pausedContext)); | 450 m_inspector->contextGroupId(pausedContext)); |
| 536 if (!agent || (agent->skipAllPauses() && !m_scheduledOOMBreak)) return; | 451 if (!agent || (agent->skipAllPauses() && !m_scheduledOOMBreak)) return; |
| 537 | 452 |
| 538 std::vector<String16> breakpointIds; | |
| 539 if (!hitBreakpointNumbers.IsEmpty()) { | |
| 540 breakpointIds.reserve(hitBreakpointNumbers->Length()); | |
| 541 for (uint32_t i = 0; i < hitBreakpointNumbers->Length(); i++) { | |
| 542 v8::Local<v8::Value> hitBreakpointNumber = | |
| 543 hitBreakpointNumbers->Get(debuggerContext(), i).ToLocalChecked(); | |
| 544 DCHECK(hitBreakpointNumber->IsInt32()); | |
| 545 breakpointIds.push_back(String16::fromInteger( | |
| 546 hitBreakpointNumber->Int32Value(debuggerContext()).FromJust())); | |
| 547 } | |
| 548 } | |
| 549 | |
| 550 m_pausedContext = pausedContext; | 453 m_pausedContext = pausedContext; |
| 551 m_executionState = executionState; | 454 m_executionState = executionState; |
| 552 m_runningNestedMessageLoop = true; | 455 m_runningNestedMessageLoop = true; |
| 553 agent->didPause(InspectedContext::contextId(pausedContext), exception, | 456 agent->didPause(InspectedContext::contextId(pausedContext), exception, |
| 554 breakpointIds, isPromiseRejection, isUncaught, | 457 hitBreakPoints, isPromiseRejection, isUncaught, |
| 555 m_scheduledOOMBreak); | 458 m_scheduledOOMBreak); |
| 556 int groupId = m_inspector->contextGroupId(pausedContext); | 459 int groupId = m_inspector->contextGroupId(pausedContext); |
| 557 DCHECK(groupId); | 460 DCHECK(groupId); |
| 558 { | 461 { |
| 559 v8::Context::Scope scope(pausedContext); | 462 v8::Context::Scope scope(pausedContext); |
| 560 v8::Local<v8::Context> context = m_isolate->GetCurrentContext(); | 463 v8::Local<v8::Context> context = m_isolate->GetCurrentContext(); |
| 561 CHECK(!context.IsEmpty() && | 464 CHECK(!context.IsEmpty() && |
| 562 context != v8::debug::GetDebugContext(m_isolate)); | 465 context != v8::debug::GetDebugContext(m_isolate)); |
| 563 m_inspector->client()->runMessageLoopOnPause(groupId); | 466 m_inspector->client()->runMessageLoopOnPause(groupId); |
| 564 m_runningNestedMessageLoop = false; | 467 m_runningNestedMessageLoop = false; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 588 } else if (m_ignoreScriptParsedEventsCounter == 0) { | 491 } else if (m_ignoreScriptParsedEventsCounter == 0) { |
| 589 agent->didParseSource( | 492 agent->didParseSource( |
| 590 V8DebuggerScript::Create(m_isolate, script, inLiveEditScope), | 493 V8DebuggerScript::Create(m_isolate, script, inLiveEditScope), |
| 591 !has_compile_error); | 494 !has_compile_error); |
| 592 } | 495 } |
| 593 } | 496 } |
| 594 | 497 |
| 595 void V8Debugger::BreakProgramRequested(v8::Local<v8::Context> pausedContext, | 498 void V8Debugger::BreakProgramRequested(v8::Local<v8::Context> pausedContext, |
| 596 v8::Local<v8::Object> execState, | 499 v8::Local<v8::Object> execState, |
| 597 v8::Local<v8::Value> breakPointsHit) { | 500 v8::Local<v8::Value> breakPointsHit) { |
| 598 v8::Local<v8::Value> argv[] = {breakPointsHit}; | 501 v8::PersistentValueVector<v8::debug::BreakPoint> breakPoints(m_isolate); |
| 599 v8::Local<v8::Value> hitBreakpoints; | 502 if (!breakPointsHit->IsArray()) { |
| 600 if (!callDebuggerMethod("getBreakpointNumbers", 1, argv, true) | 503 handleProgramBreak(pausedContext, execState, v8::Local<v8::Value>(), |
| 601 .ToLocal(&hitBreakpoints)) { | 504 breakPoints); |
| 602 return; | 505 return; |
| 603 } | 506 } |
| 604 DCHECK(hitBreakpoints->IsArray()); | 507 v8::Local<v8::Array> breakPointsHitArray = |
| 508 v8::Local<v8::Array>::Cast(breakPointsHit); |
| 509 for (uint32_t i = 0; i < breakPointsHitArray->Length(); ++i) { |
| 510 v8::Local<v8::Value> item; |
| 511 if (!breakPointsHitArray->Get(pausedContext, i).ToLocal(&item)) continue; |
| 512 v8::Local<v8::debug::BreakPoint> breakPoint; |
| 513 if (!v8::debug::BreakPoint::Cast(m_isolate, item).ToLocal(&breakPoint)) { |
| 514 continue; |
| 515 } |
| 516 breakPoints.Append(breakPoint); |
| 517 } |
| 605 handleProgramBreak(pausedContext, execState, v8::Local<v8::Value>(), | 518 handleProgramBreak(pausedContext, execState, v8::Local<v8::Value>(), |
| 606 hitBreakpoints.As<v8::Array>()); | 519 breakPoints); |
| 607 } | 520 } |
| 608 | 521 |
| 609 void V8Debugger::ExceptionThrown(v8::Local<v8::Context> pausedContext, | 522 void V8Debugger::ExceptionThrown(v8::Local<v8::Context> pausedContext, |
| 610 v8::Local<v8::Object> execState, | 523 v8::Local<v8::Object> execState, |
| 611 v8::Local<v8::Value> exception, | 524 v8::Local<v8::Value> exception, |
| 612 v8::Local<v8::Value> promise, | 525 v8::Local<v8::Value> promise, |
| 613 bool isUncaught) { | 526 bool isUncaught) { |
| 614 bool isPromiseRejection = promise->IsPromise(); | 527 bool isPromiseRejection = promise->IsPromise(); |
| 615 handleProgramBreak(pausedContext, execState, exception, | 528 v8::PersistentValueVector<v8::debug::BreakPoint> hitBreakpoints(m_isolate); |
| 616 v8::Local<v8::Array>(), isPromiseRejection, isUncaught); | 529 handleProgramBreak(pausedContext, execState, exception, hitBreakpoints, |
| 530 isPromiseRejection, isUncaught); |
| 617 } | 531 } |
| 618 | 532 |
| 619 bool V8Debugger::IsFunctionBlackboxed(v8::Local<v8::debug::Script> script, | 533 bool V8Debugger::IsFunctionBlackboxed(v8::Local<v8::debug::Script> script, |
| 620 const v8::debug::Location& start, | 534 const v8::debug::Location& start, |
| 621 const v8::debug::Location& end) { | 535 const v8::debug::Location& end) { |
| 622 V8DebuggerAgentImpl* agent = agentForScript(m_inspector, script); | 536 V8DebuggerAgentImpl* agent = agentForScript(m_inspector, script); |
| 623 if (!agent) return false; | 537 if (!agent) return false; |
| 624 return agent->isFunctionBlackboxed(String16::fromInteger(script->Id()), start, | 538 return agent->isFunctionBlackboxed(String16::fromInteger(script->Id()), start, |
| 625 end); | 539 end); |
| 626 } | 540 } |
| (...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 960 | 874 |
| 961 size_t stackSize = | 875 size_t stackSize = |
| 962 fullStack ? V8StackTraceImpl::maxCallStackSizeToCapture : 1; | 876 fullStack ? V8StackTraceImpl::maxCallStackSizeToCapture : 1; |
| 963 if (m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) | 877 if (m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) |
| 964 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; | 878 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; |
| 965 | 879 |
| 966 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); | 880 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); |
| 967 } | 881 } |
| 968 | 882 |
| 969 } // namespace v8_inspector | 883 } // namespace v8_inspector |
| OLD | NEW |