Changeset 266074 in webkit for trunk/Source/JavaScriptCore/debugger/Debugger.cpp
- Timestamp:
- Aug 24, 2020, 10:34:12 AM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/debugger/Debugger.cpp
r261895 r266074 25 25 #include "CodeBlock.h" 26 26 #include "DebuggerCallFrame.h" 27 #include "DebuggerScope.h" 27 28 #include "HeapIterationScope.h" 28 29 #include "JSCInlines.h" 29 30 #include "MarkedSpaceInlines.h" 30 31 #include "VMEntryScope.h" 32 #include <wtf/HashMap.h> 33 #include <wtf/HashSet.h> 34 #include <wtf/RefPtr.h> 35 #include <wtf/Vector.h> 36 #include <wtf/text/TextPosition.h> 31 37 32 38 namespace JSC { … … 90 96 , m_lastExecutedLine(UINT_MAX) 91 97 , m_lastExecutedSourceID(noSourceID) 92 , m_topBreakpointID(noBreakpointID)93 98 , m_pausingBreakpointID(noBreakpointID) 94 99 { … … 206 211 } 207 212 213 void Debugger::addObserver(Observer& observer) 214 { 215 bool wasEmpty = m_observers.isEmpty(); 216 217 m_observers.add(&observer); 218 219 if (wasEmpty) 220 attachDebugger(); 221 } 222 223 void Debugger::removeObserver(Observer& observer, bool isBeingDestroyed) 224 { 225 m_observers.remove(&observer); 226 227 if (m_observers.isEmpty()) 228 detachDebugger(isBeingDestroyed); 229 } 230 231 bool Debugger::canDispatchFunctionToObservers() const 232 { 233 return !m_dispatchingFunctionToObservers && !m_observers.isEmpty(); 234 } 235 236 void Debugger::dispatchFunctionToObservers(Function<void(Observer&)> func) 237 { 238 if (!canDispatchFunctionToObservers()) 239 return; 240 241 SetForScope<bool> change(m_dispatchingFunctionToObservers, true); 242 243 for (auto* observer : copyToVector(m_observers)) 244 func(*observer); 245 } 246 208 247 void Debugger::setProfilingClient(ProfilingClient* client) 209 248 { … … 212 251 } 213 252 253 void Debugger::sourceParsed(JSGlobalObject* globalObject, SourceProvider* sourceProvider, int errorLine, const String& errorMessage) 254 { 255 // Preemptively check whether we can dispatch so that we don't do any unnecessary allocations. 256 if (!canDispatchFunctionToObservers()) 257 return; 258 259 if (errorLine != -1) { 260 auto sourceURL = sourceProvider->sourceURL(); 261 auto data = sourceProvider->source().toString(); 262 auto firstLine = sourceProvider->startPosition().m_line.oneBasedInt(); 263 dispatchFunctionToObservers([&] (Observer& observer) { 264 observer.failedToParseSource(sourceURL, data, firstLine, errorLine, errorMessage); 265 }); 266 return; 267 } 268 269 JSC::SourceID sourceID = sourceProvider->asID(); 270 271 // FIXME: <https://webkit.org/b/162773> Web Inspector: Simplify Debugger::Script to use SourceProvider 272 Debugger::Script script; 273 script.sourceProvider = sourceProvider; 274 script.url = sourceProvider->sourceURL(); 275 script.source = sourceProvider->source().toString(); 276 script.startLine = sourceProvider->startPosition().m_line.zeroBasedInt(); 277 script.startColumn = sourceProvider->startPosition().m_column.zeroBasedInt(); 278 script.isContentScript = isContentScript(globalObject); 279 script.sourceURL = sourceProvider->sourceURLDirective(); 280 script.sourceMappingURL = sourceProvider->sourceMappingURLDirective(); 281 282 int sourceLength = script.source.length(); 283 int lineCount = 1; 284 int lastLineStart = 0; 285 for (int i = 0; i < sourceLength; ++i) { 286 if (script.source[i] == '\n') { 287 lineCount += 1; 288 lastLineStart = i + 1; 289 } 290 } 291 292 script.endLine = script.startLine + lineCount - 1; 293 if (lineCount == 1) 294 script.endColumn = script.startColumn + sourceLength; 295 else 296 script.endColumn = sourceLength - lastLineStart; 297 298 dispatchFunctionToObservers([&] (Observer& observer) { 299 observer.didParseSource(sourceID, script); 300 }); 301 } 302 214 303 Seconds Debugger::willEvaluateScript() 215 304 { … … 224 313 void Debugger::toggleBreakpoint(CodeBlock* codeBlock, Breakpoint& breakpoint, BreakpointState enabledOrNot) 225 314 { 226 ASSERT(breakpoint. resolved);315 ASSERT(breakpoint.isResolved()); 227 316 228 317 ScriptExecutable* executable = codeBlock->ownerExecutable(); 229 318 230 319 SourceID sourceID = static_cast<SourceID>(executable->sourceID()); 231 if (breakpoint.sourceID != sourceID)320 if (breakpoint.sourceID() != sourceID) 232 321 return; 233 322 … … 239 328 // Inspector breakpoint line and column values are zero-based but the executable 240 329 // and CodeBlock line and column values are one-based. 241 unsigned line = breakpoint.line + 1;330 unsigned line = breakpoint.lineNumber() + 1; 242 331 Optional<unsigned> column; 243 if (breakpoint.column )244 column = breakpoint.column + 1;332 if (breakpoint.columnNumber()) 333 column = breakpoint.columnNumber() + 1; 245 334 246 335 if (line < startLine || line > endLine) … … 264 353 void Debugger::applyBreakpoints(CodeBlock* codeBlock) 265 354 { 266 BreakpointIDToBreakpointMap& breakpoints = m_breakpointIDToBreakpoint; 267 for (auto* breakpoint : breakpoints.values()) 268 toggleBreakpoint(codeBlock, *breakpoint, BreakpointEnabled); 355 for (auto& breakpoint : m_breakpoints) 356 toggleBreakpoint(codeBlock, breakpoint, BreakpointEnabled); 269 357 } 270 358 … … 315 403 } 316 404 317 voidDebugger::resolveBreakpoint(Breakpoint& breakpoint, SourceProvider* sourceProvider)318 { 319 RELEASE_ASSERT(!breakpoint. resolved);320 ASSERT(breakpoint. sourceID != noSourceID);405 bool Debugger::resolveBreakpoint(Breakpoint& breakpoint, SourceProvider* sourceProvider) 406 { 407 RELEASE_ASSERT(!breakpoint.isResolved()); 408 ASSERT(breakpoint.isLinked()); 321 409 322 410 // FIXME: <https://webkit.org/b/162771> Web Inspector: Adopt TextPosition in Inspector to avoid oneBasedInt/zeroBasedInt ambiguity 323 411 // Inspector breakpoint line and column values are zero-based but the executable 324 412 // and CodeBlock line values are one-based while column is zero-based. 325 int line = breakpoint.line + 1;326 int column = breakpoint.column ;413 int line = breakpoint.lineNumber() + 1; 414 int column = breakpoint.columnNumber(); 327 415 328 416 // Account for a <script>'s start position on the first line only. 329 417 int providerStartLine = sourceProvider->startPosition().m_line.oneBasedInt(); // One based to match the already adjusted line. 330 418 int providerStartColumn = sourceProvider->startPosition().m_column.zeroBasedInt(); // Zero based so column zero is zero. 331 if (line == providerStartLine && breakpoint.column ) {419 if (line == providerStartLine && breakpoint.columnNumber()) { 332 420 ASSERT(providerStartColumn <= column); 333 421 if (providerStartColumn) … … 335 423 } 336 424 337 DebuggerParseData& parseData = debuggerParseData(breakpoint.sourceID , sourceProvider);425 DebuggerParseData& parseData = debuggerParseData(breakpoint.sourceID(), sourceProvider); 338 426 Optional<JSTextPosition> resolvedPosition = parseData.pausePositions.breakpointLocationForLineColumn(line, column); 339 427 if (!resolvedPosition) 340 return ;428 return false; 341 429 342 430 int resolvedLine = resolvedPosition->line; … … 344 432 345 433 // Re-account for a <script>'s start position on the first line only. 346 if (resolvedLine == providerStartLine && breakpoint.column ) {434 if (resolvedLine == providerStartLine && breakpoint.columnNumber()) { 347 435 if (providerStartColumn) 348 436 resolvedColumn += providerStartColumn; 349 437 } 350 438 351 breakpoint.line = resolvedLine - 1; 352 breakpoint.column = resolvedColumn; 353 breakpoint.resolved = true; 354 } 355 356 BreakpointID Debugger::setBreakpoint(Breakpoint& breakpoint, bool& existing) 357 { 358 ASSERT(breakpoint.resolved); 359 ASSERT(breakpoint.sourceID != noSourceID); 360 361 SourceID sourceID = breakpoint.sourceID; 362 unsigned line = breakpoint.line; 363 unsigned column = breakpoint.column; 364 365 SourceIDToBreakpointsMap::iterator it = m_sourceIDToBreakpoints.find(breakpoint.sourceID); 366 if (it == m_sourceIDToBreakpoints.end()) 367 it = m_sourceIDToBreakpoints.set(sourceID, LineToBreakpointsMap()).iterator; 368 369 LineToBreakpointsMap::iterator breaksIt = it->value.find(line); 370 if (breaksIt == it->value.end()) 371 breaksIt = it->value.set(line, adoptRef(new BreakpointsList)).iterator; 372 373 BreakpointsList& breakpoints = *breaksIt->value; 374 for (Breakpoint* current = breakpoints.head(); current; current = current->next()) { 375 if (current->column == column) { 439 return breakpoint.resolve(resolvedLine - 1, resolvedColumn); 440 } 441 442 bool Debugger::setBreakpoint(Breakpoint& breakpoint) 443 { 444 ASSERT(breakpoint.isResolved()); 445 446 auto& breakpointsForLine = m_breakpointsForSourceID.ensure(breakpoint.sourceID(), [] { 447 return LineToBreakpointsMap(); 448 }).iterator->value; 449 450 auto& breakpoints = breakpointsForLine.ensure(breakpoint.lineNumber(), [] { 451 return BreakpointsVector(); 452 }).iterator->value; 453 454 for (auto& existingBreakpoint : breakpoints) { 455 if (existingBreakpoint->columnNumber() == breakpoint.columnNumber()) { 456 ASSERT(existingBreakpoint->id() != breakpoint.id()); 376 457 // Found existing breakpoint. Do not create a duplicate at this location. 377 existing = true; 378 return current->id; 458 return false; 379 459 } 380 460 } 381 461 382 existing = false; 383 BreakpointID id = ++m_topBreakpointID; 384 RELEASE_ASSERT(id != noBreakpointID); 385 386 breakpoint.id = id; 387 388 Breakpoint* newBreakpoint = new Breakpoint(breakpoint); 389 breakpoints.append(newBreakpoint); 390 m_breakpointIDToBreakpoint.set(id, newBreakpoint); 391 392 toggleBreakpoint(*newBreakpoint, BreakpointEnabled); 393 394 return id; 395 } 396 397 void Debugger::removeBreakpoint(BreakpointID id) 398 { 399 ASSERT(id != noBreakpointID); 400 401 BreakpointIDToBreakpointMap::iterator idIt = m_breakpointIDToBreakpoint.find(id); 402 ASSERT(idIt != m_breakpointIDToBreakpoint.end()); 403 Breakpoint* breakpoint = idIt->value; 404 405 SourceID sourceID = breakpoint->sourceID; 406 ASSERT(sourceID); 407 SourceIDToBreakpointsMap::iterator it = m_sourceIDToBreakpoints.find(sourceID); 408 ASSERT(it != m_sourceIDToBreakpoints.end()); 409 LineToBreakpointsMap::iterator breaksIt = it->value.find(breakpoint->line); 410 ASSERT(breaksIt != it->value.end()); 411 412 toggleBreakpoint(*breakpoint, BreakpointDisabled); 413 414 BreakpointsList& breakpoints = *breaksIt->value; 462 breakpoints.append(makeRef(breakpoint)); 463 464 m_breakpoints.add(makeRef(breakpoint)); 465 466 toggleBreakpoint(breakpoint, BreakpointEnabled); 467 468 return true; 469 } 470 471 bool Debugger::removeBreakpoint(Breakpoint& breakpoint) 472 { 473 ASSERT(breakpoint.isResolved()); 474 475 auto breakpointsForLineIterator = m_breakpointsForSourceID.find(breakpoint.sourceID()); 476 if (breakpointsForLineIterator == m_breakpointsForSourceID.end()) 477 return false; 478 479 auto breakpointsIterator = breakpointsForLineIterator->value.find(breakpoint.lineNumber()); 480 if (breakpointsIterator == breakpointsForLineIterator->value.end()) 481 return false; 482 483 toggleBreakpoint(breakpoint, BreakpointDisabled); 484 485 auto& breakpoints = breakpointsIterator->value; 486 415 487 #if ASSERT_ENABLED 416 488 bool found = false; 417 for (Breakpoint* current = breakpoints.head(); current && !found; current = current->next()) { 418 if (current->id == breakpoint->id) 489 for (auto& existingBreakpoint : breakpoints) { 490 if (existingBreakpoint->columnNumber() == breakpoint.columnNumber()) { 491 ASSERT(existingBreakpoint->id() == breakpoint.id()); 492 ASSERT(!found); 419 493 found = true; 420 }421 ASSERT(found);494 } 495 } 422 496 #endif // ASSERT_ENABLED 423 497 424 m_breakpointIDToBreakpoint.remove(idIt); 425 breakpoints.remove(breakpoint); 426 delete breakpoint; 498 auto removed = m_breakpoints.remove(breakpoint); 499 removed |= !breakpoints.removeAllMatching([&] (const Ref<Breakpoint>& existingBreakpoint) { 500 return &breakpoint == existingBreakpoint.ptr(); 501 }); 427 502 428 503 if (breakpoints.isEmpty()) { 429 it->value.remove(breaksIt); 430 if (it->value.isEmpty()) 431 m_sourceIDToBreakpoints.remove(it); 432 } 433 } 434 435 bool Debugger::hasBreakpoint(SourceID sourceID, const TextPosition& position, Breakpoint *hitBreakpoint) 504 breakpointsForLineIterator->value.remove(breakpointsIterator); 505 if (breakpointsForLineIterator->value.isEmpty()) 506 m_breakpointsForSourceID.remove(breakpointsForLineIterator); 507 } 508 509 return removed; 510 } 511 512 RefPtr<Breakpoint> Debugger::didHitBreakpoint(JSGlobalObject* globalObject, SourceID sourceID, const TextPosition& position) 436 513 { 437 514 if (!m_breakpointsActivated) 438 return false;439 440 SourceIDToBreakpointsMap::const_iterator it = m_sourceIDToBreakpoints.find(sourceID);441 if ( it == m_sourceIDToBreakpoints.end())442 return false;515 return nullptr; 516 517 auto breakpointsForLineIterator = m_breakpointsForSourceID.find(sourceID); 518 if (breakpointsForLineIterator == m_breakpointsForSourceID.end()) 519 return nullptr; 443 520 444 521 unsigned line = position.m_line.zeroBasedInt(); 445 522 unsigned column = position.m_column.zeroBasedInt(); 446 523 447 LineToBreakpointsMap::const_iterator breaksIt = it->value.find(line); 448 if (breaksIt == it->value.end()) 449 return false; 450 451 bool hit = false; 452 const BreakpointsList& breakpoints = *breaksIt->value; 453 Breakpoint* breakpoint; 454 for (breakpoint = breakpoints.head(); breakpoint; breakpoint = breakpoint->next()) { 455 unsigned breakLine = breakpoint->line; 456 unsigned breakColumn = breakpoint->column; 524 auto breakpointsIterator = breakpointsForLineIterator->value.find(line); 525 if (breakpointsIterator == breakpointsForLineIterator->value.end()) 526 return nullptr; 527 528 for (auto& breakpoint : breakpointsIterator->value) { 529 unsigned breakLine = breakpoint->lineNumber(); 530 unsigned breakColumn = breakpoint->columnNumber(); 531 457 532 // Since frontend truncates the indent, the first statement in a line must match the breakpoint (line,0). 458 533 ASSERT(this == m_currentCallFrame->codeBlock()->globalObject()->debugger()); 459 if ((line != m_lastExecutedLine && line == breakLine && !breakColumn) 460 || (line == breakLine && column == breakColumn)) {461 hit = true;534 if ((line != m_lastExecutedLine && line == breakLine && !breakColumn) || (line == breakLine && column == breakColumn)) { 535 if (breakpoint->shouldPause(*this, globalObject)) 536 return breakpoint.copyRef(); 462 537 break; 463 538 } 464 539 } 465 if (!hit) 466 return false; 467 468 if (hitBreakpoint) 469 *hitBreakpoint = *breakpoint; 470 471 breakpoint->hitCount++; 472 if (breakpoint->ignoreCount >= breakpoint->hitCount) 473 return false; 474 475 if (breakpoint->condition.isEmpty()) 476 return true; 477 478 // We cannot stop in the debugger while executing condition code, 479 // so make it looks like the debugger is already paused. 480 TemporaryPausedState pausedState(*this); 481 482 NakedPtr<Exception> exception; 483 DebuggerCallFrame& debuggerCallFrame = currentDebuggerCallFrame(); 484 JSObject* scopeExtensionObject = nullptr; 485 JSValue result = debuggerCallFrame.evaluateWithScopeExtension(breakpoint->condition, scopeExtensionObject, exception); 486 487 // We can lose the debugger while executing JavaScript. 488 if (!m_currentCallFrame) 489 return false; 490 491 JSGlobalObject* globalObject = m_currentCallFrame->lexicalGlobalObject(m_vm); 492 if (exception) { 493 // An erroneous condition counts as "false". 494 handleExceptionInBreakpointCondition(globalObject, exception); 495 return false; 496 } 497 498 return result.toBoolean(globalObject); 540 541 return nullptr; 499 542 } 500 543 … … 520 563 m_vm.heap.completeAllJITPlans(); 521 564 522 m_ topBreakpointID = noBreakpointID;523 m_breakpoint IDToBreakpoint.clear();524 m_s ourceIDToBreakpoints.clear();565 m_breakpointsForSourceID.clear(); 566 m_breakpoints.clear(); 567 m_specialBreakpoint = nullptr; 525 568 526 569 ClearCodeBlockDebuggerRequestsFunctor functor(this); 527 570 m_vm.heap.forEachCodeBlock(functor); 571 } 572 573 bool Debugger::evaluateBreakpointCondition(Breakpoint& breakpoint, JSGlobalObject* globalObject) 574 { 575 const String& condition = breakpoint.condition(); 576 if (condition.isEmpty()) 577 return true; 578 579 // We cannot stop in the debugger while executing condition code, 580 // so make it looks like the debugger is already paused. 581 TemporaryPausedState pausedState(*this); 582 583 NakedPtr<Exception> exception; 584 DebuggerCallFrame& debuggerCallFrame = currentDebuggerCallFrame(); 585 JSObject* scopeExtensionObject = nullptr; 586 JSValue result = debuggerCallFrame.evaluateWithScopeExtension(condition, scopeExtensionObject, exception); 587 588 // We can lose the debugger while executing JavaScript. 589 if (!m_currentCallFrame) 590 return false; 591 592 if (exception) { 593 reportException(globalObject, exception); 594 return false; 595 } 596 597 return result.toBoolean(globalObject); 598 } 599 600 void Debugger::evaluateBreakpointActions(Breakpoint& breakpoint, JSGlobalObject* globalObject) 601 { 602 ASSERT(m_isPaused); 603 ASSERT(isAttached(globalObject)); 604 605 m_currentProbeBatchId++; 606 607 for (auto& action : breakpoint.actions()) { 608 auto& debuggerCallFrame = currentDebuggerCallFrame(); 609 610 switch (action.type) { 611 case Breakpoint::Action::Type::Log: 612 dispatchFunctionToObservers([&] (Observer& observer) { 613 observer.breakpointActionLog(debuggerCallFrame.globalObject(), action.data); 614 }); 615 break; 616 617 case Breakpoint::Action::Type::Evaluate: { 618 NakedPtr<Exception> exception; 619 JSObject* scopeExtensionObject = nullptr; 620 debuggerCallFrame.evaluateWithScopeExtension(action.data, scopeExtensionObject, exception); 621 if (exception) 622 reportException(debuggerCallFrame.globalObject(), exception); 623 break; 624 } 625 626 case Breakpoint::Action::Type::Sound: 627 dispatchFunctionToObservers([&] (Observer& observer) { 628 observer.breakpointActionSound(action.id); 629 }); 630 break; 631 632 case Breakpoint::Action::Type::Probe: { 633 NakedPtr<Exception> exception; 634 JSObject* scopeExtensionObject = nullptr; 635 JSValue result = debuggerCallFrame.evaluateWithScopeExtension(action.data, scopeExtensionObject, exception); 636 JSC::JSGlobalObject* debuggerGlobalObject = debuggerCallFrame.globalObject(); 637 if (exception) 638 reportException(debuggerGlobalObject, exception); 639 640 dispatchFunctionToObservers([&] (Observer& observer) { 641 observer.breakpointActionProbe(debuggerGlobalObject, action.id, m_currentProbeBatchId, m_nextProbeSampleId++, exception ? exception->value() : result); 642 }); 643 break; 644 } 645 } 646 647 if (!isAttached(globalObject)) 648 return; 649 } 528 650 } 529 651 … … 572 694 } 573 695 574 void Debugger::setPauseOnNextStatement(bool pause) 575 { 576 m_pauseAtNextOpportunity = pause; 577 if (pause) 578 setSteppingMode(SteppingModeEnabled); 696 void Debugger::schedulePauseAtNextOpportunity() 697 { 698 m_pauseAtNextOpportunity = true; 699 700 setSteppingMode(SteppingModeEnabled); 701 } 702 703 void Debugger::cancelPauseAtNextOpportunity() 704 { 705 m_pauseAtNextOpportunity = false; 706 } 707 708 bool Debugger::schedulePauseForSpecialBreakpoint(Breakpoint& breakpoint) 709 { 710 if (m_specialBreakpoint) 711 return false; 712 713 m_specialBreakpoint = makeRef(breakpoint); 714 setSteppingMode(SteppingModeEnabled); 715 return true; 716 } 717 718 bool Debugger::cancelPauseForSpecialBreakpoint(Breakpoint& breakpoint) 719 { 720 if (&breakpoint != m_specialBreakpoint) 721 return false; 722 723 m_specialBreakpoint = nullptr; 724 return true; 579 725 } 580 726 … … 600 746 return; 601 747 602 notifyDoneProcessingDebuggerEvents();748 m_doneProcessingDebuggerEvents = true; 603 749 } 604 750 … … 611 757 m_pauseOnStepNext = true; 612 758 setSteppingMode(SteppingModeEnabled); 613 notifyDoneProcessingDebuggerEvents();759 m_doneProcessingDebuggerEvents = true; 614 760 } 615 761 … … 621 767 m_pauseAtNextOpportunity = true; 622 768 setSteppingMode(SteppingModeEnabled); 623 notifyDoneProcessingDebuggerEvents();769 m_doneProcessingDebuggerEvents = true; 624 770 } 625 771 … … 631 777 m_pauseOnCallFrame = m_currentCallFrame; 632 778 setSteppingMode(SteppingModeEnabled); 633 notifyDoneProcessingDebuggerEvents();779 m_doneProcessingDebuggerEvents = true; 634 780 } 635 781 … … 643 789 m_pauseOnStepOut = true; 644 790 setSteppingMode(SteppingModeEnabled); 645 notifyDoneProcessingDebuggerEvents();791 m_doneProcessingDebuggerEvents = true; 646 792 } 647 793 … … 702 848 bool didPauseForStep = pauseNow; 703 849 704 Breakpoint breakpoint;705 850 TextPosition position = DebuggerCallFrame::positionForCallFrame(vm, m_currentCallFrame); 706 bool didHitBreakpoint = hasBreakpoint(sourceID, position, &breakpoint); 707 pauseNow |= didHitBreakpoint; 851 852 auto breakpoint = didHitBreakpoint(globalObject, sourceID, position); 853 if (breakpoint) 854 pauseNow = true; 855 856 // Special breakpoints are only given one opportunity to pause. 857 auto specialBreakpoint = WTFMove(m_specialBreakpoint); 858 if (specialBreakpoint && specialBreakpoint->shouldPause(*this, globalObject)) 859 pauseNow = true; 860 708 861 m_lastExecutedLine = position.m_line.zeroBasedInt(); 709 862 if (!pauseNow) … … 717 870 TemporaryPausedState pausedState(*this); 718 871 719 if (didHitBreakpoint) { 720 handleBreakpointHit(globalObject, breakpoint); 872 if (breakpoint || specialBreakpoint) { 721 873 // Note that the actions can potentially stop the debugger, so we need to check that 722 874 // we still have a current call frame when we get back. 723 if (!m_currentCallFrame) 724 return; 725 726 if (breakpoint.autoContinue) { 875 876 bool autoContinue = false; 877 878 if (breakpoint) { 879 evaluateBreakpointActions(*breakpoint, globalObject); 880 881 if (!m_currentCallFrame) 882 return; 883 884 if (breakpoint->isAutoContinue()) 885 autoContinue = true; 886 } 887 888 if (specialBreakpoint) { 889 evaluateBreakpointActions(*specialBreakpoint, globalObject); 890 891 if (!m_currentCallFrame) 892 return; 893 894 if (specialBreakpoint->isAutoContinue()) 895 autoContinue = true; 896 } 897 898 if (autoContinue) { 727 899 if (!didPauseForStep) 728 900 return; 729 didHitBreakpoint = false; 730 } else 731 m_pausingBreakpointID = breakpoint.id; 901 902 breakpoint = nullptr; 903 specialBreakpoint = nullptr; 904 } else if (breakpoint) 905 m_pausingBreakpointID = breakpoint->id(); 732 906 } 733 907 734 908 if (blackboxTypeIterator != m_blackboxedScripts.end() && blackboxTypeIterator->value == BlackboxType::Deferred) { 735 909 m_afterBlackboxedScript = true; 736 s etPauseOnNextStatement(true);910 schedulePauseAtNextOpportunity(); 737 911 return; 738 912 } … … 742 916 if (afterBlackboxedScript) 743 917 reason = PausedAfterBlackboxedScript; 744 else if ( didHitBreakpoint)918 else if (breakpoint) 745 919 reason = PausedForBreakpoint; 746 920 PauseReasonDeclaration rauseReasonDeclaration(*this, reason); … … 752 926 m_pausingBreakpointID = noBreakpointID; 753 927 754 if (!m_pauseAtNextOpportunity && !m_pauseOnCallFrame ) {928 if (!m_pauseAtNextOpportunity && !m_pauseOnCallFrame && !m_specialBreakpoint) { 755 929 setSteppingMode(SteppingModeDisabled); 756 930 m_currentCallFrame = nullptr; 757 931 } 932 } 933 934 void Debugger::handlePause(JSGlobalObject* globalObject, ReasonForPause) 935 { 936 dispatchFunctionToObservers([&] (Observer& observer) { 937 ASSERT(isPaused()); 938 observer.didPause(globalObject, currentDebuggerCallFrame(), exceptionOrCaughtValue(globalObject)); 939 }); 940 941 didPause(globalObject); 942 943 m_doneProcessingDebuggerEvents = false; 944 runEventLoopWhilePaused(); 945 946 didContinue(globalObject); 947 948 dispatchFunctionToObservers([&] (Observer& observer) { 949 observer.didContinue(); 950 }); 951 } 952 953 JSC::JSValue Debugger::exceptionOrCaughtValue(JSC::JSGlobalObject* globalObject) 954 { 955 if (reasonForPause() == PausedForException) 956 return currentException(); 957 958 for (RefPtr<DebuggerCallFrame> frame = ¤tDebuggerCallFrame(); frame; frame = frame->callerFrame()) { 959 DebuggerScope& scope = *frame->scope(); 960 if (scope.isCatchScope()) 961 return scope.caughtValue(globalObject); 962 } 963 964 return { }; 758 965 } 759 966 … … 808 1015 } 809 1016 810 // Only pause at the next expression with step-in, step-next, and step-out.811 bool shouldAttemptPause = m_pauseAtNextOpportunity || m_pauseOnStepNext || m_pauseOnStepOut ;1017 // Only pause at the next expression for step-in, step-next, step-out, or special breakpoints. 1018 bool shouldAttemptPause = m_pauseAtNextOpportunity || m_pauseOnStepNext || m_pauseOnStepOut || m_specialBreakpoint; 812 1019 813 1020 PauseReasonDeclaration reason(*this, PausedAtExpression); … … 918 1125 m_pauseOnStepOut = false; 919 1126 m_afterBlackboxedScript = false; 1127 m_specialBreakpoint = nullptr; 920 1128 } 921 1129 … … 934 1142 } 935 1143 1144 void Debugger::willRunMicrotask() 1145 { 1146 dispatchFunctionToObservers([&] (Observer& observer) { 1147 observer.willRunMicrotask(); 1148 }); 1149 } 1150 1151 void Debugger::didRunMicrotask() 1152 { 1153 dispatchFunctionToObservers([&] (Observer& observer) { 1154 observer.didRunMicrotask(); 1155 }); 1156 } 1157 936 1158 DebuggerCallFrame& Debugger::currentDebuggerCallFrame() 937 1159 {
Note:
See TracChangeset
for help on using the changeset viewer.