1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_DEBUG_DEBUG_H_ 6 #define V8_DEBUG_DEBUG_H_ 7 8 #include <memory> 9 #include <vector> 10 11 #include "src/codegen/source-position-table.h" 12 #include "src/common/globals.h" 13 #include "src/debug/debug-interface.h" 14 #include "src/debug/interface-types.h" 15 #include "src/execution/interrupts-scope.h" 16 #include "src/execution/isolate.h" 17 #include "src/handles/handles.h" 18 #include "src/objects/debug-objects.h" 19 20 namespace v8 { 21 namespace internal { 22 23 // Forward declarations. 24 class AbstractCode; 25 class DebugScope; 26 class InterpretedFrame; 27 class JavaScriptFrame; 28 class JSGeneratorObject; 29 class StackFrame; 30 31 // Step actions. NOTE: These values are in macros.py as well. 32 enum StepAction : int8_t { 33 StepNone = -1, // Stepping not prepared. 34 StepOut = 0, // Step out of the current function. 35 StepNext = 1, // Step to the next statement in the current function. 36 StepIn = 2, // Step into new functions invoked or the next statement 37 // in the current function. 38 LastStepAction = StepIn 39 }; 40 41 // Type of exception break. NOTE: These values are in macros.py as well. 42 enum ExceptionBreakType { 43 BreakException = 0, 44 BreakUncaughtException = 1 45 }; 46 47 enum DebugBreakType { 48 NOT_DEBUG_BREAK, 49 DEBUGGER_STATEMENT, 50 DEBUG_BREAK_SLOT, 51 DEBUG_BREAK_SLOT_AT_CALL, 52 DEBUG_BREAK_SLOT_AT_RETURN, 53 DEBUG_BREAK_SLOT_AT_SUSPEND, 54 DEBUG_BREAK_AT_ENTRY, 55 }; 56 57 enum IgnoreBreakMode { 58 kIgnoreIfAllFramesBlackboxed, 59 kIgnoreIfTopFrameBlackboxed 60 }; 61 62 class BreakLocation { 63 public: Invalid()64 static BreakLocation Invalid() { return BreakLocation(-1, NOT_DEBUG_BREAK); } 65 static BreakLocation FromFrame(Handle<DebugInfo> debug_info, 66 JavaScriptFrame* frame); 67 68 static void AllAtCurrentStatement(Handle<DebugInfo> debug_info, 69 JavaScriptFrame* frame, 70 std::vector<BreakLocation>* result_out); 71 IsSuspend()72 inline bool IsSuspend() const { return type_ == DEBUG_BREAK_SLOT_AT_SUSPEND; } IsReturn()73 inline bool IsReturn() const { return type_ == DEBUG_BREAK_SLOT_AT_RETURN; } IsReturnOrSuspend()74 inline bool IsReturnOrSuspend() const { 75 return type_ >= DEBUG_BREAK_SLOT_AT_RETURN; 76 } IsCall()77 inline bool IsCall() const { return type_ == DEBUG_BREAK_SLOT_AT_CALL; } IsDebugBreakSlot()78 inline bool IsDebugBreakSlot() const { return type_ >= DEBUG_BREAK_SLOT; } IsDebuggerStatement()79 inline bool IsDebuggerStatement() const { 80 return type_ == DEBUGGER_STATEMENT; 81 } IsDebugBreakAtEntry()82 inline bool IsDebugBreakAtEntry() const { 83 bool result = type_ == DEBUG_BREAK_AT_ENTRY; 84 return result; 85 } 86 87 bool HasBreakPoint(Isolate* isolate, Handle<DebugInfo> debug_info) const; 88 position()89 inline int position() const { return position_; } 90 91 debug::BreakLocationType type() const; 92 93 JSGeneratorObject GetGeneratorObjectForSuspendedFrame( 94 JavaScriptFrame* frame) const; 95 96 private: BreakLocation(Handle<AbstractCode> abstract_code,DebugBreakType type,int code_offset,int position,int generator_obj_reg_index)97 BreakLocation(Handle<AbstractCode> abstract_code, DebugBreakType type, 98 int code_offset, int position, int generator_obj_reg_index) 99 : abstract_code_(abstract_code), 100 code_offset_(code_offset), 101 type_(type), 102 position_(position), 103 generator_obj_reg_index_(generator_obj_reg_index) { 104 DCHECK_NE(NOT_DEBUG_BREAK, type_); 105 } 106 BreakLocation(int position,DebugBreakType type)107 BreakLocation(int position, DebugBreakType type) 108 : code_offset_(0), 109 type_(type), 110 position_(position), 111 generator_obj_reg_index_(0) {} 112 113 static int BreakIndexFromCodeOffset(Handle<DebugInfo> debug_info, 114 Handle<AbstractCode> abstract_code, 115 int offset); 116 117 void SetDebugBreak(); 118 void ClearDebugBreak(); 119 120 Handle<AbstractCode> abstract_code_; 121 int code_offset_; 122 DebugBreakType type_; 123 int position_; 124 int generator_obj_reg_index_; 125 126 friend class BreakIterator; 127 }; 128 129 class V8_EXPORT_PRIVATE BreakIterator { 130 public: 131 explicit BreakIterator(Handle<DebugInfo> debug_info); 132 133 BreakLocation GetBreakLocation(); Done()134 bool Done() const { return source_position_iterator_.done(); } 135 void Next(); 136 137 void SkipToPosition(int position); SkipTo(int count)138 void SkipTo(int count) { 139 while (count-- > 0) Next(); 140 } 141 code_offset()142 int code_offset() { return source_position_iterator_.code_offset(); } break_index()143 int break_index() const { return break_index_; } position()144 inline int position() const { return position_; } statement_position()145 inline int statement_position() const { return statement_position_; } 146 147 void ClearDebugBreak(); 148 void SetDebugBreak(); 149 150 private: 151 int BreakIndexFromPosition(int position); 152 153 Isolate* isolate(); 154 155 DebugBreakType GetDebugBreakType(); 156 157 Handle<DebugInfo> debug_info_; 158 int break_index_; 159 int position_; 160 int statement_position_; 161 SourcePositionTableIterator source_position_iterator_; 162 DisallowHeapAllocation no_gc_; 163 164 DISALLOW_COPY_AND_ASSIGN(BreakIterator); 165 }; 166 167 // Linked list holding debug info objects. The debug info objects are kept as 168 // weak handles to avoid a debug info object to keep a function alive. 169 class DebugInfoListNode { 170 public: 171 DebugInfoListNode(Isolate* isolate, DebugInfo debug_info); 172 ~DebugInfoListNode(); 173 next()174 DebugInfoListNode* next() { return next_; } set_next(DebugInfoListNode * next)175 void set_next(DebugInfoListNode* next) { next_ = next; } debug_info()176 Handle<DebugInfo> debug_info() { return Handle<DebugInfo>(debug_info_); } 177 178 private: 179 // Global (weak) handle to the debug info object. 180 Address* debug_info_; 181 182 // Next pointer for linked list. 183 DebugInfoListNode* next_; 184 }; 185 186 class DebugFeatureTracker { 187 public: 188 enum Feature { 189 kActive = 1, 190 kBreakPoint = 2, 191 kStepping = 3, 192 kHeapSnapshot = 4, 193 kAllocationTracking = 5, 194 kProfiler = 6, 195 kLiveEdit = 7, 196 }; 197 DebugFeatureTracker(Isolate * isolate)198 explicit DebugFeatureTracker(Isolate* isolate) 199 : isolate_(isolate), bitfield_(0) {} 200 void Track(Feature feature); 201 202 private: 203 Isolate* isolate_; 204 uint32_t bitfield_; 205 }; 206 207 208 // This class contains the debugger support. The main purpose is to handle 209 // setting break points in the code. 210 // 211 // This class controls the debug info for all functions which currently have 212 // active breakpoints in them. This debug info is held in the heap root object 213 // debug_info which is a FixedArray. Each entry in this list is of class 214 // DebugInfo. 215 class V8_EXPORT_PRIVATE Debug { 216 public: 217 // Debug event triggers. 218 void OnDebugBreak(Handle<FixedArray> break_points_hit, StepAction stepAction); 219 220 base::Optional<Object> OnThrow(Handle<Object> exception) 221 V8_WARN_UNUSED_RESULT; 222 void OnPromiseReject(Handle<Object> promise, Handle<Object> value); 223 void OnCompileError(Handle<Script> script); 224 void OnAfterCompile(Handle<Script> script); 225 226 void HandleDebugBreak(IgnoreBreakMode ignore_break_mode); 227 228 // The break target may not be the top-most frame, since we may be 229 // breaking before entering a function that cannot contain break points. 230 void Break(JavaScriptFrame* frame, Handle<JSFunction> break_target); 231 232 // Scripts handling. 233 Handle<FixedArray> GetLoadedScripts(); 234 235 // Break point handling. 236 bool SetBreakpoint(Handle<SharedFunctionInfo> shared, 237 Handle<BreakPoint> break_point, int* source_position); 238 void ClearBreakPoint(Handle<BreakPoint> break_point); 239 void ChangeBreakOnException(ExceptionBreakType type, bool enable); 240 bool IsBreakOnException(ExceptionBreakType type); 241 242 void SetTerminateOnResume(); 243 244 bool SetBreakPointForScript(Handle<Script> script, Handle<String> condition, 245 int* source_position, int* id); 246 bool SetBreakpointForFunction(Handle<SharedFunctionInfo> shared, 247 Handle<String> condition, int* id); 248 void RemoveBreakpoint(int id); 249 void RemoveBreakpointForWasmScript(Handle<Script> script, int id); 250 251 void RecordWasmScriptWithBreakpoints(Handle<Script> script); 252 253 // Find breakpoints from the debug info and the break location and check 254 // whether they are hit. Return an empty handle if not, or a FixedArray with 255 // hit BreakPoint objects. 256 MaybeHandle<FixedArray> GetHitBreakPoints(Handle<DebugInfo> debug_info, 257 int position); 258 259 // Stepping handling. 260 void PrepareStep(StepAction step_action); 261 void PrepareStepIn(Handle<JSFunction> function); 262 void PrepareStepInSuspendedGenerator(); 263 void PrepareStepOnThrow(); 264 void ClearStepping(); 265 266 void SetBreakOnNextFunctionCall(); 267 void ClearBreakOnNextFunctionCall(); 268 269 void DeoptimizeFunction(Handle<SharedFunctionInfo> shared); 270 void PrepareFunctionForDebugExecution(Handle<SharedFunctionInfo> shared); 271 void InstallDebugBreakTrampoline(); 272 bool GetPossibleBreakpoints(Handle<Script> script, int start_position, 273 int end_position, bool restrict_to_function, 274 std::vector<BreakLocation>* locations); 275 276 bool IsBlackboxed(Handle<SharedFunctionInfo> shared); 277 bool ShouldBeSkipped(); 278 279 bool CanBreakAtEntry(Handle<SharedFunctionInfo> shared); 280 281 void SetDebugDelegate(debug::DebugDelegate* delegate); 282 283 // Returns whether the operation succeeded. 284 bool EnsureBreakInfo(Handle<SharedFunctionInfo> shared); 285 void CreateBreakInfo(Handle<SharedFunctionInfo> shared); 286 Handle<DebugInfo> GetOrCreateDebugInfo(Handle<SharedFunctionInfo> shared); 287 288 void InstallCoverageInfo(Handle<SharedFunctionInfo> shared, 289 Handle<CoverageInfo> coverage_info); 290 void RemoveAllCoverageInfos(); 291 292 // This function is used in FunctionNameUsing* tests. 293 Handle<Object> FindSharedFunctionInfoInScript(Handle<Script> script, 294 int position); 295 296 static Handle<Object> GetSourceBreakLocations( 297 Isolate* isolate, Handle<SharedFunctionInfo> shared); 298 299 // Check whether this frame is just about to return. 300 bool IsBreakAtReturn(JavaScriptFrame* frame); 301 302 // Support for LiveEdit 303 void ScheduleFrameRestart(StackFrame* frame); 304 305 bool AllFramesOnStackAreBlackboxed(); 306 307 // Set new script source, throw an exception if error occurred. When preview 308 // is true: try to set source, throw exception if any without actual script 309 // change. stack_changed is true if after editing script on pause stack is 310 // changed and client should request stack trace again. 311 bool SetScriptSource(Handle<Script> script, Handle<String> source, 312 bool preview, debug::LiveEditResult* result); 313 314 int GetFunctionDebuggingId(Handle<JSFunction> function); 315 316 // Threading support. 317 char* ArchiveDebug(char* to); 318 char* RestoreDebug(char* from); 319 static int ArchiveSpacePerThread(); FreeThreadResources()320 void FreeThreadResources() { } 321 void Iterate(RootVisitor* v); InitThread(const ExecutionAccess & lock)322 void InitThread(const ExecutionAccess& lock) { ThreadInit(); } 323 CheckExecutionState()324 bool CheckExecutionState() { return is_active(); } 325 326 void StartSideEffectCheckMode(); 327 void StopSideEffectCheckMode(); 328 329 void ApplySideEffectChecks(Handle<DebugInfo> debug_info); 330 void ClearSideEffectChecks(Handle<DebugInfo> debug_info); 331 332 bool PerformSideEffectCheck(Handle<JSFunction> function, 333 Handle<Object> receiver); 334 335 enum AccessorKind { kNotAccessor, kGetter, kSetter }; 336 bool PerformSideEffectCheckForCallback(Handle<Object> callback_info, 337 Handle<Object> receiver, 338 AccessorKind accessor_kind); 339 bool PerformSideEffectCheckAtBytecode(InterpretedFrame* frame); 340 bool PerformSideEffectCheckForObject(Handle<Object> object); 341 342 // Flags and states. is_active()343 inline bool is_active() const { return is_active_; } in_debug_scope()344 inline bool in_debug_scope() const { 345 return !!base::Relaxed_Load(&thread_local_.current_debug_scope_); 346 } needs_check_on_function_call()347 inline bool needs_check_on_function_call() const { 348 return hook_on_function_call_; 349 } 350 set_break_points_active(bool v)351 void set_break_points_active(bool v) { break_points_active_ = v; } break_points_active()352 bool break_points_active() const { return break_points_active_; } 353 break_frame_id()354 StackFrameId break_frame_id() { return thread_local_.break_frame_id_; } 355 356 Handle<Object> return_value_handle(); return_value()357 Object return_value() { return thread_local_.return_value_; } set_return_value(Object value)358 void set_return_value(Object value) { thread_local_.return_value_ = value; } 359 360 // Support for embedding into generated code. is_active_address()361 Address is_active_address() { 362 return reinterpret_cast<Address>(&is_active_); 363 } 364 hook_on_function_call_address()365 Address hook_on_function_call_address() { 366 return reinterpret_cast<Address>(&hook_on_function_call_); 367 } 368 suspended_generator_address()369 Address suspended_generator_address() { 370 return reinterpret_cast<Address>(&thread_local_.suspended_generator_); 371 } 372 restart_fp_address()373 Address restart_fp_address() { 374 return reinterpret_cast<Address>(&thread_local_.restart_fp_); 375 } will_restart()376 bool will_restart() const { 377 return thread_local_.restart_fp_ != kNullAddress; 378 } 379 last_step_action()380 StepAction last_step_action() { return thread_local_.last_step_action_; } break_on_next_function_call()381 bool break_on_next_function_call() const { 382 return thread_local_.break_on_next_function_call_; 383 } 384 break_disabled()385 inline bool break_disabled() const { return break_disabled_; } 386 feature_tracker()387 DebugFeatureTracker* feature_tracker() { return &feature_tracker_; } 388 389 // For functions in which we cannot set a break point, use a canonical 390 // source position for break points. 391 static const int kBreakAtEntryPosition = 0; 392 393 void RemoveBreakInfoAndMaybeFree(Handle<DebugInfo> debug_info); 394 395 private: 396 explicit Debug(Isolate* isolate); 397 ~Debug(); 398 399 void UpdateDebugInfosForExecutionMode(); 400 void UpdateState(); 401 void UpdateHookOnFunctionCall(); 402 void Unload(); 403 404 // Return the number of virtual frames below debugger entry. 405 int CurrentFrameCount(); 406 ignore_events()407 inline bool ignore_events() const { 408 return is_suppressed_ || !is_active_ || 409 isolate_->debug_execution_mode() == DebugInfo::kSideEffects; 410 } 411 clear_suspended_generator()412 void clear_suspended_generator() { 413 thread_local_.suspended_generator_ = Smi::zero(); 414 } 415 has_suspended_generator()416 bool has_suspended_generator() const { 417 return thread_local_.suspended_generator_ != Smi::zero(); 418 } 419 420 bool IsExceptionBlackboxed(bool uncaught); 421 422 void OnException(Handle<Object> exception, Handle<Object> promise, 423 v8::debug::ExceptionType exception_type); 424 425 void ProcessCompileEvent(bool has_compile_error, Handle<Script> script); 426 427 // Find the closest source position for a break point for a given position. 428 int FindBreakablePosition(Handle<DebugInfo> debug_info, int source_position); 429 // Instrument code to break at break points. 430 void ApplyBreakPoints(Handle<DebugInfo> debug_info); 431 // Clear code from instrumentation. 432 void ClearBreakPoints(Handle<DebugInfo> debug_info); 433 // Clear all code from instrumentation. 434 void ClearAllBreakPoints(); 435 // Instrument a function with one-shots. 436 void FloodWithOneShot(Handle<SharedFunctionInfo> function, 437 bool returns_only = false); 438 // Clear all one-shot instrumentations, but restore break points. 439 void ClearOneShot(); 440 441 bool IsFrameBlackboxed(JavaScriptFrame* frame); 442 443 void ActivateStepOut(StackFrame* frame); 444 MaybeHandle<FixedArray> CheckBreakPoints(Handle<DebugInfo> debug_info, 445 BreakLocation* location, 446 bool* has_break_points = nullptr); 447 bool IsMutedAtCurrentLocation(JavaScriptFrame* frame); 448 // Check whether a BreakPoint object is hit. Evaluate condition depending 449 // on whether this is a regular break location or a break at function entry. 450 bool CheckBreakPoint(Handle<BreakPoint> break_point, bool is_break_at_entry); 451 AssertDebugContext()452 inline void AssertDebugContext() { 453 DCHECK(in_debug_scope()); 454 } 455 456 void ThreadInit(); 457 458 void PrintBreakLocation(); 459 460 void ClearAllDebuggerHints(); 461 462 // Wraps logic for clearing and maybe freeing all debug infos. 463 using DebugInfoClearFunction = std::function<void(Handle<DebugInfo>)>; 464 void ClearAllDebugInfos(const DebugInfoClearFunction& clear_function); 465 466 void FindDebugInfo(Handle<DebugInfo> debug_info, DebugInfoListNode** prev, 467 DebugInfoListNode** curr); 468 void FreeDebugInfoListNode(DebugInfoListNode* prev, DebugInfoListNode* node); 469 470 debug::DebugDelegate* debug_delegate_ = nullptr; 471 472 // Debugger is active, i.e. there is a debug event listener attached. 473 bool is_active_; 474 // Debugger needs to be notified on every new function call. 475 // Used for stepping and read-only checks 476 bool hook_on_function_call_; 477 // Suppress debug events. 478 bool is_suppressed_; 479 // Running liveedit. 480 bool running_live_edit_ = false; 481 // Do not trigger debug break events. 482 bool break_disabled_; 483 // Do not break on break points. 484 bool break_points_active_; 485 // Trigger debug break events for all exceptions. 486 bool break_on_exception_; 487 // Trigger debug break events for uncaught exceptions. 488 bool break_on_uncaught_exception_; 489 // Termination exception because side effect check has failed. 490 bool side_effect_check_failed_; 491 492 // List of active debug info objects. 493 DebugInfoListNode* debug_info_list_; 494 495 // Used for side effect check to mark temporary objects. 496 class TemporaryObjectsTracker; 497 std::unique_ptr<TemporaryObjectsTracker> temporary_objects_; 498 499 Handle<RegExpMatchInfo> regexp_match_info_; 500 501 // Used to collect histogram data on debugger feature usage. 502 DebugFeatureTracker feature_tracker_; 503 504 // Per-thread data. 505 class ThreadLocal { 506 public: 507 // Top debugger entry. 508 base::AtomicWord current_debug_scope_; 509 510 // Frame id for the frame of the current break. 511 StackFrameId break_frame_id_; 512 513 // Step action for last step performed. 514 StepAction last_step_action_; 515 516 // If set, next PrepareStepIn will ignore this function until stepped into 517 // another function, at which point this will be cleared. 518 Object ignore_step_into_function_; 519 520 // If set then we need to repeat StepOut action at return. 521 bool fast_forward_to_return_; 522 523 // Source statement position from last step next action. 524 int last_statement_position_; 525 526 // Frame pointer from last step next or step frame action. 527 int last_frame_count_; 528 529 // Frame pointer of the target frame we want to arrive at. 530 int target_frame_count_; 531 532 // Value of the accumulator at the point of entering the debugger. 533 Object return_value_; 534 535 // The suspended generator object to track when stepping. 536 Object suspended_generator_; 537 538 // The new frame pointer to drop to when restarting a frame. 539 Address restart_fp_; 540 541 // Last used inspector breakpoint id. 542 int last_breakpoint_id_; 543 544 // This flag is true when SetBreakOnNextFunctionCall is called and it forces 545 // debugger to break on next function call. 546 bool break_on_next_function_call_; 547 }; 548 549 // Storage location for registers when handling debug break calls 550 ThreadLocal thread_local_; 551 552 // This is a global handle, lazily initialized. 553 Handle<WeakArrayList> wasm_scripts_with_breakpoints_; 554 555 Isolate* isolate_; 556 557 friend class Isolate; 558 friend class DebugScope; 559 friend class DisableBreak; 560 friend class LiveEdit; 561 friend class SuppressDebug; 562 563 friend Handle<FixedArray> GetDebuggedFunctions(); // In test-debug.cc 564 friend void CheckDebuggerUnloaded(); // In test-debug.cc 565 566 DISALLOW_COPY_AND_ASSIGN(Debug); 567 }; 568 569 // This scope is used to load and enter the debug context and create a new 570 // break state. Leaving the scope will restore the previous state. 571 class DebugScope { 572 public: 573 explicit DebugScope(Debug* debug); 574 ~DebugScope(); 575 576 void set_terminate_on_resume(); 577 578 private: isolate()579 Isolate* isolate() { return debug_->isolate_; } 580 581 Debug* debug_; 582 DebugScope* prev_; // Previous scope if entered recursively. 583 StackFrameId break_frame_id_; // Previous break frame id. 584 PostponeInterruptsScope no_interrupts_; 585 // This is used as a boolean. 586 bool terminate_on_resume_ = false; 587 }; 588 589 // This scope is used to handle return values in nested debug break points. 590 // When there are nested debug breaks, we use this to restore the return 591 // value to the previous state. This is not merged with DebugScope because 592 // return_value_ will not be cleared when we use DebugScope. 593 class ReturnValueScope { 594 public: 595 explicit ReturnValueScope(Debug* debug); 596 ~ReturnValueScope(); 597 598 private: 599 Debug* debug_; 600 Handle<Object> return_value_; // Previous result. 601 }; 602 603 // Stack allocated class for disabling break. 604 class DisableBreak { 605 public: 606 explicit DisableBreak(Debug* debug, bool disable = true) debug_(debug)607 : debug_(debug), previous_break_disabled_(debug->break_disabled_) { 608 debug_->break_disabled_ = disable; 609 } ~DisableBreak()610 ~DisableBreak() { 611 debug_->break_disabled_ = previous_break_disabled_; 612 } 613 614 private: 615 Debug* debug_; 616 bool previous_break_disabled_; 617 DISALLOW_COPY_AND_ASSIGN(DisableBreak); 618 }; 619 620 class SuppressDebug { 621 public: SuppressDebug(Debug * debug)622 explicit SuppressDebug(Debug* debug) 623 : debug_(debug), old_state_(debug->is_suppressed_) { 624 debug_->is_suppressed_ = true; 625 } ~SuppressDebug()626 ~SuppressDebug() { debug_->is_suppressed_ = old_state_; } 627 628 private: 629 Debug* debug_; 630 bool old_state_; 631 DISALLOW_COPY_AND_ASSIGN(SuppressDebug); 632 }; 633 634 // Code generator routines. 635 class DebugCodegen : public AllStatic { 636 public: 637 enum DebugBreakCallHelperMode { 638 SAVE_RESULT_REGISTER, 639 IGNORE_RESULT_REGISTER 640 }; 641 642 // Builtin to drop frames to restart function. 643 static void GenerateFrameDropperTrampoline(MacroAssembler* masm); 644 645 // Builtin to atomically (wrt deopts) handle debugger statement and 646 // drop frames to restart function if necessary. 647 static void GenerateHandleDebuggerStatement(MacroAssembler* masm); 648 649 // Builtin to trigger a debug break before entering the function. 650 static void GenerateDebugBreakTrampoline(MacroAssembler* masm); 651 }; 652 653 654 } // namespace internal 655 } // namespace v8 656 657 #endif // V8_DEBUG_DEBUG_H_ 658