• 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 "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 
IsReturn()77   inline bool IsReturn() const { return type_ == DEBUG_BREAK_SLOT_AT_RETURN; }
IsCall()78   inline bool IsCall() const { return type_ == DEBUG_BREAK_SLOT_AT_CALL; }
IsTailCall()79   inline bool IsTailCall() const {
80     return type_ == DEBUG_BREAK_SLOT_AT_TAIL_CALL;
81   }
IsDebugBreakSlot()82   inline bool IsDebugBreakSlot() const { return type_ >= DEBUG_BREAK_SLOT; }
IsDebuggerStatement()83   inline bool IsDebuggerStatement() const {
84     return type_ == DEBUGGER_STATEMENT;
85   }
86 
87   bool HasBreakPoint(Handle<DebugInfo> debug_info) const;
88 
position()89   inline int position() const { return position_; }
90 
91  private:
BreakLocation(Handle<AbstractCode> abstract_code,DebugBreakType type,int code_offset,int position)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 
~BreakIterator()122   virtual ~BreakIterator() {}
123 
124   virtual BreakLocation GetBreakLocation() = 0;
125   virtual bool Done() const = 0;
126   virtual void Next() = 0;
127 
SkipTo(int count)128   void SkipTo(int count) {
129     while (count-- > 0) Next();
130   }
131 
132   virtual int code_offset() = 0;
break_index()133   int break_index() const { return break_index_; }
position()134   inline int position() const { return position_; }
statement_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 
isolate()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);
~CodeBreakIterator()161   ~CodeBreakIterator() override {}
162 
163   BreakLocation GetBreakLocation() override;
Done()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 
code_offset()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 
rmode()182   RelocInfo::Mode rmode() { return reloc_iterator_.rinfo()->rmode(); }
rinfo()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);
~BytecodeArrayBreakIterator()193   ~BytecodeArrayBreakIterator() override {}
194 
195   BreakLocation GetBreakLocation() override;
Done()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 
code_offset()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 
next()221   DebugInfoListNode* next() { return next_; }
set_next(DebugInfoListNode * next)222   void set_next(DebugInfoListNode* next) { next_ = next; }
debug_info()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 
DebugFeatureTracker(Isolate * isolate)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();
FreeThreadResources()359   void FreeThreadResources() { }
360   void Iterate(ObjectVisitor* v);
361 
CheckExecutionState(int id)362   bool CheckExecutionState(int id) {
363     return CheckExecutionState() && break_id() == id;
364   }
365 
CheckExecutionState()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.
debugger_entry()374   DebugScope* debugger_entry() {
375     return reinterpret_cast<DebugScope*>(
376         base::NoBarrier_Load(&thread_local_.current_debug_scope_));
377   }
debug_context()378   inline Handle<Context> debug_context() { return debug_context_; }
379 
set_live_edit_enabled(bool v)380   void set_live_edit_enabled(bool v) { live_edit_enabled_ = v; }
live_edit_enabled()381   bool live_edit_enabled() const {
382     return FLAG_enable_liveedit && live_edit_enabled_;
383   }
384 
is_active()385   inline bool is_active() const { return is_active_; }
is_loaded()386   inline bool is_loaded() const { return !debug_context_.is_null(); }
in_debug_scope()387   inline bool in_debug_scope() const {
388     return !!base::NoBarrier_Load(&thread_local_.current_debug_scope_);
389   }
set_break_points_active(bool v)390   void set_break_points_active(bool v) { break_points_active_ = v; }
break_points_active()391   bool break_points_active() const { return break_points_active_; }
392 
break_frame_id()393   StackFrame::Id break_frame_id() { return thread_local_.break_frame_id_; }
break_id()394   int break_id() { return thread_local_.break_id_; }
395 
return_value_handle()396   Handle<Object> return_value_handle() {
397     return handle(thread_local_.return_value_, isolate_);
398   }
return_value()399   Object* return_value() { return thread_local_.return_value_; }
set_return_value(Object * value)400   void set_return_value(Object* value) { thread_local_.return_value_ = value; }
401 
402   // Support for embedding into generated code.
is_active_address()403   Address is_active_address() {
404     return reinterpret_cast<Address>(&is_active_);
405   }
406 
hook_on_function_call_address()407   Address hook_on_function_call_address() {
408     return reinterpret_cast<Address>(&hook_on_function_call_);
409   }
410 
last_step_action_address()411   Address last_step_action_address() {
412     return reinterpret_cast<Address>(&thread_local_.last_step_action_);
413   }
414 
suspended_generator_address()415   Address suspended_generator_address() {
416     return reinterpret_cast<Address>(&thread_local_.suspended_generator_);
417   }
418 
restart_fp_address()419   Address restart_fp_address() {
420     return reinterpret_cast<Address>(&thread_local_.restart_fp_);
421   }
422 
last_step_action()423   StepAction last_step_action() { return thread_local_.last_step_action_; }
424 
feature_tracker()425   DebugFeatureTracker* feature_tracker() { return &feature_tracker_; }
426 
427  private:
428   explicit Debug(Isolate* isolate);
~Debug()429   ~Debug() { DCHECK_NULL(debug_delegate_); }
430 
431   void UpdateState();
432   void UpdateHookOnFunctionCall();
433   void RemoveDebugDelegate();
434   void Unload();
SetNextBreakId()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 
ignore_events()442   inline bool ignore_events() const {
443     return is_suppressed_ || !is_active_ || isolate_->needs_side_effect_check();
444   }
break_disabled()445   inline bool break_disabled() const { return break_disabled_; }
446 
clear_suspended_generator()447   void clear_suspended_generator() {
448     thread_local_.suspended_generator_ = Smi::kZero;
449   }
450 
has_suspended_generator()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 
AssertDebugContext()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:
LegacyDebugDelegate(Isolate * isolate)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;
IsFunctionBlackboxed(v8::Local<v8::debug::Script> script,const v8::debug::Location & start,const v8::debug::Location & end)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;
GetClientData()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.
failed()686   inline bool failed() { return failed_; }
687 
688   // Get the active context from before entering the debugger.
GetContext()689   inline Handle<Context> GetContext() { return save_.context(); }
690 
691  private:
isolate()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:
DisableBreak(Debug * debug)720   explicit DisableBreak(Debug* debug)
721       : debug_(debug), previous_break_disabled_(debug->break_disabled_) {
722     debug_->break_disabled_ = true;
723   }
~DisableBreak()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:
SuppressDebug(Debug * debug)737   explicit SuppressDebug(Debug* debug)
738       : debug_(debug), old_state_(debug->is_suppressed_) {
739     debug_->is_suppressed_ = true;
740   }
~SuppressDebug()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:
NoSideEffectScope(Isolate * isolate,bool disallow_side_effects)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