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 "src/allocation.h"
9#include "src/assembler.h"
10#include "src/base/atomicops.h"
11#include "src/base/hashmap.h"
12#include "src/base/platform/platform.h"
13#include "src/debug/debug-interface.h"
14#include "src/debug/interface-types.h"
15#include "src/execution.h"
16#include "src/factory.h"
17#include "src/flags.h"
18#include "src/frames.h"
19#include "src/globals.h"
20#include "src/runtime/runtime.h"
21#include "src/source-position-table.h"
22#include "src/string-stream.h"
23#include "src/v8threads.h"
24
25#include "include/v8-debug.h"
26
27namespace v8 {
28namespace internal {
29
30
31// Forward declarations.
32class DebugScope;
33
34
35// Step actions. NOTE: These values are in macros.py as well.
36enum StepAction : int8_t {
37  StepNone = -1,  // Stepping not prepared.
38  StepOut = 0,    // Step out of the current function.
39  StepNext = 1,   // Step to the next statement in the current function.
40  StepIn = 2,     // Step into new functions invoked or the next statement
41                  // in the current function.
42  LastStepAction = StepIn
43};
44
45// Type of exception break. NOTE: These values are in macros.py as well.
46enum ExceptionBreakType {
47  BreakException = 0,
48  BreakUncaughtException = 1
49};
50
51
52// The different types of breakpoint position alignments.
53// Must match Debug.BreakPositionAlignment in debug.js
54enum BreakPositionAlignment {
55  STATEMENT_ALIGNED = 0,
56  BREAK_POSITION_ALIGNED = 1
57};
58
59enum DebugBreakType {
60  NOT_DEBUG_BREAK,
61  DEBUGGER_STATEMENT,
62  DEBUG_BREAK_SLOT,
63  DEBUG_BREAK_SLOT_AT_CALL,
64  DEBUG_BREAK_SLOT_AT_RETURN,
65  DEBUG_BREAK_SLOT_AT_TAIL_CALL,
66};
67
68class BreakLocation {
69 public:
70  static BreakLocation FromFrame(Handle<DebugInfo> debug_info,
71                                 JavaScriptFrame* frame);
72
73  static void AllAtCurrentStatement(Handle<DebugInfo> debug_info,
74                                    JavaScriptFrame* frame,
75                                    List<BreakLocation>* result_out);
76
77  inline bool IsReturn() const { return type_ == DEBUG_BREAK_SLOT_AT_RETURN; }
78  inline bool IsCall() const { return type_ == DEBUG_BREAK_SLOT_AT_CALL; }
79  inline bool IsTailCall() const {
80    return type_ == DEBUG_BREAK_SLOT_AT_TAIL_CALL;
81  }
82  inline bool IsDebugBreakSlot() const { return type_ >= DEBUG_BREAK_SLOT; }
83  inline bool IsDebuggerStatement() const {
84    return type_ == DEBUGGER_STATEMENT;
85  }
86
87  bool HasBreakPoint(Handle<DebugInfo> debug_info) const;
88
89  inline int position() const { return position_; }
90
91 private:
92  BreakLocation(Handle<AbstractCode> abstract_code, DebugBreakType type,
93                int code_offset, int position)
94      : abstract_code_(abstract_code),
95        code_offset_(code_offset),
96        type_(type),
97        position_(position) {
98    DCHECK_NE(NOT_DEBUG_BREAK, type_);
99  }
100
101  static int BreakIndexFromCodeOffset(Handle<DebugInfo> debug_info,
102                                      Handle<AbstractCode> abstract_code,
103                                      int offset);
104
105  void SetDebugBreak();
106  void ClearDebugBreak();
107
108  Handle<AbstractCode> abstract_code_;
109  int code_offset_;
110  DebugBreakType type_;
111  int position_;
112
113  friend class CodeBreakIterator;
114  friend class BytecodeArrayBreakIterator;
115};
116
117class BreakIterator {
118 public:
119  static std::unique_ptr<BreakIterator> GetIterator(
120      Handle<DebugInfo> debug_info, Handle<AbstractCode> abstract_code);
121
122  virtual ~BreakIterator() {}
123
124  virtual BreakLocation GetBreakLocation() = 0;
125  virtual bool Done() const = 0;
126  virtual void Next() = 0;
127
128  void SkipTo(int count) {
129    while (count-- > 0) Next();
130  }
131
132  virtual int code_offset() = 0;
133  int break_index() const { return break_index_; }
134  inline int position() const { return position_; }
135  inline int statement_position() const { return statement_position_; }
136
137  virtual bool IsDebugBreak() = 0;
138  virtual void ClearDebugBreak() = 0;
139  virtual void SetDebugBreak() = 0;
140
141 protected:
142  explicit BreakIterator(Handle<DebugInfo> debug_info);
143
144  int BreakIndexFromPosition(int position, BreakPositionAlignment alignment);
145
146  Isolate* isolate() { return debug_info_->GetIsolate(); }
147
148  Handle<DebugInfo> debug_info_;
149  int break_index_;
150  int position_;
151  int statement_position_;
152
153 private:
154  DisallowHeapAllocation no_gc_;
155  DISALLOW_COPY_AND_ASSIGN(BreakIterator);
156};
157
158class CodeBreakIterator : public BreakIterator {
159 public:
160  explicit CodeBreakIterator(Handle<DebugInfo> debug_info);
161  ~CodeBreakIterator() override {}
162
163  BreakLocation GetBreakLocation() override;
164  bool Done() const override { return reloc_iterator_.done(); }
165  void Next() override;
166
167  bool IsDebugBreak() override;
168  void ClearDebugBreak() override;
169  void SetDebugBreak() override;
170
171  void SkipToPosition(int position, BreakPositionAlignment alignment);
172
173  int code_offset() override {
174    return static_cast<int>(rinfo()->pc() -
175                            debug_info_->DebugCode()->instruction_start());
176  }
177
178 private:
179  int GetModeMask();
180  DebugBreakType GetDebugBreakType();
181
182  RelocInfo::Mode rmode() { return reloc_iterator_.rinfo()->rmode(); }
183  RelocInfo* rinfo() { return reloc_iterator_.rinfo(); }
184
185  RelocIterator reloc_iterator_;
186  SourcePositionTableIterator source_position_iterator_;
187  DISALLOW_COPY_AND_ASSIGN(CodeBreakIterator);
188};
189
190class BytecodeArrayBreakIterator : public BreakIterator {
191 public:
192  explicit BytecodeArrayBreakIterator(Handle<DebugInfo> debug_info);
193  ~BytecodeArrayBreakIterator() override {}
194
195  BreakLocation GetBreakLocation() override;
196  bool Done() const override { return source_position_iterator_.done(); }
197  void Next() override;
198
199  bool IsDebugBreak() override;
200  void ClearDebugBreak() override;
201  void SetDebugBreak() override;
202
203  void SkipToPosition(int position, BreakPositionAlignment alignment);
204
205  int code_offset() override { return source_position_iterator_.code_offset(); }
206
207 private:
208  DebugBreakType GetDebugBreakType();
209
210  SourcePositionTableIterator source_position_iterator_;
211  DISALLOW_COPY_AND_ASSIGN(BytecodeArrayBreakIterator);
212};
213
214// Linked list holding debug info objects. The debug info objects are kept as
215// weak handles to avoid a debug info object to keep a function alive.
216class DebugInfoListNode {
217 public:
218  explicit DebugInfoListNode(DebugInfo* debug_info);
219  ~DebugInfoListNode();
220
221  DebugInfoListNode* next() { return next_; }
222  void set_next(DebugInfoListNode* next) { next_ = next; }
223  Handle<DebugInfo> debug_info() { return Handle<DebugInfo>(debug_info_); }
224
225 private:
226  // Global (weak) handle to the debug info object.
227  DebugInfo** debug_info_;
228
229  // Next pointer for linked list.
230  DebugInfoListNode* next_;
231};
232
233class DebugFeatureTracker {
234 public:
235  enum Feature {
236    kActive = 1,
237    kBreakPoint = 2,
238    kStepping = 3,
239    kHeapSnapshot = 4,
240    kAllocationTracking = 5,
241    kProfiler = 6,
242    kLiveEdit = 7,
243  };
244
245  explicit DebugFeatureTracker(Isolate* isolate)
246      : isolate_(isolate), bitfield_(0) {}
247  void Track(Feature feature);
248
249 private:
250  Isolate* isolate_;
251  uint32_t bitfield_;
252};
253
254
255// This class contains the debugger support. The main purpose is to handle
256// setting break points in the code.
257//
258// This class controls the debug info for all functions which currently have
259// active breakpoints in them. This debug info is held in the heap root object
260// debug_info which is a FixedArray. Each entry in this list is of class
261// DebugInfo.
262class Debug {
263 public:
264  // Debug event triggers.
265  void OnDebugBreak(Handle<Object> break_points_hit);
266
267  void OnThrow(Handle<Object> exception);
268  void OnPromiseReject(Handle<Object> promise, Handle<Object> value);
269  void OnCompileError(Handle<Script> script);
270  void OnAfterCompile(Handle<Script> script);
271  void OnAsyncTaskEvent(debug::PromiseDebugActionType type, int id,
272                        int parent_id);
273
274  MUST_USE_RESULT MaybeHandle<Object> Call(Handle<Object> fun,
275                                           Handle<Object> data);
276  Handle<Context> GetDebugContext();
277  void HandleDebugBreak();
278
279  // Internal logic
280  bool Load();
281  void Break(JavaScriptFrame* frame);
282
283  // Scripts handling.
284  Handle<FixedArray> GetLoadedScripts();
285
286  // Break point handling.
287  bool SetBreakPoint(Handle<JSFunction> function,
288                     Handle<Object> break_point_object,
289                     int* source_position);
290  bool SetBreakPointForScript(Handle<Script> script,
291                              Handle<Object> break_point_object,
292                              int* source_position,
293                              BreakPositionAlignment alignment);
294  void ClearBreakPoint(Handle<Object> break_point_object);
295  void ChangeBreakOnException(ExceptionBreakType type, bool enable);
296  bool IsBreakOnException(ExceptionBreakType type);
297
298  // The parameter is either a BreakPointInfo object, or a FixedArray of
299  // BreakPointInfo objects.
300  // Returns an empty handle if no breakpoint is hit, or a FixedArray with all
301  // hit breakpoints.
302  MaybeHandle<FixedArray> GetHitBreakPointObjects(
303      Handle<Object> break_point_objects);
304
305  // Stepping handling.
306  void PrepareStep(StepAction step_action);
307  void PrepareStepIn(Handle<JSFunction> function);
308  void PrepareStepInSuspendedGenerator();
309  void PrepareStepOnThrow();
310  void ClearStepping();
311  void ClearStepOut();
312
313  bool PrepareFunctionForBreakPoints(Handle<SharedFunctionInfo> shared);
314  bool GetPossibleBreakpoints(Handle<Script> script, int start_position,
315                              int end_position, std::set<int>* positions);
316
317  void RecordGenerator(Handle<JSGeneratorObject> generator_object);
318
319  void RunPromiseHook(PromiseHookType type, Handle<JSPromise> promise,
320                      Handle<Object> parent);
321
322  int NextAsyncTaskId(Handle<JSObject> promise);
323
324  bool IsBlackboxed(Handle<SharedFunctionInfo> shared);
325
326  void SetDebugDelegate(debug::DebugDelegate* delegate, bool pass_ownership);
327
328  // Returns whether the operation succeeded.
329  bool EnsureDebugInfo(Handle<SharedFunctionInfo> shared);
330  void CreateDebugInfo(Handle<SharedFunctionInfo> shared);
331  static Handle<DebugInfo> GetDebugInfo(Handle<SharedFunctionInfo> shared);
332
333  template <typename C>
334  bool CompileToRevealInnerFunctions(C* compilable);
335
336  // This function is used in FunctionNameUsing* tests.
337  Handle<Object> FindSharedFunctionInfoInScript(Handle<Script> script,
338                                                int position);
339
340  static Handle<Object> GetSourceBreakLocations(
341      Handle<SharedFunctionInfo> shared,
342      BreakPositionAlignment position_aligment);
343
344  // Check whether a global object is the debug global object.
345  bool IsDebugGlobal(JSGlobalObject* global);
346
347  // Check whether this frame is just about to return.
348  bool IsBreakAtReturn(JavaScriptFrame* frame);
349
350  // Support for LiveEdit
351  void ScheduleFrameRestart(StackFrame* frame);
352
353  bool IsFrameBlackboxed(JavaScriptFrame* frame);
354
355  // Threading support.
356  char* ArchiveDebug(char* to);
357  char* RestoreDebug(char* from);
358  static int ArchiveSpacePerThread();
359  void FreeThreadResources() { }
360  void Iterate(ObjectVisitor* v);
361
362  bool CheckExecutionState(int id) {
363    return CheckExecutionState() && break_id() == id;
364  }
365
366  bool CheckExecutionState() {
367    return is_active() && !debug_context().is_null() && break_id() != 0;
368  }
369
370  bool PerformSideEffectCheck(Handle<JSFunction> function);
371  bool PerformSideEffectCheckForCallback(Address function);
372
373  // Flags and states.
374  DebugScope* debugger_entry() {
375    return reinterpret_cast<DebugScope*>(
376        base::NoBarrier_Load(&thread_local_.current_debug_scope_));
377  }
378  inline Handle<Context> debug_context() { return debug_context_; }
379
380  void set_live_edit_enabled(bool v) { live_edit_enabled_ = v; }
381  bool live_edit_enabled() const {
382    return FLAG_enable_liveedit && live_edit_enabled_;
383  }
384
385  inline bool is_active() const { return is_active_; }
386  inline bool is_loaded() const { return !debug_context_.is_null(); }
387  inline bool in_debug_scope() const {
388    return !!base::NoBarrier_Load(&thread_local_.current_debug_scope_);
389  }
390  void set_break_points_active(bool v) { break_points_active_ = v; }
391  bool break_points_active() const { return break_points_active_; }
392
393  StackFrame::Id break_frame_id() { return thread_local_.break_frame_id_; }
394  int break_id() { return thread_local_.break_id_; }
395
396  Handle<Object> return_value_handle() {
397    return handle(thread_local_.return_value_, isolate_);
398  }
399  Object* return_value() { return thread_local_.return_value_; }
400  void set_return_value(Object* value) { thread_local_.return_value_ = value; }
401
402  // Support for embedding into generated code.
403  Address is_active_address() {
404    return reinterpret_cast<Address>(&is_active_);
405  }
406
407  Address hook_on_function_call_address() {
408    return reinterpret_cast<Address>(&hook_on_function_call_);
409  }
410
411  Address last_step_action_address() {
412    return reinterpret_cast<Address>(&thread_local_.last_step_action_);
413  }
414
415  Address suspended_generator_address() {
416    return reinterpret_cast<Address>(&thread_local_.suspended_generator_);
417  }
418
419  Address restart_fp_address() {
420    return reinterpret_cast<Address>(&thread_local_.restart_fp_);
421  }
422
423  StepAction last_step_action() { return thread_local_.last_step_action_; }
424
425  DebugFeatureTracker* feature_tracker() { return &feature_tracker_; }
426
427 private:
428  explicit Debug(Isolate* isolate);
429  ~Debug() { DCHECK_NULL(debug_delegate_); }
430
431  void UpdateState();
432  void UpdateHookOnFunctionCall();
433  void RemoveDebugDelegate();
434  void Unload();
435  void SetNextBreakId() {
436    thread_local_.break_id_ = ++thread_local_.break_count_;
437  }
438
439  // Return the number of virtual frames below debugger entry.
440  int CurrentFrameCount();
441
442  inline bool ignore_events() const {
443    return is_suppressed_ || !is_active_ || isolate_->needs_side_effect_check();
444  }
445  inline bool break_disabled() const { return break_disabled_; }
446
447  void clear_suspended_generator() {
448    thread_local_.suspended_generator_ = Smi::kZero;
449  }
450
451  bool has_suspended_generator() const {
452    return thread_local_.suspended_generator_ != Smi::kZero;
453  }
454
455  bool IsExceptionBlackboxed(bool uncaught);
456
457  void OnException(Handle<Object> exception, Handle<Object> promise);
458
459  // Constructors for debug event objects.
460  MUST_USE_RESULT MaybeHandle<Object> MakeExecutionState();
461  MUST_USE_RESULT MaybeHandle<Object> MakeBreakEvent(
462      Handle<Object> break_points_hit);
463  MUST_USE_RESULT MaybeHandle<Object> MakeExceptionEvent(
464      Handle<Object> exception,
465      bool uncaught,
466      Handle<Object> promise);
467  MUST_USE_RESULT MaybeHandle<Object> MakeCompileEvent(
468      Handle<Script> script, v8::DebugEvent type);
469  MUST_USE_RESULT MaybeHandle<Object> MakeAsyncTaskEvent(
470      v8::debug::PromiseDebugActionType type, int id);
471
472  void ProcessCompileEvent(v8::DebugEvent event, Handle<Script> script);
473  void ProcessDebugEvent(v8::DebugEvent event, Handle<JSObject> event_data);
474
475  // Find the closest source position for a break point for a given position.
476  int FindBreakablePosition(Handle<DebugInfo> debug_info, int source_position,
477                            BreakPositionAlignment alignment);
478  // Instrument code to break at break points.
479  void ApplyBreakPoints(Handle<DebugInfo> debug_info);
480  // Clear code from instrumentation.
481  void ClearBreakPoints(Handle<DebugInfo> debug_info);
482  // Clear all code from instrumentation.
483  void ClearAllBreakPoints();
484  // Instrument a function with one-shots.
485  void FloodWithOneShot(Handle<SharedFunctionInfo> function);
486  // Clear all one-shot instrumentations, but restore break points.
487  void ClearOneShot();
488
489  void ActivateStepOut(StackFrame* frame);
490  void RemoveDebugInfoAndClearFromShared(Handle<DebugInfo> debug_info);
491  MaybeHandle<FixedArray> CheckBreakPoints(Handle<DebugInfo> debug_info,
492                                           BreakLocation* location,
493                                           bool* has_break_points = nullptr);
494  bool IsMutedAtCurrentLocation(JavaScriptFrame* frame);
495  bool CheckBreakPoint(Handle<Object> break_point_object);
496  MaybeHandle<Object> CallFunction(const char* name, int argc,
497                                   Handle<Object> args[]);
498
499  inline void AssertDebugContext() {
500    DCHECK(isolate_->context() == *debug_context());
501    DCHECK(in_debug_scope());
502  }
503
504  void ThreadInit();
505
506  void PrintBreakLocation();
507
508  // Global handles.
509  Handle<Context> debug_context_;
510
511  debug::DebugDelegate* debug_delegate_ = nullptr;
512  bool owns_debug_delegate_ = false;
513
514  // Debugger is active, i.e. there is a debug event listener attached.
515  bool is_active_;
516  // Debugger needs to be notified on every new function call.
517  // Used for stepping and read-only checks
518  bool hook_on_function_call_;
519  // Suppress debug events.
520  bool is_suppressed_;
521  // LiveEdit is enabled.
522  bool live_edit_enabled_;
523  // Do not trigger debug break events.
524  bool break_disabled_;
525  // Do not break on break points.
526  bool break_points_active_;
527  // Trigger debug break events for all exceptions.
528  bool break_on_exception_;
529  // Trigger debug break events for uncaught exceptions.
530  bool break_on_uncaught_exception_;
531  // Termination exception because side effect check has failed.
532  bool side_effect_check_failed_;
533
534  // List of active debug info objects.
535  DebugInfoListNode* debug_info_list_;
536
537  // Used to collect histogram data on debugger feature usage.
538  DebugFeatureTracker feature_tracker_;
539
540  // Per-thread data.
541  class ThreadLocal {
542   public:
543    // Top debugger entry.
544    base::AtomicWord current_debug_scope_;
545
546    // Counter for generating next break id.
547    int break_count_;
548
549    // Current break id.
550    int break_id_;
551
552    // Frame id for the frame of the current break.
553    StackFrame::Id break_frame_id_;
554
555    // Step action for last step performed.
556    StepAction last_step_action_;
557
558    // Source statement position from last step next action.
559    int last_statement_position_;
560
561    // Frame pointer from last step next or step frame action.
562    int last_frame_count_;
563
564    // Frame pointer of the target frame we want to arrive at.
565    int target_frame_count_;
566
567    // Value of the accumulator at the point of entering the debugger.
568    Object* return_value_;
569
570    // The suspended generator object to track when stepping.
571    Object* suspended_generator_;
572
573    // The new frame pointer to drop to when restarting a frame.
574    Address restart_fp_;
575
576    int async_task_count_;
577  };
578
579  // Storage location for registers when handling debug break calls
580  ThreadLocal thread_local_;
581
582  Isolate* isolate_;
583
584  friend class Isolate;
585  friend class DebugScope;
586  friend class DisableBreak;
587  friend class LiveEdit;
588  friend class SuppressDebug;
589  friend class NoSideEffectScope;
590  friend class LegacyDebugDelegate;
591
592  friend Handle<FixedArray> GetDebuggedFunctions();  // In test-debug.cc
593  friend void CheckDebuggerUnloaded(bool check_functions);  // In test-debug.cc
594
595  DISALLOW_COPY_AND_ASSIGN(Debug);
596};
597
598class LegacyDebugDelegate : public v8::debug::DebugDelegate {
599 public:
600  explicit LegacyDebugDelegate(Isolate* isolate) : isolate_(isolate) {}
601  void PromiseEventOccurred(v8::debug::PromiseDebugActionType type, int id,
602                            int parent_id) override;
603  void ScriptCompiled(v8::Local<v8::debug::Script> script,
604                      bool has_compile_error) override;
605  void BreakProgramRequested(v8::Local<v8::Context> paused_context,
606                             v8::Local<v8::Object> exec_state,
607                             v8::Local<v8::Value> break_points_hit) override;
608  void ExceptionThrown(v8::Local<v8::Context> paused_context,
609                       v8::Local<v8::Object> exec_state,
610                       v8::Local<v8::Value> exception,
611                       v8::Local<v8::Value> promise, bool is_uncaught) override;
612  bool IsFunctionBlackboxed(v8::Local<v8::debug::Script> script,
613                            const v8::debug::Location& start,
614                            const v8::debug::Location& end) override {
615    return false;
616  }
617
618 protected:
619  Isolate* isolate_;
620
621 private:
622  void ProcessDebugEvent(v8::DebugEvent event, Handle<JSObject> event_data);
623  virtual void ProcessDebugEvent(v8::DebugEvent event,
624                                 Handle<JSObject> event_data,
625                                 Handle<JSObject> exec_state) = 0;
626};
627
628class JavaScriptDebugDelegate : public LegacyDebugDelegate {
629 public:
630  JavaScriptDebugDelegate(Isolate* isolate, Handle<JSFunction> listener,
631                          Handle<Object> data);
632  virtual ~JavaScriptDebugDelegate();
633
634 private:
635  void ProcessDebugEvent(v8::DebugEvent event, Handle<JSObject> event_data,
636                         Handle<JSObject> exec_state) override;
637
638  Handle<JSFunction> listener_;
639  Handle<Object> data_;
640};
641
642class NativeDebugDelegate : public LegacyDebugDelegate {
643 public:
644  NativeDebugDelegate(Isolate* isolate, v8::Debug::EventCallback callback,
645                      Handle<Object> data);
646  virtual ~NativeDebugDelegate();
647
648 private:
649  // Details of the debug event delivered to the debug event listener.
650  class EventDetails : public v8::Debug::EventDetails {
651   public:
652    EventDetails(DebugEvent event, Handle<JSObject> exec_state,
653                 Handle<JSObject> event_data, Handle<Object> callback_data);
654    virtual DebugEvent GetEvent() const;
655    virtual v8::Local<v8::Object> GetExecutionState() const;
656    virtual v8::Local<v8::Object> GetEventData() const;
657    virtual v8::Local<v8::Context> GetEventContext() const;
658    virtual v8::Local<v8::Value> GetCallbackData() const;
659    virtual v8::Debug::ClientData* GetClientData() const { return nullptr; }
660    virtual v8::Isolate* GetIsolate() const;
661
662   private:
663    DebugEvent event_;              // Debug event causing the break.
664    Handle<JSObject> exec_state_;   // Current execution state.
665    Handle<JSObject> event_data_;   // Data associated with the event.
666    Handle<Object> callback_data_;  // User data passed with the callback
667                                    // when it was registered.
668  };
669
670  void ProcessDebugEvent(v8::DebugEvent event, Handle<JSObject> event_data,
671                         Handle<JSObject> exec_state) override;
672
673  v8::Debug::EventCallback callback_;
674  Handle<Object> data_;
675};
676
677// This scope is used to load and enter the debug context and create a new
678// break state.  Leaving the scope will restore the previous state.
679// On failure to load, FailedToEnter returns true.
680class DebugScope BASE_EMBEDDED {
681 public:
682  explicit DebugScope(Debug* debug);
683  ~DebugScope();
684
685  // Check whether loading was successful.
686  inline bool failed() { return failed_; }
687
688  // Get the active context from before entering the debugger.
689  inline Handle<Context> GetContext() { return save_.context(); }
690
691 private:
692  Isolate* isolate() { return debug_->isolate_; }
693
694  Debug* debug_;
695  DebugScope* prev_;               // Previous scope if entered recursively.
696  StackFrame::Id break_frame_id_;  // Previous break frame id.
697  int break_id_;                   // Previous break id.
698  bool failed_;                    // Did the debug context fail to load?
699  SaveContext save_;               // Saves previous context.
700  PostponeInterruptsScope no_termination_exceptons_;
701};
702
703// This scope is used to handle return values in nested debug break points.
704// When there are nested debug breaks, we use this to restore the return
705// value to the previous state. This is not merged with DebugScope because
706// return_value_ will not be cleared when we use DebugScope.
707class ReturnValueScope {
708 public:
709  explicit ReturnValueScope(Debug* debug);
710  ~ReturnValueScope();
711
712 private:
713  Debug* debug_;
714  Handle<Object> return_value_;  // Previous result.
715};
716
717// Stack allocated class for disabling break.
718class DisableBreak BASE_EMBEDDED {
719 public:
720  explicit DisableBreak(Debug* debug)
721      : debug_(debug), previous_break_disabled_(debug->break_disabled_) {
722    debug_->break_disabled_ = true;
723  }
724  ~DisableBreak() {
725    debug_->break_disabled_ = previous_break_disabled_;
726  }
727
728 private:
729  Debug* debug_;
730  bool previous_break_disabled_;
731  DISALLOW_COPY_AND_ASSIGN(DisableBreak);
732};
733
734
735class SuppressDebug BASE_EMBEDDED {
736 public:
737  explicit SuppressDebug(Debug* debug)
738      : debug_(debug), old_state_(debug->is_suppressed_) {
739    debug_->is_suppressed_ = true;
740  }
741  ~SuppressDebug() { debug_->is_suppressed_ = old_state_; }
742
743 private:
744  Debug* debug_;
745  bool old_state_;
746  DISALLOW_COPY_AND_ASSIGN(SuppressDebug);
747};
748
749class NoSideEffectScope {
750 public:
751  NoSideEffectScope(Isolate* isolate, bool disallow_side_effects)
752      : isolate_(isolate),
753        old_needs_side_effect_check_(isolate->needs_side_effect_check()) {
754    isolate->set_needs_side_effect_check(old_needs_side_effect_check_ ||
755                                         disallow_side_effects);
756    isolate->debug()->UpdateHookOnFunctionCall();
757    isolate->debug()->side_effect_check_failed_ = false;
758  }
759  ~NoSideEffectScope();
760
761 private:
762  Isolate* isolate_;
763  bool old_needs_side_effect_check_;
764  DISALLOW_COPY_AND_ASSIGN(NoSideEffectScope);
765};
766
767// Code generator routines.
768class DebugCodegen : public AllStatic {
769 public:
770  enum DebugBreakCallHelperMode {
771    SAVE_RESULT_REGISTER,
772    IGNORE_RESULT_REGISTER
773  };
774
775  static void GenerateDebugBreakStub(MacroAssembler* masm,
776                                     DebugBreakCallHelperMode mode);
777
778  static void GenerateSlot(MacroAssembler* masm, RelocInfo::Mode mode);
779
780  // Builtin to drop frames to restart function.
781  static void GenerateFrameDropperTrampoline(MacroAssembler* masm);
782
783  // Builtin to atomically (wrt deopts) handle debugger statement and
784  // drop frames to restart function if necessary.
785  static void GenerateHandleDebuggerStatement(MacroAssembler* masm);
786
787  static void PatchDebugBreakSlot(Isolate* isolate, Address pc,
788                                  Handle<Code> code);
789  static bool DebugBreakSlotIsPatched(Address pc);
790  static void ClearDebugBreakSlot(Isolate* isolate, Address pc);
791};
792
793
794}  // namespace internal
795}  // namespace v8
796
797#endif  // V8_DEBUG_DEBUG_H_
798