1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_DEBUG_DEBUG_H_ 6 #define V8_DEBUG_DEBUG_H_ 7 8 #include <memory> 9 #include <vector> 10 11 #include "src/base/enum-set.h" 12 #include "src/codegen/source-position-table.h" 13 #include "src/common/globals.h" 14 #include "src/debug/debug-interface.h" 15 #include "src/debug/interface-types.h" 16 #include "src/execution/interrupts-scope.h" 17 #include "src/execution/isolate.h" 18 #include "src/handles/handles.h" 19 #include "src/objects/debug-objects.h" 20 #include "src/objects/shared-function-info.h" 21 22 namespace v8 { 23 namespace internal { 24 25 // Forward declarations. 26 class AbstractCode; 27 class DebugScope; 28 class InterpretedFrame; 29 class JavaScriptFrame; 30 class JSGeneratorObject; 31 class StackFrame; 32 33 // Step actions. 34 enum StepAction : int8_t { 35 StepNone = -1, // Stepping not prepared. 36 StepOut = 0, // Step out of the current function. 37 StepOver = 1, // Step to the next statement in the current function. 38 StepInto = 2, // Step into new functions invoked or the next statement 39 // in the current function. 40 LastStepAction = StepInto 41 }; 42 43 // Type of exception break. NOTE: These values are in macros.py as well. 44 enum ExceptionBreakType { BreakException = 0, BreakUncaughtException = 1 }; 45 46 // Type of debug break. NOTE: The order matters for the predicates 47 // below inside BreakLocation, so be careful when adding / removing. 48 enum DebugBreakType { 49 NOT_DEBUG_BREAK, 50 DEBUGGER_STATEMENT, 51 DEBUG_BREAK_AT_ENTRY, 52 DEBUG_BREAK_SLOT, 53 DEBUG_BREAK_SLOT_AT_CALL, 54 DEBUG_BREAK_SLOT_AT_RETURN, 55 DEBUG_BREAK_SLOT_AT_SUSPEND, 56 }; 57 58 enum IgnoreBreakMode { 59 kIgnoreIfAllFramesBlackboxed, 60 kIgnoreIfTopFrameBlackboxed 61 }; 62 63 class BreakLocation { 64 public: Invalid()65 static BreakLocation Invalid() { return BreakLocation(-1, NOT_DEBUG_BREAK); } 66 static BreakLocation FromFrame(Handle<DebugInfo> debug_info, 67 JavaScriptFrame* frame); 68 69 static void AllAtCurrentStatement(Handle<DebugInfo> debug_info, 70 JavaScriptFrame* frame, 71 std::vector<BreakLocation>* result_out); 72 IsSuspend()73 bool IsSuspend() const { return type_ == DEBUG_BREAK_SLOT_AT_SUSPEND; } IsReturn()74 bool IsReturn() const { return type_ == DEBUG_BREAK_SLOT_AT_RETURN; } IsReturnOrSuspend()75 bool IsReturnOrSuspend() const { return type_ >= DEBUG_BREAK_SLOT_AT_RETURN; } IsCall()76 bool IsCall() const { return type_ == DEBUG_BREAK_SLOT_AT_CALL; } IsDebugBreakSlot()77 bool IsDebugBreakSlot() const { return type_ >= DEBUG_BREAK_SLOT; } IsDebuggerStatement()78 bool IsDebuggerStatement() const { return type_ == DEBUGGER_STATEMENT; } IsDebugBreakAtEntry()79 bool IsDebugBreakAtEntry() const { return type_ == DEBUG_BREAK_AT_ENTRY; } 80 81 bool HasBreakPoint(Isolate* isolate, Handle<DebugInfo> debug_info) const; 82 generator_suspend_id()83 int generator_suspend_id() { return generator_suspend_id_; } position()84 int position() const { return position_; } 85 86 debug::BreakLocationType type() const; 87 88 JSGeneratorObject GetGeneratorObjectForSuspendedFrame( 89 JavaScriptFrame* frame) const; 90 91 private: BreakLocation(Handle<AbstractCode> abstract_code,DebugBreakType type,int code_offset,int position,int generator_obj_reg_index,int generator_suspend_id)92 BreakLocation(Handle<AbstractCode> abstract_code, DebugBreakType type, 93 int code_offset, int position, int generator_obj_reg_index, 94 int generator_suspend_id) 95 : abstract_code_(abstract_code), 96 code_offset_(code_offset), 97 type_(type), 98 position_(position), 99 generator_obj_reg_index_(generator_obj_reg_index), 100 generator_suspend_id_(generator_suspend_id) { 101 DCHECK_NE(NOT_DEBUG_BREAK, type_); 102 } 103 BreakLocation(int position,DebugBreakType type)104 BreakLocation(int position, DebugBreakType type) 105 : code_offset_(0), 106 type_(type), 107 position_(position), 108 generator_obj_reg_index_(0), 109 generator_suspend_id_(-1) {} 110 111 static int BreakIndexFromCodeOffset(Handle<DebugInfo> debug_info, 112 Handle<AbstractCode> abstract_code, 113 int offset); 114 115 void SetDebugBreak(); 116 void ClearDebugBreak(); 117 118 Handle<AbstractCode> abstract_code_; 119 int code_offset_; 120 DebugBreakType type_; 121 int position_; 122 int generator_obj_reg_index_; 123 int generator_suspend_id_; 124 125 friend class BreakIterator; 126 }; 127 128 class V8_EXPORT_PRIVATE BreakIterator { 129 public: 130 explicit BreakIterator(Handle<DebugInfo> debug_info); 131 BreakIterator(const BreakIterator&) = delete; 132 BreakIterator& operator=(const BreakIterator&) = delete; 133 134 BreakLocation GetBreakLocation(); Done()135 bool Done() const { return source_position_iterator_.done(); } 136 void Next(); 137 138 void SkipToPosition(int position); SkipTo(int count)139 void SkipTo(int count) { 140 while (count-- > 0) Next(); 141 } 142 code_offset()143 int code_offset() { return source_position_iterator_.code_offset(); } break_index()144 int break_index() const { return break_index_; } position()145 inline int position() const { return position_; } statement_position()146 inline int statement_position() const { return statement_position_; } 147 148 void ClearDebugBreak(); 149 void SetDebugBreak(); 150 151 private: 152 int BreakIndexFromPosition(int position); 153 154 Isolate* isolate(); 155 156 DebugBreakType GetDebugBreakType(); 157 158 Handle<DebugInfo> debug_info_; 159 int break_index_; 160 int position_; 161 int statement_position_; 162 SourcePositionTableIterator source_position_iterator_; 163 DISALLOW_GARBAGE_COLLECTION(no_gc_) 164 }; 165 166 // Linked list holding debug info objects. The debug info objects are kept as 167 // weak handles to avoid a debug info object to keep a function alive. 168 class DebugInfoListNode { 169 public: 170 DebugInfoListNode(Isolate* isolate, DebugInfo debug_info); 171 ~DebugInfoListNode(); 172 next()173 DebugInfoListNode* next() { return next_; } set_next(DebugInfoListNode * next)174 void set_next(DebugInfoListNode* next) { next_ = next; } debug_info()175 Handle<DebugInfo> debug_info() { return Handle<DebugInfo>(debug_info_); } 176 177 private: 178 // Global (weak) handle to the debug info object. 179 Address* debug_info_; 180 181 // Next pointer for linked list. 182 DebugInfoListNode* next_; 183 }; 184 185 class DebugFeatureTracker { 186 public: 187 enum Feature { 188 kActive = 1, 189 kBreakPoint = 2, 190 kStepping = 3, 191 kHeapSnapshot = 4, 192 kAllocationTracking = 5, 193 kProfiler = 6, 194 kLiveEdit = 7, 195 }; 196 DebugFeatureTracker(Isolate * isolate)197 explicit DebugFeatureTracker(Isolate* isolate) 198 : isolate_(isolate), bitfield_(0) {} 199 void Track(Feature feature); 200 201 private: 202 Isolate* isolate_; 203 uint32_t bitfield_; 204 }; 205 206 // This class contains the debugger support. The main purpose is to handle 207 // setting break points in the code. 208 // 209 // This class controls the debug info for all functions which currently have 210 // active breakpoints in them. This debug info is held in the heap root object 211 // debug_info which is a FixedArray. Each entry in this list is of class 212 // DebugInfo. 213 class V8_EXPORT_PRIVATE Debug { 214 public: 215 Debug(const Debug&) = delete; 216 Debug& operator=(const Debug&) = delete; 217 218 // Debug event triggers. 219 void OnDebugBreak(Handle<FixedArray> break_points_hit, StepAction stepAction, 220 debug::BreakReasons break_reasons = {}); 221 void OnInstrumentationBreak(); 222 223 base::Optional<Object> OnThrow(Handle<Object> exception) 224 V8_WARN_UNUSED_RESULT; 225 void OnPromiseReject(Handle<Object> promise, Handle<Object> value); 226 void OnCompileError(Handle<Script> script); 227 void OnAfterCompile(Handle<Script> script); 228 229 void HandleDebugBreak(IgnoreBreakMode ignore_break_mode, 230 debug::BreakReasons break_reasons); 231 232 // The break target may not be the top-most frame, since we may be 233 // breaking before entering a function that cannot contain break points. 234 void Break(JavaScriptFrame* frame, Handle<JSFunction> break_target); 235 236 // Scripts handling. 237 Handle<FixedArray> GetLoadedScripts(); 238 239 // Break point handling. 240 enum BreakPointKind { kRegular, kInstrumentation }; 241 bool SetBreakpoint(Handle<SharedFunctionInfo> shared, 242 Handle<BreakPoint> break_point, int* source_position); 243 void ClearBreakPoint(Handle<BreakPoint> break_point); 244 void ChangeBreakOnException(ExceptionBreakType type, bool enable); 245 bool IsBreakOnException(ExceptionBreakType type); 246 247 void SetTerminateOnResume(); 248 249 bool SetBreakPointForScript(Handle<Script> script, Handle<String> condition, 250 int* source_position, int* id); 251 bool SetBreakpointForFunction(Handle<SharedFunctionInfo> shared, 252 Handle<String> condition, int* id, 253 BreakPointKind kind = kRegular); 254 void RemoveBreakpoint(int id); 255 #if V8_ENABLE_WEBASSEMBLY 256 void SetInstrumentationBreakpointForWasmScript(Handle<Script> script, 257 int* id); 258 void RemoveBreakpointForWasmScript(Handle<Script> script, int id); 259 260 void RecordWasmScriptWithBreakpoints(Handle<Script> script); 261 #endif // V8_ENABLE_WEBASSEMBLY 262 263 // Find breakpoints from the debug info and the break location and check 264 // whether they are hit. Return an empty handle if not, or a FixedArray with 265 // hit BreakPoint objects. has_break_points is set to true if position has 266 // any non-instrumentation breakpoint. 267 MaybeHandle<FixedArray> GetHitBreakPoints(Handle<DebugInfo> debug_info, 268 int position, 269 bool* has_break_points); 270 271 // Stepping handling. 272 void PrepareStep(StepAction step_action); 273 void PrepareStepIn(Handle<JSFunction> function); 274 void PrepareStepInSuspendedGenerator(); 275 void PrepareStepOnThrow(); 276 void ClearStepping(); 277 278 void SetBreakOnNextFunctionCall(); 279 void ClearBreakOnNextFunctionCall(); 280 281 void DiscardBaselineCode(SharedFunctionInfo shared); 282 void DiscardAllBaselineCode(); 283 284 void DeoptimizeFunction(Handle<SharedFunctionInfo> shared); 285 void PrepareFunctionForDebugExecution(Handle<SharedFunctionInfo> shared); 286 void InstallDebugBreakTrampoline(); 287 bool GetPossibleBreakpoints(Handle<Script> script, int start_position, 288 int end_position, bool restrict_to_function, 289 std::vector<BreakLocation>* locations); 290 291 bool IsBlackboxed(Handle<SharedFunctionInfo> shared); 292 bool ShouldBeSkipped(); 293 294 bool CanBreakAtEntry(Handle<SharedFunctionInfo> shared); 295 296 void SetDebugDelegate(debug::DebugDelegate* delegate); 297 298 // Returns whether the operation succeeded. 299 bool EnsureBreakInfo(Handle<SharedFunctionInfo> shared); 300 void CreateBreakInfo(Handle<SharedFunctionInfo> shared); 301 Handle<DebugInfo> GetOrCreateDebugInfo(Handle<SharedFunctionInfo> shared); 302 303 void InstallCoverageInfo(Handle<SharedFunctionInfo> shared, 304 Handle<CoverageInfo> coverage_info); 305 void RemoveAllCoverageInfos(); 306 307 // This function is used in FunctionNameUsing* tests. 308 Handle<Object> FindInnermostContainingFunctionInfo(Handle<Script> script, 309 int position); 310 311 Handle<SharedFunctionInfo> FindClosestSharedFunctionInfoFromPosition( 312 int position, Handle<Script> script, 313 Handle<SharedFunctionInfo> outer_shared); 314 315 bool FindSharedFunctionInfosIntersectingRange( 316 Handle<Script> script, int start_position, int end_position, 317 std::vector<Handle<SharedFunctionInfo>>* candidates); 318 319 static Handle<Object> GetSourceBreakLocations( 320 Isolate* isolate, Handle<SharedFunctionInfo> shared); 321 322 // Check whether this frame is just about to return. 323 bool IsBreakAtReturn(JavaScriptFrame* frame); 324 325 bool AllFramesOnStackAreBlackboxed(); 326 327 // Set new script source, throw an exception if error occurred. When preview 328 // is true: try to set source, throw exception if any without actual script 329 // change. stack_changed is true if after editing script on pause stack is 330 // changed and client should request stack trace again. 331 bool SetScriptSource(Handle<Script> script, Handle<String> source, 332 bool preview, debug::LiveEditResult* result); 333 334 int GetFunctionDebuggingId(Handle<JSFunction> function); 335 336 // Threading support. 337 char* ArchiveDebug(char* to); 338 char* RestoreDebug(char* from); 339 static int ArchiveSpacePerThread(); FreeThreadResources()340 void FreeThreadResources() {} 341 void Iterate(RootVisitor* v); InitThread(const ExecutionAccess & lock)342 void InitThread(const ExecutionAccess& lock) { ThreadInit(); } 343 CheckExecutionState()344 bool CheckExecutionState() { return is_active(); } 345 346 void StartSideEffectCheckMode(); 347 void StopSideEffectCheckMode(); 348 349 void ApplySideEffectChecks(Handle<DebugInfo> debug_info); 350 void ClearSideEffectChecks(Handle<DebugInfo> debug_info); 351 352 bool PerformSideEffectCheck(Handle<JSFunction> function, 353 Handle<Object> receiver); 354 355 enum AccessorKind { kNotAccessor, kGetter, kSetter }; 356 bool PerformSideEffectCheckForCallback(Handle<Object> callback_info, 357 Handle<Object> receiver, 358 AccessorKind accessor_kind); 359 bool PerformSideEffectCheckAtBytecode(InterpretedFrame* frame); 360 bool PerformSideEffectCheckForObject(Handle<Object> object); 361 362 // Flags and states. is_active()363 inline bool is_active() const { return is_active_; } in_debug_scope()364 inline bool in_debug_scope() const { 365 return !!base::Relaxed_Load(&thread_local_.current_debug_scope_); 366 } needs_check_on_function_call()367 inline bool needs_check_on_function_call() const { 368 return hook_on_function_call_; 369 } 370 set_break_points_active(bool v)371 void set_break_points_active(bool v) { break_points_active_ = v; } break_points_active()372 bool break_points_active() const { return break_points_active_; } 373 break_frame_id()374 StackFrameId break_frame_id() { return thread_local_.break_frame_id_; } 375 376 Handle<Object> return_value_handle(); return_value()377 Object return_value() { return thread_local_.return_value_; } set_return_value(Object value)378 void set_return_value(Object value) { thread_local_.return_value_ = value; } 379 380 // Support for embedding into generated code. is_active_address()381 Address is_active_address() { return reinterpret_cast<Address>(&is_active_); } 382 hook_on_function_call_address()383 Address hook_on_function_call_address() { 384 return reinterpret_cast<Address>(&hook_on_function_call_); 385 } 386 suspended_generator_address()387 Address suspended_generator_address() { 388 return reinterpret_cast<Address>(&thread_local_.suspended_generator_); 389 } 390 last_step_action()391 StepAction last_step_action() { return thread_local_.last_step_action_; } break_on_next_function_call()392 bool break_on_next_function_call() const { 393 return thread_local_.break_on_next_function_call_; 394 } 395 break_disabled()396 inline bool break_disabled() const { return break_disabled_; } 397 feature_tracker()398 DebugFeatureTracker* feature_tracker() { return &feature_tracker_; } 399 400 // For functions in which we cannot set a break point, use a canonical 401 // source position for break points. 402 static const int kBreakAtEntryPosition = 0; 403 404 // Use -1 to encode instrumentation breakpoints. 405 static const int kInstrumentationId = -1; 406 407 void RemoveBreakInfoAndMaybeFree(Handle<DebugInfo> debug_info); 408 409 static char* Iterate(RootVisitor* v, char* thread_storage); 410 411 private: 412 explicit Debug(Isolate* isolate); 413 ~Debug(); 414 415 void UpdateDebugInfosForExecutionMode(); 416 void UpdateState(); 417 void UpdateHookOnFunctionCall(); 418 void Unload(); 419 420 // Return the number of virtual frames below debugger entry. 421 int CurrentFrameCount(); 422 ignore_events()423 inline bool ignore_events() const { 424 return is_suppressed_ || !is_active_ || 425 isolate_->debug_execution_mode() == DebugInfo::kSideEffects; 426 } 427 clear_suspended_generator()428 void clear_suspended_generator() { 429 thread_local_.suspended_generator_ = Smi::zero(); 430 } 431 has_suspended_generator()432 bool has_suspended_generator() const { 433 return thread_local_.suspended_generator_ != Smi::zero(); 434 } 435 436 bool IsExceptionBlackboxed(bool uncaught); 437 438 void OnException(Handle<Object> exception, Handle<Object> promise, 439 v8::debug::ExceptionType exception_type); 440 441 void ProcessCompileEvent(bool has_compile_error, Handle<Script> script); 442 443 // Find the closest source position for a break point for a given position. 444 int FindBreakablePosition(Handle<DebugInfo> debug_info, int source_position); 445 // Instrument code to break at break points. 446 void ApplyBreakPoints(Handle<DebugInfo> debug_info); 447 // Clear code from instrumentation. 448 void ClearBreakPoints(Handle<DebugInfo> debug_info); 449 // Clear all code from instrumentation. 450 void ClearAllBreakPoints(); 451 // Instrument a function with one-shots. 452 void FloodWithOneShot(Handle<SharedFunctionInfo> function, 453 bool returns_only = false); 454 // Clear all one-shot instrumentations, but restore break points. 455 void ClearOneShot(); 456 457 bool IsFrameBlackboxed(JavaScriptFrame* frame); 458 459 void ActivateStepOut(StackFrame* frame); 460 bool IsBreakOnInstrumentation(Handle<DebugInfo> debug_info, 461 const BreakLocation& location); 462 MaybeHandle<FixedArray> CheckBreakPoints(Handle<DebugInfo> debug_info, 463 BreakLocation* location, 464 bool* has_break_points); 465 MaybeHandle<FixedArray> CheckBreakPointsForLocations( 466 Handle<DebugInfo> debug_info, std::vector<BreakLocation>& break_locations, 467 bool* has_break_points); 468 469 MaybeHandle<FixedArray> GetHitBreakpointsAtCurrentStatement( 470 JavaScriptFrame* frame, bool* hasBreakpoints); 471 472 bool IsMutedAtCurrentLocation(JavaScriptFrame* frame); 473 // Check whether a BreakPoint object is hit. Evaluate condition depending 474 // on whether this is a regular break location or a break at function entry. 475 bool CheckBreakPoint(Handle<BreakPoint> break_point, bool is_break_at_entry); 476 AssertDebugContext()477 inline void AssertDebugContext() { DCHECK(in_debug_scope()); } 478 479 void ThreadInit(); 480 481 void PrintBreakLocation(); 482 483 void ClearAllDebuggerHints(); 484 485 // Wraps logic for clearing and maybe freeing all debug infos. 486 using DebugInfoClearFunction = std::function<void(Handle<DebugInfo>)>; 487 void ClearAllDebugInfos(const DebugInfoClearFunction& clear_function); 488 489 void FindDebugInfo(Handle<DebugInfo> debug_info, DebugInfoListNode** prev, 490 DebugInfoListNode** curr); 491 void FreeDebugInfoListNode(DebugInfoListNode* prev, DebugInfoListNode* node); 492 493 void SetTemporaryObjectTrackingDisabled(bool disabled); 494 bool GetTemporaryObjectTrackingDisabled() const; 495 496 debug::DebugDelegate* debug_delegate_ = nullptr; 497 498 // Debugger is active, i.e. there is a debug event listener attached. 499 bool is_active_; 500 // Debugger needs to be notified on every new function call. 501 // Used for stepping and read-only checks 502 bool hook_on_function_call_; 503 // Suppress debug events. 504 bool is_suppressed_; 505 // Running liveedit. 506 bool running_live_edit_ = false; 507 // Do not trigger debug break events. 508 bool break_disabled_; 509 // Do not break on break points. 510 bool break_points_active_; 511 // Trigger debug break events for all exceptions. 512 bool break_on_exception_; 513 // Trigger debug break events for uncaught exceptions. 514 bool break_on_uncaught_exception_; 515 // Termination exception because side effect check has failed. 516 bool side_effect_check_failed_; 517 518 // List of active debug info objects. 519 DebugInfoListNode* debug_info_list_; 520 521 // Used for side effect check to mark temporary objects. 522 class TemporaryObjectsTracker; 523 std::unique_ptr<TemporaryObjectsTracker> temporary_objects_; 524 525 Handle<RegExpMatchInfo> regexp_match_info_; 526 527 // Used to collect histogram data on debugger feature usage. 528 DebugFeatureTracker feature_tracker_; 529 530 // Per-thread data. 531 class ThreadLocal { 532 public: 533 // Top debugger entry. 534 base::AtomicWord current_debug_scope_; 535 536 // Frame id for the frame of the current break. 537 StackFrameId break_frame_id_; 538 539 // Step action for last step performed. 540 StepAction last_step_action_; 541 542 // If set, next PrepareStepIn will ignore this function until stepped into 543 // another function, at which point this will be cleared. 544 Object ignore_step_into_function_; 545 546 // If set then we need to repeat StepOut action at return. 547 bool fast_forward_to_return_; 548 549 // Source statement position from last step next action. 550 int last_statement_position_; 551 552 // Frame pointer from last step next or step frame action. 553 int last_frame_count_; 554 555 // Frame pointer of the target frame we want to arrive at. 556 int target_frame_count_; 557 558 // Value of the accumulator at the point of entering the debugger. 559 Object return_value_; 560 561 // The suspended generator object to track when stepping. 562 Object suspended_generator_; 563 564 // Last used inspector breakpoint id. 565 int last_breakpoint_id_; 566 567 // This flag is true when SetBreakOnNextFunctionCall is called and it forces 568 // debugger to break on next function call. 569 bool break_on_next_function_call_; 570 571 // Throwing an exception may cause a Promise rejection. For this purpose 572 // we keep track of a stack of nested promises. 573 Object promise_stack_; 574 }; 575 576 static void Iterate(RootVisitor* v, ThreadLocal* thread_local_data); 577 578 // Storage location for registers when handling debug break calls 579 ThreadLocal thread_local_; 580 581 #if V8_ENABLE_WEBASSEMBLY 582 // This is a global handle, lazily initialized. 583 Handle<WeakArrayList> wasm_scripts_with_break_points_; 584 #endif // V8_ENABLE_WEBASSEMBLY 585 586 Isolate* isolate_; 587 588 friend class Isolate; 589 friend class DebugScope; 590 friend class DisableBreak; 591 friend class DisableTemporaryObjectTracking; 592 friend class LiveEdit; 593 friend class SuppressDebug; 594 595 friend Handle<FixedArray> GetDebuggedFunctions(); // In test-debug.cc 596 friend void CheckDebuggerUnloaded(); // In test-debug.cc 597 }; 598 599 // This scope is used to load and enter the debug context and create a new 600 // break state. Leaving the scope will restore the previous state. 601 class V8_NODISCARD DebugScope { 602 public: 603 explicit DebugScope(Debug* debug); 604 ~DebugScope(); 605 606 void set_terminate_on_resume(); 607 608 private: isolate()609 Isolate* isolate() { return debug_->isolate_; } 610 611 Debug* debug_; 612 DebugScope* prev_; // Previous scope if entered recursively. 613 StackFrameId break_frame_id_; // Previous break frame id. 614 PostponeInterruptsScope no_interrupts_; 615 // This is used as a boolean. 616 bool terminate_on_resume_ = false; 617 }; 618 619 // This scope is used to handle return values in nested debug break points. 620 // When there are nested debug breaks, we use this to restore the return 621 // value to the previous state. This is not merged with DebugScope because 622 // return_value_ will not be cleared when we use DebugScope. 623 class V8_NODISCARD ReturnValueScope { 624 public: 625 explicit ReturnValueScope(Debug* debug); 626 ~ReturnValueScope(); 627 628 private: 629 Debug* debug_; 630 Handle<Object> return_value_; // Previous result. 631 }; 632 633 // Stack allocated class for disabling break. 634 class DisableBreak { 635 public: 636 explicit DisableBreak(Debug* debug, bool disable = true) debug_(debug)637 : debug_(debug), previous_break_disabled_(debug->break_disabled_) { 638 debug_->break_disabled_ = disable; 639 } ~DisableBreak()640 ~DisableBreak() { debug_->break_disabled_ = previous_break_disabled_; } 641 DisableBreak(const DisableBreak&) = delete; 642 DisableBreak& operator=(const DisableBreak&) = delete; 643 644 private: 645 Debug* debug_; 646 bool previous_break_disabled_; 647 }; 648 649 // Stack allocated class for disabling temporary object tracking. 650 class DisableTemporaryObjectTracking { 651 public: DisableTemporaryObjectTracking(Debug * debug)652 explicit DisableTemporaryObjectTracking(Debug* debug) 653 : debug_(debug), 654 previous_tracking_disabled_( 655 debug->GetTemporaryObjectTrackingDisabled()) { 656 debug_->SetTemporaryObjectTrackingDisabled(true); 657 } ~DisableTemporaryObjectTracking()658 ~DisableTemporaryObjectTracking() { 659 debug_->SetTemporaryObjectTrackingDisabled(previous_tracking_disabled_); 660 } 661 DisableTemporaryObjectTracking(const DisableTemporaryObjectTracking&) = 662 delete; 663 DisableTemporaryObjectTracking& operator=( 664 const DisableTemporaryObjectTracking&) = delete; 665 666 private: 667 Debug* debug_; 668 bool previous_tracking_disabled_; 669 }; 670 671 class SuppressDebug { 672 public: SuppressDebug(Debug * debug)673 explicit SuppressDebug(Debug* debug) 674 : debug_(debug), old_state_(debug->is_suppressed_) { 675 debug_->is_suppressed_ = true; 676 } ~SuppressDebug()677 ~SuppressDebug() { debug_->is_suppressed_ = old_state_; } 678 SuppressDebug(const SuppressDebug&) = delete; 679 SuppressDebug& operator=(const SuppressDebug&) = delete; 680 681 private: 682 Debug* debug_; 683 bool old_state_; 684 }; 685 686 } // namespace internal 687 } // namespace v8 688 689 #endif // V8_DEBUG_DEBUG_H_ 690