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