Home | History | Annotate | Download | only in debug
      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 
     27 namespace v8 {
     28 namespace internal {
     29 
     30 
     31 // Forward declarations.
     32 class DebugScope;
     33 
     34 
     35 // Step actions. NOTE: These values are in macros.py as well.
     36 enum 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.
     46 enum 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
     54 enum BreakPositionAlignment {
     55   STATEMENT_ALIGNED = 0,
     56   BREAK_POSITION_ALIGNED = 1
     57 };
     58 
     59 enum 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 
     68 class 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 
    117 class 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 
    158 class 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 
    190 class 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.
    216 class 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 
    233 class 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.
    262 class 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 
    598 class 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 
    628 class 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 
    642 class 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.
    680 class 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.
    707 class 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.
    718 class 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 
    735 class 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 
    749 class 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.
    768 class 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