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 22namespace v8 { 23namespace internal { 24 25// Forward declarations. 26class AbstractCode; 27class DebugScope; 28class InterpretedFrame; 29class JavaScriptFrame; 30class JSGeneratorObject; 31class StackFrame; 32 33// Step actions. 34enum 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. 44enum 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. 48enum 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 58enum IgnoreBreakMode { 59 kIgnoreIfAllFramesBlackboxed, 60 kIgnoreIfTopFrameBlackboxed 61}; 62 63class BreakLocation { 64 public: 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 73 bool IsSuspend() const { return type_ == DEBUG_BREAK_SLOT_AT_SUSPEND; } 74 bool IsReturn() const { return type_ == DEBUG_BREAK_SLOT_AT_RETURN; } 75 bool IsReturnOrSuspend() const { return type_ >= DEBUG_BREAK_SLOT_AT_RETURN; } 76 bool IsCall() const { return type_ == DEBUG_BREAK_SLOT_AT_CALL; } 77 bool IsDebugBreakSlot() const { return type_ >= DEBUG_BREAK_SLOT; } 78 bool IsDebuggerStatement() const { return type_ == DEBUGGER_STATEMENT; } 79 bool IsDebugBreakAtEntry() const { return type_ == DEBUG_BREAK_AT_ENTRY; } 80 81 bool HasBreakPoint(Isolate* isolate, Handle<DebugInfo> debug_info) const; 82 83 int generator_suspend_id() { return generator_suspend_id_; } 84 int position() const { return position_; } 85 86 debug::BreakLocationType type() const; 87 88 JSGeneratorObject GetGeneratorObjectForSuspendedFrame( 89 JavaScriptFrame* frame) const; 90 91 private: 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 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 128class 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(); 135 bool Done() const { return source_position_iterator_.done(); } 136 void Next(); 137 138 void SkipToPosition(int position); 139 void SkipTo(int count) { 140 while (count-- > 0) Next(); 141 } 142 143 int code_offset() { return source_position_iterator_.code_offset(); } 144 int break_index() const { return break_index_; } 145 inline int position() const { return 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. 168class DebugInfoListNode { 169 public: 170 DebugInfoListNode(Isolate* isolate, DebugInfo debug_info); 171 ~DebugInfoListNode(); 172 173 DebugInfoListNode* next() { return next_; } 174 void set_next(DebugInfoListNode* next) { next_ = next; } 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 185class 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 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. 213class 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(); 340 void FreeThreadResources() {} 341 void Iterate(RootVisitor* v); 342 void InitThread(const ExecutionAccess& lock) { ThreadInit(); } 343 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. 363 inline bool is_active() const { return is_active_; } 364 inline bool in_debug_scope() const { 365 return !!base::Relaxed_Load(&thread_local_.current_debug_scope_); 366 } 367 inline bool needs_check_on_function_call() const { 368 return hook_on_function_call_; 369 } 370 371 void set_break_points_active(bool v) { break_points_active_ = v; } 372 bool break_points_active() const { return break_points_active_; } 373 374 StackFrameId break_frame_id() { return thread_local_.break_frame_id_; } 375 376 Handle<Object> return_value_handle(); 377 Object return_value() { return thread_local_.return_value_; } 378 void set_return_value(Object value) { thread_local_.return_value_ = value; } 379 380 // Support for embedding into generated code. 381 Address is_active_address() { return reinterpret_cast<Address>(&is_active_); } 382 383 Address hook_on_function_call_address() { 384 return reinterpret_cast<Address>(&hook_on_function_call_); 385 } 386 387 Address suspended_generator_address() { 388 return reinterpret_cast<Address>(&thread_local_.suspended_generator_); 389 } 390 391 StepAction last_step_action() { return thread_local_.last_step_action_; } 392 bool break_on_next_function_call() const { 393 return thread_local_.break_on_next_function_call_; 394 } 395 396 inline bool break_disabled() const { return break_disabled_; } 397 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 423 inline bool ignore_events() const { 424 return is_suppressed_ || !is_active_ || 425 isolate_->debug_execution_mode() == DebugInfo::kSideEffects; 426 } 427 428 void clear_suspended_generator() { 429 thread_local_.suspended_generator_ = Smi::zero(); 430 } 431 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 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. 601class V8_NODISCARD DebugScope { 602 public: 603 explicit DebugScope(Debug* debug); 604 ~DebugScope(); 605 606 void set_terminate_on_resume(); 607 608 private: 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. 623class 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. 634class DisableBreak { 635 public: 636 explicit DisableBreak(Debug* debug, bool disable = true) 637 : debug_(debug), previous_break_disabled_(debug->break_disabled_) { 638 debug_->break_disabled_ = disable; 639 } 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. 650class DisableTemporaryObjectTracking { 651 public: 652 explicit DisableTemporaryObjectTracking(Debug* debug) 653 : debug_(debug), 654 previous_tracking_disabled_( 655 debug->GetTemporaryObjectTrackingDisabled()) { 656 debug_->SetTemporaryObjectTrackingDisabled(true); 657 } 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 671class SuppressDebug { 672 public: 673 explicit SuppressDebug(Debug* debug) 674 : debug_(debug), old_state_(debug->is_suppressed_) { 675 debug_->is_suppressed_ = true; 676 } 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