• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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