| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef V8_DEBUG_H_ | 5 #ifndef V8_DEBUG_H_ |
| 6 #define V8_DEBUG_H_ | 6 #define V8_DEBUG_H_ |
| 7 | 7 |
| 8 #include "allocation.h" | 8 #include "allocation.h" |
| 9 #include "arguments.h" | 9 #include "arguments.h" |
| 10 #include "assembler.h" | 10 #include "assembler.h" |
| 11 #include "execution.h" | 11 #include "execution.h" |
| 12 #include "factory.h" | 12 #include "factory.h" |
| 13 #include "flags.h" | 13 #include "flags.h" |
| 14 #include "frames-inl.h" | 14 #include "frames-inl.h" |
| 15 #include "hashmap.h" | 15 #include "hashmap.h" |
| 16 #include "liveedit.h" |
| 16 #include "platform.h" | 17 #include "platform.h" |
| 17 #include "string-stream.h" | 18 #include "string-stream.h" |
| 18 #include "v8threads.h" | 19 #include "v8threads.h" |
| 19 | 20 |
| 20 #include "../include/v8-debug.h" | 21 #include "../include/v8-debug.h" |
| 21 | 22 |
| 22 namespace v8 { | 23 namespace v8 { |
| 23 namespace internal { | 24 namespace internal { |
| 24 | 25 |
| 25 | 26 |
| 26 // Forward declarations. | 27 // Forward declarations. |
| 27 class EnterDebugger; | 28 class DebugScope; |
| 28 | 29 |
| 29 | 30 |
| 30 // Step actions. NOTE: These values are in macros.py as well. | 31 // Step actions. NOTE: These values are in macros.py as well. |
| 31 enum StepAction { | 32 enum StepAction { |
| 32 StepNone = -1, // Stepping not prepared. | 33 StepNone = -1, // Stepping not prepared. |
| 33 StepOut = 0, // Step out of the current function. | 34 StepOut = 0, // Step out of the current function. |
| 34 StepNext = 1, // Step to the next statement in the current function. | 35 StepNext = 1, // Step to the next statement in the current function. |
| 35 StepIn = 2, // Step into new functions invoked or the next statement | 36 StepIn = 2, // Step into new functions invoked or the next statement |
| 36 // in the current function. | 37 // in the current function. |
| 37 StepMin = 3, // Perform a minimum step in the current function. | 38 StepMin = 3, // Perform a minimum step in the current function. |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 142 DISALLOW_COPY_AND_ASSIGN(BreakLocationIterator); | 143 DISALLOW_COPY_AND_ASSIGN(BreakLocationIterator); |
| 143 }; | 144 }; |
| 144 | 145 |
| 145 | 146 |
| 146 // Cache of all script objects in the heap. When a script is added a weak handle | 147 // Cache of all script objects in the heap. When a script is added a weak handle |
| 147 // to it is created and that weak handle is stored in the cache. The weak handle | 148 // to it is created and that weak handle is stored in the cache. The weak handle |
| 148 // callback takes care of removing the script from the cache. The key used in | 149 // callback takes care of removing the script from the cache. The key used in |
| 149 // the cache is the script id. | 150 // the cache is the script id. |
| 150 class ScriptCache : private HashMap { | 151 class ScriptCache : private HashMap { |
| 151 public: | 152 public: |
| 152 explicit ScriptCache(Isolate* isolate) | 153 explicit ScriptCache(Isolate* isolate); |
| 153 : HashMap(HashMap::PointersMatch), | |
| 154 isolate_(isolate), | |
| 155 collected_scripts_(10) {} | |
| 156 virtual ~ScriptCache() { Clear(); } | 154 virtual ~ScriptCache() { Clear(); } |
| 157 | 155 |
| 158 // Add script to the cache. | 156 // Add script to the cache. |
| 159 void Add(Handle<Script> script); | 157 void Add(Handle<Script> script); |
| 160 | 158 |
| 161 // Return the scripts in the cache. | 159 // Return the scripts in the cache. |
| 162 Handle<FixedArray> GetScripts(); | 160 Handle<FixedArray> GetScripts(); |
| 163 | 161 |
| 164 // Generate debugger events for collected scripts. | 162 // Generate debugger events for collected scripts. |
| 165 void ProcessCollectedScripts(); | 163 void ProcessCollectedScripts(); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 195 Handle<DebugInfo> debug_info() { return debug_info_; } | 193 Handle<DebugInfo> debug_info() { return debug_info_; } |
| 196 | 194 |
| 197 private: | 195 private: |
| 198 // Global (weak) handle to the debug info object. | 196 // Global (weak) handle to the debug info object. |
| 199 Handle<DebugInfo> debug_info_; | 197 Handle<DebugInfo> debug_info_; |
| 200 | 198 |
| 201 // Next pointer for linked list. | 199 // Next pointer for linked list. |
| 202 DebugInfoListNode* next_; | 200 DebugInfoListNode* next_; |
| 203 }; | 201 }; |
| 204 | 202 |
| 205 // This class contains the debugger support. The main purpose is to handle | |
| 206 // setting break points in the code. | |
| 207 // | |
| 208 // This class controls the debug info for all functions which currently have | |
| 209 // active breakpoints in them. This debug info is held in the heap root object | |
| 210 // debug_info which is a FixedArray. Each entry in this list is of class | |
| 211 // DebugInfo. | |
| 212 class Debug { | |
| 213 public: | |
| 214 bool Load(); | |
| 215 void Unload(); | |
| 216 bool IsLoaded() { return !debug_context_.is_null(); } | |
| 217 bool InDebugger() { return thread_local_.debugger_entry_ != NULL; } | |
| 218 | |
| 219 Object* Break(Arguments args); | |
| 220 bool SetBreakPoint(Handle<JSFunction> function, | |
| 221 Handle<Object> break_point_object, | |
| 222 int* source_position); | |
| 223 bool SetBreakPointForScript(Handle<Script> script, | |
| 224 Handle<Object> break_point_object, | |
| 225 int* source_position, | |
| 226 BreakPositionAlignment alignment); | |
| 227 void ClearBreakPoint(Handle<Object> break_point_object); | |
| 228 void ClearAllBreakPoints(); | |
| 229 void FloodWithOneShot(Handle<JSFunction> function); | |
| 230 void FloodBoundFunctionWithOneShot(Handle<JSFunction> function); | |
| 231 void FloodHandlerWithOneShot(); | |
| 232 void ChangeBreakOnException(ExceptionBreakType type, bool enable); | |
| 233 bool IsBreakOnException(ExceptionBreakType type); | |
| 234 | |
| 235 void PromiseHandlePrologue(Handle<JSFunction> promise_getter); | |
| 236 void PromiseHandleEpilogue(); | |
| 237 // Returns a promise if it does not have a reject handler. | |
| 238 Handle<Object> GetPromiseForUncaughtException(); | |
| 239 | |
| 240 void PrepareStep(StepAction step_action, | |
| 241 int step_count, | |
| 242 StackFrame::Id frame_id); | |
| 243 void ClearStepping(); | |
| 244 void ClearStepOut(); | |
| 245 bool IsStepping() { return thread_local_.step_count_ > 0; } | |
| 246 bool StepNextContinue(BreakLocationIterator* break_location_iterator, | |
| 247 JavaScriptFrame* frame); | |
| 248 static Handle<DebugInfo> GetDebugInfo(Handle<SharedFunctionInfo> shared); | |
| 249 static bool HasDebugInfo(Handle<SharedFunctionInfo> shared); | |
| 250 | |
| 251 void PrepareForBreakPoints(); | |
| 252 | |
| 253 // This function is used in FunctionNameUsing* tests. | |
| 254 Object* FindSharedFunctionInfoInScript(Handle<Script> script, int position); | |
| 255 | |
| 256 // Returns whether the operation succeeded. Compilation can only be triggered | |
| 257 // if a valid closure is passed as the second argument, otherwise the shared | |
| 258 // function needs to be compiled already. | |
| 259 bool EnsureDebugInfo(Handle<SharedFunctionInfo> shared, | |
| 260 Handle<JSFunction> function); | |
| 261 | |
| 262 // Returns true if the current stub call is patched to call the debugger. | |
| 263 static bool IsDebugBreak(Address addr); | |
| 264 // Returns true if the current return statement has been patched to be | |
| 265 // a debugger breakpoint. | |
| 266 static bool IsDebugBreakAtReturn(RelocInfo* rinfo); | |
| 267 | |
| 268 // Check whether a code stub with the specified major key is a possible break | |
| 269 // point location. | |
| 270 static bool IsSourceBreakStub(Code* code); | |
| 271 static bool IsBreakStub(Code* code); | |
| 272 | |
| 273 // Find the builtin to use for invoking the debug break | |
| 274 static Handle<Code> FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode); | |
| 275 | |
| 276 static Handle<Object> GetSourceBreakLocations( | |
| 277 Handle<SharedFunctionInfo> shared, | |
| 278 BreakPositionAlignment position_aligment); | |
| 279 | |
| 280 // Getter for the debug_context. | |
| 281 inline Handle<Context> debug_context() { return debug_context_; } | |
| 282 | |
| 283 // Check whether a global object is the debug global object. | |
| 284 bool IsDebugGlobal(GlobalObject* global); | |
| 285 | |
| 286 // Check whether this frame is just about to return. | |
| 287 bool IsBreakAtReturn(JavaScriptFrame* frame); | |
| 288 | |
| 289 // Fast check to see if any break points are active. | |
| 290 inline bool has_break_points() { return has_break_points_; } | |
| 291 | |
| 292 void NewBreak(StackFrame::Id break_frame_id); | |
| 293 void SetBreak(StackFrame::Id break_frame_id, int break_id); | |
| 294 StackFrame::Id break_frame_id() { | |
| 295 return thread_local_.break_frame_id_; | |
| 296 } | |
| 297 int break_id() { return thread_local_.break_id_; } | |
| 298 | |
| 299 bool StepInActive() { return thread_local_.step_into_fp_ != 0; } | |
| 300 void HandleStepIn(Handle<JSFunction> function, | |
| 301 Handle<Object> holder, | |
| 302 Address fp, | |
| 303 bool is_constructor); | |
| 304 Address step_in_fp() { return thread_local_.step_into_fp_; } | |
| 305 Address* step_in_fp_addr() { return &thread_local_.step_into_fp_; } | |
| 306 | |
| 307 bool StepOutActive() { return thread_local_.step_out_fp_ != 0; } | |
| 308 Address step_out_fp() { return thread_local_.step_out_fp_; } | |
| 309 | |
| 310 EnterDebugger* debugger_entry() { | |
| 311 return thread_local_.debugger_entry_; | |
| 312 } | |
| 313 void set_debugger_entry(EnterDebugger* entry) { | |
| 314 thread_local_.debugger_entry_ = entry; | |
| 315 } | |
| 316 | |
| 317 // Check whether any of the specified interrupts are pending. | |
| 318 bool has_pending_interrupt() { | |
| 319 return thread_local_.has_pending_interrupt_; | |
| 320 } | |
| 321 | |
| 322 // Set specified interrupts as pending. | |
| 323 void set_has_pending_interrupt(bool value) { | |
| 324 thread_local_.has_pending_interrupt_ = value; | |
| 325 } | |
| 326 | |
| 327 // Getter and setter for the disable break state. | |
| 328 bool disable_break() { return disable_break_; } | |
| 329 void set_disable_break(bool disable_break) { | |
| 330 disable_break_ = disable_break; | |
| 331 } | |
| 332 | |
| 333 // Getters for the current exception break state. | |
| 334 bool break_on_exception() { return break_on_exception_; } | |
| 335 bool break_on_uncaught_exception() { | |
| 336 return break_on_uncaught_exception_; | |
| 337 } | |
| 338 | |
| 339 enum AddressId { | |
| 340 k_after_break_target_address, | |
| 341 k_restarter_frame_function_pointer | |
| 342 }; | |
| 343 | |
| 344 // Support for setting the address to jump to when returning from break point. | |
| 345 Address after_break_target_address() { | |
| 346 return reinterpret_cast<Address>(&thread_local_.after_break_target_); | |
| 347 } | |
| 348 | |
| 349 Address restarter_frame_function_pointer_address() { | |
| 350 Object*** address = &thread_local_.restarter_frame_function_pointer_; | |
| 351 return reinterpret_cast<Address>(address); | |
| 352 } | |
| 353 | |
| 354 static const int kEstimatedNofDebugInfoEntries = 16; | |
| 355 static const int kEstimatedNofBreakPointsInFunction = 16; | |
| 356 | |
| 357 // Passed to MakeWeak. | |
| 358 static void HandleWeakDebugInfo( | |
| 359 const v8::WeakCallbackData<v8::Value, void>& data); | |
| 360 | |
| 361 friend class Debugger; | |
| 362 friend Handle<FixedArray> GetDebuggedFunctions(); // In test-debug.cc | |
| 363 friend void CheckDebuggerUnloaded(bool check_functions); // In test-debug.cc | |
| 364 | |
| 365 // Threading support. | |
| 366 char* ArchiveDebug(char* to); | |
| 367 char* RestoreDebug(char* from); | |
| 368 static int ArchiveSpacePerThread(); | |
| 369 void FreeThreadResources() { } | |
| 370 | |
| 371 // Mirror cache handling. | |
| 372 void ClearMirrorCache(); | |
| 373 | |
| 374 // Script cache handling. | |
| 375 void CreateScriptCache(); | |
| 376 void DestroyScriptCache(); | |
| 377 void AddScriptToScriptCache(Handle<Script> script); | |
| 378 Handle<FixedArray> GetLoadedScripts(); | |
| 379 | |
| 380 // Record function from which eval was called. | |
| 381 static void RecordEvalCaller(Handle<Script> script); | |
| 382 | |
| 383 // Garbage collection notifications. | |
| 384 void AfterGarbageCollection(); | |
| 385 | |
| 386 // Code generator routines. | |
| 387 static void GenerateSlot(MacroAssembler* masm); | |
| 388 static void GenerateCallICStubDebugBreak(MacroAssembler* masm); | |
| 389 static void GenerateLoadICDebugBreak(MacroAssembler* masm); | |
| 390 static void GenerateStoreICDebugBreak(MacroAssembler* masm); | |
| 391 static void GenerateKeyedLoadICDebugBreak(MacroAssembler* masm); | |
| 392 static void GenerateKeyedStoreICDebugBreak(MacroAssembler* masm); | |
| 393 static void GenerateCompareNilICDebugBreak(MacroAssembler* masm); | |
| 394 static void GenerateReturnDebugBreak(MacroAssembler* masm); | |
| 395 static void GenerateCallFunctionStubDebugBreak(MacroAssembler* masm); | |
| 396 static void GenerateCallConstructStubDebugBreak(MacroAssembler* masm); | |
| 397 static void GenerateCallConstructStubRecordDebugBreak(MacroAssembler* masm); | |
| 398 static void GenerateSlotDebugBreak(MacroAssembler* masm); | |
| 399 static void GeneratePlainReturnLiveEdit(MacroAssembler* masm); | |
| 400 | |
| 401 // FrameDropper is a code replacement for a JavaScript frame with possibly | |
| 402 // several frames above. | |
| 403 // There is no calling conventions here, because it never actually gets | |
| 404 // called, it only gets returned to. | |
| 405 static void GenerateFrameDropperLiveEdit(MacroAssembler* masm); | |
| 406 | |
| 407 // Describes how exactly a frame has been dropped from stack. | |
| 408 enum FrameDropMode { | |
| 409 // No frame has been dropped. | |
| 410 FRAMES_UNTOUCHED, | |
| 411 // The top JS frame had been calling IC stub. IC stub mustn't be called now. | |
| 412 FRAME_DROPPED_IN_IC_CALL, | |
| 413 // The top JS frame had been calling debug break slot stub. Patch the | |
| 414 // address this stub jumps to in the end. | |
| 415 FRAME_DROPPED_IN_DEBUG_SLOT_CALL, | |
| 416 // The top JS frame had been calling some C++ function. The return address | |
| 417 // gets patched automatically. | |
| 418 FRAME_DROPPED_IN_DIRECT_CALL, | |
| 419 FRAME_DROPPED_IN_RETURN_CALL, | |
| 420 CURRENTLY_SET_MODE | |
| 421 }; | |
| 422 | |
| 423 void FramesHaveBeenDropped(StackFrame::Id new_break_frame_id, | |
| 424 FrameDropMode mode, | |
| 425 Object** restarter_frame_function_pointer); | |
| 426 | |
| 427 // Initializes an artificial stack frame. The data it contains is used for: | |
| 428 // a. successful work of frame dropper code which eventually gets control, | |
| 429 // b. being compatible with regular stack structure for various stack | |
| 430 // iterators. | |
| 431 // Returns address of stack allocated pointer to restarted function, | |
| 432 // the value that is called 'restarter_frame_function_pointer'. The value | |
| 433 // at this address (possibly updated by GC) may be used later when preparing | |
| 434 // 'step in' operation. | |
| 435 static Object** SetUpFrameDropperFrame(StackFrame* bottom_js_frame, | |
| 436 Handle<Code> code); | |
| 437 | |
| 438 static const int kFrameDropperFrameSize; | |
| 439 | |
| 440 // Architecture-specific constant. | |
| 441 static const bool kFrameDropperSupported; | |
| 442 | |
| 443 /** | |
| 444 * Defines layout of a stack frame that supports padding. This is a regular | |
| 445 * internal frame that has a flexible stack structure. LiveEdit can shift | |
| 446 * its lower part up the stack, taking up the 'padding' space when additional | |
| 447 * stack memory is required. | |
| 448 * Such frame is expected immediately above the topmost JavaScript frame. | |
| 449 * | |
| 450 * Stack Layout: | |
| 451 * --- Top | |
| 452 * LiveEdit routine frames | |
| 453 * --- | |
| 454 * C frames of debug handler | |
| 455 * --- | |
| 456 * ... | |
| 457 * --- | |
| 458 * An internal frame that has n padding words: | |
| 459 * - any number of words as needed by code -- upper part of frame | |
| 460 * - padding size: a Smi storing n -- current size of padding | |
| 461 * - padding: n words filled with kPaddingValue in form of Smi | |
| 462 * - 3 context/type words of a regular InternalFrame | |
| 463 * - fp | |
| 464 * --- | |
| 465 * Topmost JavaScript frame | |
| 466 * --- | |
| 467 * ... | |
| 468 * --- Bottom | |
| 469 */ | |
| 470 class FramePaddingLayout : public AllStatic { | |
| 471 public: | |
| 472 // Architecture-specific constant. | |
| 473 static const bool kIsSupported; | |
| 474 | |
| 475 // A size of frame base including fp. Padding words starts right above | |
| 476 // the base. | |
| 477 static const int kFrameBaseSize = 4; | |
| 478 | |
| 479 // A number of words that should be reserved on stack for the LiveEdit use. | |
| 480 // Normally equals 1. Stored on stack in form of Smi. | |
| 481 static const int kInitialSize; | |
| 482 // A value that padding words are filled with (in form of Smi). Going | |
| 483 // bottom-top, the first word not having this value is a counter word. | |
| 484 static const int kPaddingValue; | |
| 485 }; | |
| 486 | |
| 487 private: | |
| 488 explicit Debug(Isolate* isolate); | |
| 489 | |
| 490 static bool CompileDebuggerScript(Isolate* isolate, int index); | |
| 491 void ClearOneShot(); | |
| 492 void ActivateStepIn(StackFrame* frame); | |
| 493 void ClearStepIn(); | |
| 494 void ActivateStepOut(StackFrame* frame); | |
| 495 void ClearStepNext(); | |
| 496 // Returns whether the compile succeeded. | |
| 497 void RemoveDebugInfo(Handle<DebugInfo> debug_info); | |
| 498 void SetAfterBreakTarget(JavaScriptFrame* frame); | |
| 499 Handle<Object> CheckBreakPoints(Handle<Object> break_point); | |
| 500 bool CheckBreakPoint(Handle<Object> break_point_object); | |
| 501 | |
| 502 void EnsureFunctionHasDebugBreakSlots(Handle<JSFunction> function); | |
| 503 void RecompileAndRelocateSuspendedGenerators( | |
| 504 const List<Handle<JSGeneratorObject> > &suspended_generators); | |
| 505 | |
| 506 // Global handle to debug context where all the debugger JavaScript code is | |
| 507 // loaded. | |
| 508 Handle<Context> debug_context_; | |
| 509 | |
| 510 // Boolean state indicating whether any break points are set. | |
| 511 bool has_break_points_; | |
| 512 | |
| 513 // Cache of all scripts in the heap. | |
| 514 ScriptCache* script_cache_; | |
| 515 | |
| 516 // List of active debug info objects. | |
| 517 DebugInfoListNode* debug_info_list_; | |
| 518 | |
| 519 bool disable_break_; | |
| 520 bool break_on_exception_; | |
| 521 bool break_on_uncaught_exception_; | |
| 522 | |
| 523 class PromiseOnStack { | |
| 524 public: | |
| 525 PromiseOnStack(Isolate* isolate, | |
| 526 PromiseOnStack* prev, | |
| 527 Handle<JSFunction> getter); | |
| 528 ~PromiseOnStack(); | |
| 529 StackHandler* handler() { return handler_; } | |
| 530 Handle<JSFunction> getter() { return getter_; } | |
| 531 PromiseOnStack* prev() { return prev_; } | |
| 532 private: | |
| 533 Isolate* isolate_; | |
| 534 StackHandler* handler_; | |
| 535 Handle<JSFunction> getter_; | |
| 536 PromiseOnStack* prev_; | |
| 537 }; | |
| 538 | |
| 539 // Per-thread data. | |
| 540 class ThreadLocal { | |
| 541 public: | |
| 542 // Counter for generating next break id. | |
| 543 int break_count_; | |
| 544 | |
| 545 // Current break id. | |
| 546 int break_id_; | |
| 547 | |
| 548 // Frame id for the frame of the current break. | |
| 549 StackFrame::Id break_frame_id_; | |
| 550 | |
| 551 // Step action for last step performed. | |
| 552 StepAction last_step_action_; | |
| 553 | |
| 554 // Source statement position from last step next action. | |
| 555 int last_statement_position_; | |
| 556 | |
| 557 // Number of steps left to perform before debug event. | |
| 558 int step_count_; | |
| 559 | |
| 560 // Frame pointer from last step next action. | |
| 561 Address last_fp_; | |
| 562 | |
| 563 // Number of queued steps left to perform before debug event. | |
| 564 int queued_step_count_; | |
| 565 | |
| 566 // Frame pointer for frame from which step in was performed. | |
| 567 Address step_into_fp_; | |
| 568 | |
| 569 // Frame pointer for the frame where debugger should be called when current | |
| 570 // step out action is completed. | |
| 571 Address step_out_fp_; | |
| 572 | |
| 573 // Storage location for jump when exiting debug break calls. | |
| 574 Address after_break_target_; | |
| 575 | |
| 576 // Stores the way how LiveEdit has patched the stack. It is used when | |
| 577 // debugger returns control back to user script. | |
| 578 FrameDropMode frame_drop_mode_; | |
| 579 | |
| 580 // Top debugger entry. | |
| 581 EnterDebugger* debugger_entry_; | |
| 582 | |
| 583 // Pending interrupts scheduled while debugging. | |
| 584 bool has_pending_interrupt_; | |
| 585 | |
| 586 // When restarter frame is on stack, stores the address | |
| 587 // of the pointer to function being restarted. Otherwise (most of the time) | |
| 588 // stores NULL. This pointer is used with 'step in' implementation. | |
| 589 Object** restarter_frame_function_pointer_; | |
| 590 | |
| 591 // When a promise is being resolved, we may want to trigger a debug event | |
| 592 // if we catch a throw. For this purpose we remember the try-catch | |
| 593 // handler address that would catch the exception. We also hold onto a | |
| 594 // closure that returns a promise if the exception is considered uncaught. | |
| 595 // Due to the possibility of reentry we use a linked list. | |
| 596 PromiseOnStack* promise_on_stack_; | |
| 597 }; | |
| 598 | |
| 599 // Storage location for registers when handling debug break calls | |
| 600 ThreadLocal thread_local_; | |
| 601 void ThreadInit(); | |
| 602 | |
| 603 Isolate* isolate_; | |
| 604 | |
| 605 friend class Isolate; | |
| 606 | |
| 607 DISALLOW_COPY_AND_ASSIGN(Debug); | |
| 608 }; | |
| 609 | |
| 610 | |
| 611 DECLARE_RUNTIME_FUNCTION(Debug_Break); | |
| 612 | 203 |
| 613 | 204 |
| 614 // Message delivered to the message handler callback. This is either a debugger | 205 // Message delivered to the message handler callback. This is either a debugger |
| 615 // event or the response to a command. | 206 // event or the response to a command. |
| 616 class MessageImpl: public v8::Debug::Message { | 207 class MessageImpl: public v8::Debug::Message { |
| 617 public: | 208 public: |
| 618 // Create a message object for a debug event. | 209 // Create a message object for a debug event. |
| 619 static MessageImpl NewEvent(DebugEvent event, | 210 static MessageImpl NewEvent(DebugEvent event, |
| 620 bool running, | 211 bool running, |
| 621 Handle<JSObject> exec_state, | 212 Handle<JSObject> exec_state, |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 686 | 277 |
| 687 // Message send by user to v8 debugger or debugger output message. | 278 // Message send by user to v8 debugger or debugger output message. |
| 688 // In addition to command text it may contain a pointer to some user data | 279 // In addition to command text it may contain a pointer to some user data |
| 689 // which are expected to be passed along with the command reponse to message | 280 // which are expected to be passed along with the command reponse to message |
| 690 // handler. | 281 // handler. |
| 691 class CommandMessage { | 282 class CommandMessage { |
| 692 public: | 283 public: |
| 693 static CommandMessage New(const Vector<uint16_t>& command, | 284 static CommandMessage New(const Vector<uint16_t>& command, |
| 694 v8::Debug::ClientData* data); | 285 v8::Debug::ClientData* data); |
| 695 CommandMessage(); | 286 CommandMessage(); |
| 696 ~CommandMessage(); | |
| 697 | 287 |
| 698 // Deletes user data and disposes of the text. | 288 // Deletes user data and disposes of the text. |
| 699 void Dispose(); | 289 void Dispose(); |
| 700 Vector<uint16_t> text() const { return text_; } | 290 Vector<uint16_t> text() const { return text_; } |
| 701 v8::Debug::ClientData* client_data() const { return client_data_; } | 291 v8::Debug::ClientData* client_data() const { return client_data_; } |
| 702 private: | 292 private: |
| 703 CommandMessage(const Vector<uint16_t>& text, | 293 CommandMessage(const Vector<uint16_t>& text, |
| 704 v8::Debug::ClientData* data); | 294 v8::Debug::ClientData* data); |
| 705 | 295 |
| 706 Vector<uint16_t> text_; | 296 Vector<uint16_t> text_; |
| 707 v8::Debug::ClientData* client_data_; | 297 v8::Debug::ClientData* client_data_; |
| 708 }; | 298 }; |
| 709 | 299 |
| 300 |
| 710 // A Queue of CommandMessage objects. A thread-safe version is | 301 // A Queue of CommandMessage objects. A thread-safe version is |
| 711 // LockingCommandMessageQueue, based on this class. | 302 // LockingCommandMessageQueue, based on this class. |
| 712 class CommandMessageQueue BASE_EMBEDDED { | 303 class CommandMessageQueue BASE_EMBEDDED { |
| 713 public: | 304 public: |
| 714 explicit CommandMessageQueue(int size); | 305 explicit CommandMessageQueue(int size); |
| 715 ~CommandMessageQueue(); | 306 ~CommandMessageQueue(); |
| 716 bool IsEmpty() const { return start_ == end_; } | 307 bool IsEmpty() const { return start_ == end_; } |
| 717 CommandMessage Get(); | 308 CommandMessage Get(); |
| 718 void Put(const CommandMessage& message); | 309 void Put(const CommandMessage& message); |
| 719 void Clear() { start_ = end_ = 0; } // Queue is empty after Clear(). | 310 void Clear() { start_ = end_ = 0; } // Queue is empty after Clear(). |
| 720 private: | 311 private: |
| 721 // Doubles the size of the message queue, and copies the messages. | 312 // Doubles the size of the message queue, and copies the messages. |
| 722 void Expand(); | 313 void Expand(); |
| 723 | 314 |
| 724 CommandMessage* messages_; | 315 CommandMessage* messages_; |
| 725 int start_; | 316 int start_; |
| 726 int end_; | 317 int end_; |
| 727 int size_; // The size of the queue buffer. Queue can hold size-1 messages. | 318 int size_; // The size of the queue buffer. Queue can hold size-1 messages. |
| 728 }; | 319 }; |
| 729 | 320 |
| 730 | 321 |
| 731 class MessageDispatchHelperThread; | |
| 732 | |
| 733 | |
| 734 // LockingCommandMessageQueue is a thread-safe circular buffer of CommandMessage | 322 // LockingCommandMessageQueue is a thread-safe circular buffer of CommandMessage |
| 735 // messages. The message data is not managed by LockingCommandMessageQueue. | 323 // messages. The message data is not managed by LockingCommandMessageQueue. |
| 736 // Pointers to the data are passed in and out. Implemented by adding a | 324 // Pointers to the data are passed in and out. Implemented by adding a |
| 737 // Mutex to CommandMessageQueue. Includes logging of all puts and gets. | 325 // Mutex to CommandMessageQueue. Includes logging of all puts and gets. |
| 738 class LockingCommandMessageQueue BASE_EMBEDDED { | 326 class LockingCommandMessageQueue BASE_EMBEDDED { |
| 739 public: | 327 public: |
| 740 LockingCommandMessageQueue(Logger* logger, int size); | 328 LockingCommandMessageQueue(Logger* logger, int size); |
| 741 bool IsEmpty() const; | 329 bool IsEmpty() const; |
| 742 CommandMessage Get(); | 330 CommandMessage Get(); |
| 743 void Put(const CommandMessage& message); | 331 void Put(const CommandMessage& message); |
| 744 void Clear(); | 332 void Clear(); |
| 745 private: | 333 private: |
| 746 Logger* logger_; | 334 Logger* logger_; |
| 747 CommandMessageQueue queue_; | 335 CommandMessageQueue queue_; |
| 748 mutable Mutex mutex_; | 336 mutable Mutex mutex_; |
| 749 DISALLOW_COPY_AND_ASSIGN(LockingCommandMessageQueue); | 337 DISALLOW_COPY_AND_ASSIGN(LockingCommandMessageQueue); |
| 750 }; | 338 }; |
| 751 | 339 |
| 752 | 340 |
| 753 class Debugger { | 341 class PromiseOnStack { |
| 754 public: | 342 public: |
| 755 void OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue); | 343 PromiseOnStack(Isolate* isolate, |
| 756 void OnException(Handle<Object> exception, bool uncaught); | 344 PromiseOnStack* prev, |
| 757 void OnBeforeCompile(Handle<Script> script); | 345 Handle<JSFunction> getter); |
| 758 | 346 ~PromiseOnStack(); |
| 347 StackHandler* handler() { return handler_; } |
| 348 Handle<JSFunction> getter() { return getter_; } |
| 349 PromiseOnStack* prev() { return prev_; } |
| 350 private: |
| 351 Isolate* isolate_; |
| 352 StackHandler* handler_; |
| 353 Handle<JSFunction> getter_; |
| 354 PromiseOnStack* prev_; |
| 355 }; |
| 356 |
| 357 |
| 358 // This class contains the debugger support. The main purpose is to handle |
| 359 // setting break points in the code. |
| 360 // |
| 361 // This class controls the debug info for all functions which currently have |
| 362 // active breakpoints in them. This debug info is held in the heap root object |
| 363 // debug_info which is a FixedArray. Each entry in this list is of class |
| 364 // DebugInfo. |
| 365 class Debug { |
| 366 public: |
| 759 enum AfterCompileFlags { | 367 enum AfterCompileFlags { |
| 760 NO_AFTER_COMPILE_FLAGS, | 368 NO_AFTER_COMPILE_FLAGS, |
| 761 SEND_WHEN_DEBUGGING | 369 SEND_WHEN_DEBUGGING |
| 762 }; | 370 }; |
| 371 |
| 372 // Debug event triggers. |
| 373 void OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue); |
| 374 void OnException(Handle<Object> exception, bool uncaught); |
| 375 void OnBeforeCompile(Handle<Script> script); |
| 763 void OnAfterCompile(Handle<Script> script, | 376 void OnAfterCompile(Handle<Script> script, |
| 764 AfterCompileFlags after_compile_flags); | 377 AfterCompileFlags after_compile_flags); |
| 765 void OnScriptCollected(int id); | 378 void OnScriptCollected(int id); |
| 766 | 379 |
| 380 // API facing. |
| 767 void SetEventListener(Handle<Object> callback, Handle<Object> data); | 381 void SetEventListener(Handle<Object> callback, Handle<Object> data); |
| 768 void SetMessageHandler(v8::Debug::MessageHandler handler); | 382 void SetMessageHandler(v8::Debug::MessageHandler handler); |
| 769 | |
| 770 // Add a debugger command to the command queue. | |
| 771 void EnqueueCommandMessage(Vector<const uint16_t> command, | 383 void EnqueueCommandMessage(Vector<const uint16_t> command, |
| 772 v8::Debug::ClientData* client_data = NULL); | 384 v8::Debug::ClientData* client_data = NULL); |
| 773 | |
| 774 // Check whether there are commands in the command queue. | |
| 775 bool HasCommands(); | |
| 776 | |
| 777 // Enqueue a debugger command to the command queue for event listeners. | 385 // Enqueue a debugger command to the command queue for event listeners. |
| 778 void EnqueueDebugCommand(v8::Debug::ClientData* client_data = NULL); | 386 void EnqueueDebugCommand(v8::Debug::ClientData* client_data = NULL); |
| 779 | |
| 780 MUST_USE_RESULT MaybeHandle<Object> Call(Handle<JSFunction> fun, | 387 MUST_USE_RESULT MaybeHandle<Object> Call(Handle<JSFunction> fun, |
| 781 Handle<Object> data); | 388 Handle<Object> data); |
| 782 | |
| 783 Handle<Context> GetDebugContext(); | 389 Handle<Context> GetDebugContext(); |
| 784 | 390 void HandleDebugBreak(); |
| 785 bool ignore_debugger() const { return ignore_debugger_; } | 391 void ProcessDebugMessages(bool debug_command_only); |
| 392 |
| 393 // Internal logic |
| 394 bool Load(); |
| 395 void Break(Arguments args, JavaScriptFrame*); |
| 396 void SetAfterBreakTarget(JavaScriptFrame* frame); |
| 397 |
| 398 // Scripts handling. |
| 399 Handle<FixedArray> GetLoadedScripts(); |
| 400 |
| 401 // Break point handling. |
| 402 bool SetBreakPoint(Handle<JSFunction> function, |
| 403 Handle<Object> break_point_object, |
| 404 int* source_position); |
| 405 bool SetBreakPointForScript(Handle<Script> script, |
| 406 Handle<Object> break_point_object, |
| 407 int* source_position, |
| 408 BreakPositionAlignment alignment); |
| 409 void ClearBreakPoint(Handle<Object> break_point_object); |
| 410 void ClearAllBreakPoints(); |
| 411 void FloodWithOneShot(Handle<JSFunction> function); |
| 412 void FloodBoundFunctionWithOneShot(Handle<JSFunction> function); |
| 413 void FloodHandlerWithOneShot(); |
| 414 void ChangeBreakOnException(ExceptionBreakType type, bool enable); |
| 415 bool IsBreakOnException(ExceptionBreakType type); |
| 416 |
| 417 // Stepping handling. |
| 418 void PrepareStep(StepAction step_action, |
| 419 int step_count, |
| 420 StackFrame::Id frame_id); |
| 421 void ClearStepping(); |
| 422 void ClearStepOut(); |
| 423 bool IsStepping() { return thread_local_.step_count_ > 0; } |
| 424 bool StepNextContinue(BreakLocationIterator* break_location_iterator, |
| 425 JavaScriptFrame* frame); |
| 426 bool StepInActive() { return thread_local_.step_into_fp_ != 0; } |
| 427 void HandleStepIn(Handle<JSFunction> function, |
| 428 Handle<Object> holder, |
| 429 Address fp, |
| 430 bool is_constructor); |
| 431 bool StepOutActive() { return thread_local_.step_out_fp_ != 0; } |
| 432 |
| 433 // Purge all code objects that have no debug break slots. |
| 434 void PrepareForBreakPoints(); |
| 435 |
| 436 // Returns whether the operation succeeded. Compilation can only be triggered |
| 437 // if a valid closure is passed as the second argument, otherwise the shared |
| 438 // function needs to be compiled already. |
| 439 bool EnsureDebugInfo(Handle<SharedFunctionInfo> shared, |
| 440 Handle<JSFunction> function); |
| 441 static Handle<DebugInfo> GetDebugInfo(Handle<SharedFunctionInfo> shared); |
| 442 static bool HasDebugInfo(Handle<SharedFunctionInfo> shared); |
| 443 |
| 444 // This function is used in FunctionNameUsing* tests. |
| 445 Object* FindSharedFunctionInfoInScript(Handle<Script> script, int position); |
| 446 |
| 447 // Returns true if the current stub call is patched to call the debugger. |
| 448 static bool IsDebugBreak(Address addr); |
| 449 // Returns true if the current return statement has been patched to be |
| 450 // a debugger breakpoint. |
| 451 static bool IsDebugBreakAtReturn(RelocInfo* rinfo); |
| 452 |
| 453 static Handle<Object> GetSourceBreakLocations( |
| 454 Handle<SharedFunctionInfo> shared, |
| 455 BreakPositionAlignment position_aligment); |
| 456 |
| 457 // Check whether a global object is the debug global object. |
| 458 bool IsDebugGlobal(GlobalObject* global); |
| 459 |
| 460 // Check whether this frame is just about to return. |
| 461 bool IsBreakAtReturn(JavaScriptFrame* frame); |
| 462 |
| 463 // Promise handling. |
| 464 void PromiseHandlePrologue(Handle<JSFunction> promise_getter); |
| 465 void PromiseHandleEpilogue(); |
| 466 |
| 467 // Support for LiveEdit |
| 468 void FramesHaveBeenDropped(StackFrame::Id new_break_frame_id, |
| 469 LiveEdit::FrameDropMode mode, |
| 470 Object** restarter_frame_function_pointer); |
| 471 |
| 472 // Passed to MakeWeak. |
| 473 static void HandleWeakDebugInfo( |
| 474 const v8::WeakCallbackData<v8::Value, void>& data); |
| 475 |
| 476 // Threading support. |
| 477 char* ArchiveDebug(char* to); |
| 478 char* RestoreDebug(char* from); |
| 479 static int ArchiveSpacePerThread(); |
| 480 void FreeThreadResources() { } |
| 481 |
| 482 // Record function from which eval was called. |
| 483 static void RecordEvalCaller(Handle<Script> script); |
| 484 |
| 485 // Garbage collection notifications. |
| 486 void AfterGarbageCollection(); |
| 487 |
| 488 // Flags and states. |
| 489 DebugScope* debugger_entry() { return thread_local_.current_debug_scope_; } |
| 490 inline Handle<Context> debug_context() { return debug_context_; } |
| 786 void set_live_edit_enabled(bool v) { live_edit_enabled_ = v; } | 491 void set_live_edit_enabled(bool v) { live_edit_enabled_ = v; } |
| 787 bool live_edit_enabled() const { | 492 bool live_edit_enabled() const { |
| 788 return FLAG_enable_liveedit && live_edit_enabled_ ; | 493 return FLAG_enable_liveedit && live_edit_enabled_ ; |
| 789 } | 494 } |
| 790 | 495 |
| 791 bool is_active() { return is_active_; } | 496 inline bool is_active() const { return is_active_; } |
| 792 | 497 inline bool is_loaded() const { return !debug_context_.is_null(); } |
| 793 class IgnoreScope { | 498 inline bool has_break_points() const { return has_break_points_; } |
| 794 public: | 499 inline bool in_debug_scope() const { |
| 795 explicit IgnoreScope(Debugger* debugger) | 500 return thread_local_.current_debug_scope_ != NULL; |
| 796 : debugger_(debugger), | 501 } |
| 797 old_state_(debugger_->ignore_debugger_) { | 502 void set_disable_break(bool v) { break_disabled_ = v; } |
| 798 debugger_->ignore_debugger_ = true; | 503 |
| 799 } | 504 StackFrame::Id break_frame_id() { return thread_local_.break_frame_id_; } |
| 800 | 505 int break_id() { return thread_local_.break_id_; } |
| 801 ~IgnoreScope() { | 506 |
| 802 debugger_->ignore_debugger_ = old_state_; | 507 // Support for embedding into generated code. |
| 803 } | 508 Address after_break_target_address() { |
| 804 | 509 return reinterpret_cast<Address>(&after_break_target_); |
| 805 private: | 510 } |
| 806 Debugger* debugger_; | 511 |
| 807 bool old_state_; | 512 Address restarter_frame_function_pointer_address() { |
| 808 DISALLOW_COPY_AND_ASSIGN(IgnoreScope); | 513 Object*** address = &thread_local_.restarter_frame_function_pointer_; |
| 809 }; | 514 return reinterpret_cast<Address>(address); |
| 515 } |
| 516 |
| 517 Address step_in_fp_addr() { |
| 518 return reinterpret_cast<Address>(&thread_local_.step_into_fp_); |
| 519 } |
| 810 | 520 |
| 811 private: | 521 private: |
| 812 explicit Debugger(Isolate* isolate); | 522 explicit Debug(Isolate* isolate); |
| 813 ~Debugger(); | 523 |
| 814 | 524 void UpdateState(); |
| 525 void Unload(); |
| 526 void SetNextBreakId() { |
| 527 thread_local_.break_id_ = ++thread_local_.break_count_; |
| 528 } |
| 529 |
| 530 // Check whether there are commands in the command queue. |
| 531 inline bool has_commands() const { return !command_queue_.IsEmpty(); } |
| 532 inline bool ignore_events() const { return is_suppressed_ || !is_active_; } |
| 533 |
| 534 // Constructors for debug event objects. |
| 815 MUST_USE_RESULT MaybeHandle<Object> MakeJSObject( | 535 MUST_USE_RESULT MaybeHandle<Object> MakeJSObject( |
| 816 Vector<const char> constructor_name, | 536 const char* constructor_name, |
| 817 int argc, | 537 int argc, |
| 818 Handle<Object> argv[]); | 538 Handle<Object> argv[]); |
| 819 MUST_USE_RESULT MaybeHandle<Object> MakeExecutionState(); | 539 MUST_USE_RESULT MaybeHandle<Object> MakeExecutionState(); |
| 820 MUST_USE_RESULT MaybeHandle<Object> MakeBreakEvent( | 540 MUST_USE_RESULT MaybeHandle<Object> MakeBreakEvent( |
| 821 Handle<Object> break_points_hit); | 541 Handle<Object> break_points_hit); |
| 822 MUST_USE_RESULT MaybeHandle<Object> MakeExceptionEvent( | 542 MUST_USE_RESULT MaybeHandle<Object> MakeExceptionEvent( |
| 823 Handle<Object> exception, | 543 Handle<Object> exception, |
| 824 bool uncaught, | 544 bool uncaught, |
| 825 Handle<Object> promise); | 545 Handle<Object> promise); |
| 826 MUST_USE_RESULT MaybeHandle<Object> MakeCompileEvent( | 546 MUST_USE_RESULT MaybeHandle<Object> MakeCompileEvent( |
| 827 Handle<Script> script, bool before); | 547 Handle<Script> script, bool before); |
| 828 MUST_USE_RESULT MaybeHandle<Object> MakeScriptCollectedEvent(int id); | 548 MUST_USE_RESULT MaybeHandle<Object> MakeScriptCollectedEvent(int id); |
| 829 | 549 |
| 550 // Mirror cache handling. |
| 551 void ClearMirrorCache(); |
| 552 |
| 553 // Returns a promise if it does not have a reject handler. |
| 554 Handle<Object> GetPromiseForUncaughtException(); |
| 555 |
| 830 void CallEventCallback(v8::DebugEvent event, | 556 void CallEventCallback(v8::DebugEvent event, |
| 831 Handle<Object> exec_state, | 557 Handle<Object> exec_state, |
| 832 Handle<Object> event_data, | 558 Handle<Object> event_data, |
| 833 v8::Debug::ClientData* client_data); | 559 v8::Debug::ClientData* client_data); |
| 834 void CallCEventCallback(v8::DebugEvent event, | |
| 835 Handle<Object> exec_state, | |
| 836 Handle<Object> event_data, | |
| 837 v8::Debug::ClientData* client_data); | |
| 838 void CallJSEventCallback(v8::DebugEvent event, | |
| 839 Handle<Object> exec_state, | |
| 840 Handle<Object> event_data); | |
| 841 void UpdateState(); | |
| 842 | |
| 843 void ProcessDebugEvent(v8::DebugEvent event, | 560 void ProcessDebugEvent(v8::DebugEvent event, |
| 844 Handle<JSObject> event_data, | 561 Handle<JSObject> event_data, |
| 845 bool auto_continue); | 562 bool auto_continue); |
| 846 void NotifyMessageHandler(v8::DebugEvent event, | 563 void NotifyMessageHandler(v8::DebugEvent event, |
| 847 Handle<JSObject> exec_state, | 564 Handle<JSObject> exec_state, |
| 848 Handle<JSObject> event_data, | 565 Handle<JSObject> event_data, |
| 849 bool auto_continue); | 566 bool auto_continue); |
| 850 | |
| 851 // Invoke the message handler function. | |
| 852 void InvokeMessageHandler(MessageImpl message); | 567 void InvokeMessageHandler(MessageImpl message); |
| 853 | 568 |
| 854 inline bool EventActive() { | 569 static bool CompileDebuggerScript(Isolate* isolate, int index); |
| 855 // Check whether the message handler was been cleared. | 570 void ClearOneShot(); |
| 856 // TODO(yangguo): handle loading and unloading of the debugger differently. | 571 void ActivateStepIn(StackFrame* frame); |
| 857 // Currently argument event is not used. | 572 void ClearStepIn(); |
| 858 return !ignore_debugger_ && is_active_; | 573 void ActivateStepOut(StackFrame* frame); |
| 574 void ClearStepNext(); |
| 575 // Returns whether the compile succeeded. |
| 576 void RemoveDebugInfo(Handle<DebugInfo> debug_info); |
| 577 Handle<Object> CheckBreakPoints(Handle<Object> break_point); |
| 578 bool CheckBreakPoint(Handle<Object> break_point_object); |
| 579 |
| 580 inline void AssertDebugContext() { |
| 581 ASSERT(isolate_->context() == *debug_context()); |
| 582 ASSERT(in_debug_scope()); |
| 859 } | 583 } |
| 860 | 584 |
| 861 Handle<Object> event_listener_; // Global handle to listener. | 585 void ThreadInit(); |
| 586 |
| 587 // Global handles. |
| 588 Handle<Context> debug_context_; |
| 589 Handle<Object> event_listener_; |
| 862 Handle<Object> event_listener_data_; | 590 Handle<Object> event_listener_data_; |
| 591 |
| 592 v8::Debug::MessageHandler message_handler_; |
| 593 |
| 594 static const int kQueueInitialSize = 4; |
| 595 Semaphore command_received_; // Signaled for each command received. |
| 596 LockingCommandMessageQueue command_queue_; |
| 597 LockingCommandMessageQueue event_command_queue_; |
| 598 |
| 863 bool is_active_; | 599 bool is_active_; |
| 864 bool ignore_debugger_; // Are we temporarily ignoring the debugger? | 600 bool is_suppressed_; |
| 865 bool live_edit_enabled_; // Enable LiveEdit. | 601 bool live_edit_enabled_; |
| 866 v8::Debug::MessageHandler message_handler_; | 602 bool has_break_points_; |
| 867 bool debugger_unload_pending_; // Was message handler cleared? | 603 bool break_disabled_; |
| 868 | 604 bool break_on_exception_; |
| 869 static const int kQueueInitialSize = 4; | 605 bool break_on_uncaught_exception_; |
| 870 LockingCommandMessageQueue command_queue_; | 606 |
| 871 Semaphore command_received_; // Signaled for each command received. | 607 ScriptCache* script_cache_; // Cache of all scripts in the heap. |
| 872 LockingCommandMessageQueue event_command_queue_; | 608 DebugInfoListNode* debug_info_list_; // List of active debug info objects. |
| 609 |
| 610 // Storage location for jump when exiting debug break calls. |
| 611 // Note that this address is not GC safe. It should be computed immediately |
| 612 // before returning to the DebugBreakCallHelper. |
| 613 Address after_break_target_; |
| 614 |
| 615 // Per-thread data. |
| 616 class ThreadLocal { |
| 617 public: |
| 618 // Top debugger entry. |
| 619 DebugScope* current_debug_scope_; |
| 620 |
| 621 // Counter for generating next break id. |
| 622 int break_count_; |
| 623 |
| 624 // Current break id. |
| 625 int break_id_; |
| 626 |
| 627 // Frame id for the frame of the current break. |
| 628 StackFrame::Id break_frame_id_; |
| 629 |
| 630 // Step action for last step performed. |
| 631 StepAction last_step_action_; |
| 632 |
| 633 // Source statement position from last step next action. |
| 634 int last_statement_position_; |
| 635 |
| 636 // Number of steps left to perform before debug event. |
| 637 int step_count_; |
| 638 |
| 639 // Frame pointer from last step next action. |
| 640 Address last_fp_; |
| 641 |
| 642 // Number of queued steps left to perform before debug event. |
| 643 int queued_step_count_; |
| 644 |
| 645 // Frame pointer for frame from which step in was performed. |
| 646 Address step_into_fp_; |
| 647 |
| 648 // Frame pointer for the frame where debugger should be called when current |
| 649 // step out action is completed. |
| 650 Address step_out_fp_; |
| 651 |
| 652 // Stores the way how LiveEdit has patched the stack. It is used when |
| 653 // debugger returns control back to user script. |
| 654 LiveEdit::FrameDropMode frame_drop_mode_; |
| 655 |
| 656 // When restarter frame is on stack, stores the address |
| 657 // of the pointer to function being restarted. Otherwise (most of the time) |
| 658 // stores NULL. This pointer is used with 'step in' implementation. |
| 659 Object** restarter_frame_function_pointer_; |
| 660 |
| 661 // When a promise is being resolved, we may want to trigger a debug event |
| 662 // if we catch a throw. For this purpose we remember the try-catch |
| 663 // handler address that would catch the exception. We also hold onto a |
| 664 // closure that returns a promise if the exception is considered uncaught. |
| 665 // Due to the possibility of reentry we use a linked list. |
| 666 PromiseOnStack* promise_on_stack_; |
| 667 }; |
| 668 |
| 669 // Storage location for registers when handling debug break calls |
| 670 ThreadLocal thread_local_; |
| 873 | 671 |
| 874 Isolate* isolate_; | 672 Isolate* isolate_; |
| 875 | 673 |
| 876 friend class EnterDebugger; | |
| 877 friend class Isolate; | 674 friend class Isolate; |
| 878 | 675 friend class DebugScope; |
| 879 DISALLOW_COPY_AND_ASSIGN(Debugger); | 676 friend class DisableBreak; |
| 880 }; | 677 friend class SuppressDebug; |
| 881 | 678 |
| 882 | 679 friend Handle<FixedArray> GetDebuggedFunctions(); // In test-debug.cc |
| 883 // This class is used for entering the debugger. Create an instance in the stack | 680 friend void CheckDebuggerUnloaded(bool check_functions); // In test-debug.cc |
| 884 // to enter the debugger. This will set the current break state, make sure the | 681 |
| 885 // debugger is loaded and switch to the debugger context. If the debugger for | 682 DISALLOW_COPY_AND_ASSIGN(Debug); |
| 886 // some reason could not be entered FailedToEnter will return true. | 683 }; |
| 887 class EnterDebugger BASE_EMBEDDED { | 684 |
| 888 public: | 685 |
| 889 explicit EnterDebugger(Isolate* isolate); | 686 DECLARE_RUNTIME_FUNCTION(Debug_Break); |
| 890 ~EnterDebugger(); | 687 |
| 891 | 688 |
| 892 // Check whether the debugger could be entered. | 689 // This scope is used to load and enter the debug context and create a new |
| 893 inline bool FailedToEnter() { return load_failed_; } | 690 // break state. Leaving the scope will restore the previous state. |
| 894 | 691 // On failure to load, FailedToEnter returns true. |
| 895 // Check whether there are any JavaScript frames on the stack. | 692 class DebugScope BASE_EMBEDDED { |
| 896 inline bool HasJavaScriptFrames() { return has_js_frames_; } | 693 public: |
| 694 explicit DebugScope(Debug* debug); |
| 695 ~DebugScope(); |
| 696 |
| 697 // Check whether loading was successful. |
| 698 inline bool failed() { return failed_; } |
| 897 | 699 |
| 898 // Get the active context from before entering the debugger. | 700 // Get the active context from before entering the debugger. |
| 899 inline Handle<Context> GetContext() { return save_.context(); } | 701 inline Handle<Context> GetContext() { return save_.context(); } |
| 900 | 702 |
| 901 private: | 703 private: |
| 902 Isolate* isolate_; | 704 Isolate* isolate() { return debug_->isolate_; } |
| 903 EnterDebugger* prev_; // Previous debugger entry if entered recursively. | 705 |
| 904 bool has_js_frames_; // Were there any JavaScript frames? | 706 Debug* debug_; |
| 707 DebugScope* prev_; // Previous scope if entered recursively. |
| 905 StackFrame::Id break_frame_id_; // Previous break frame id. | 708 StackFrame::Id break_frame_id_; // Previous break frame id. |
| 906 int break_id_; // Previous break id. | 709 int break_id_; // Previous break id. |
| 907 bool load_failed_; // Did the debugger fail to load? | 710 bool failed_; // Did the debug context fail to load? |
| 908 SaveContext save_; // Saves previous context. | 711 SaveContext save_; // Saves previous context. |
| 909 }; | 712 }; |
| 910 | 713 |
| 911 | 714 |
| 912 // Stack allocated class for disabling break. | 715 // Stack allocated class for disabling break. |
| 913 class DisableBreak BASE_EMBEDDED { | 716 class DisableBreak BASE_EMBEDDED { |
| 914 public: | 717 public: |
| 915 explicit DisableBreak(Isolate* isolate, bool disable_break) | 718 explicit DisableBreak(Debug* debug, bool disable_break) |
| 916 : isolate_(isolate) { | 719 : debug_(debug), old_state_(debug->break_disabled_) { |
| 917 prev_disable_break_ = isolate_->debug()->disable_break(); | 720 debug_->break_disabled_ = disable_break; |
| 918 isolate_->debug()->set_disable_break(disable_break); | |
| 919 } | 721 } |
| 920 ~DisableBreak() { | 722 ~DisableBreak() { debug_->break_disabled_ = old_state_; } |
| 921 isolate_->debug()->set_disable_break(prev_disable_break_); | 723 |
| 724 private: |
| 725 Debug* debug_; |
| 726 bool old_state_; |
| 727 DISALLOW_COPY_AND_ASSIGN(DisableBreak); |
| 728 }; |
| 729 |
| 730 |
| 731 class SuppressDebug BASE_EMBEDDED { |
| 732 public: |
| 733 explicit SuppressDebug(Debug* debug) |
| 734 : debug_(debug), old_state_(debug->is_suppressed_) { |
| 735 debug_->is_suppressed_ = true; |
| 922 } | 736 } |
| 737 ~SuppressDebug() { debug_->is_suppressed_ = old_state_; } |
| 923 | 738 |
| 924 private: | 739 private: |
| 925 Isolate* isolate_; | 740 Debug* debug_; |
| 926 // The previous state of the disable break used to restore the value when this | 741 bool old_state_; |
| 927 // object is destructed. | 742 DISALLOW_COPY_AND_ASSIGN(SuppressDebug); |
| 928 bool prev_disable_break_; | 743 }; |
| 929 }; | 744 |
| 745 |
| 746 // Code generator routines. |
| 747 class DebugCodegen : public AllStatic { |
| 748 public: |
| 749 static void GenerateSlot(MacroAssembler* masm); |
| 750 static void GenerateCallICStubDebugBreak(MacroAssembler* masm); |
| 751 static void GenerateLoadICDebugBreak(MacroAssembler* masm); |
| 752 static void GenerateStoreICDebugBreak(MacroAssembler* masm); |
| 753 static void GenerateKeyedLoadICDebugBreak(MacroAssembler* masm); |
| 754 static void GenerateKeyedStoreICDebugBreak(MacroAssembler* masm); |
| 755 static void GenerateCompareNilICDebugBreak(MacroAssembler* masm); |
| 756 static void GenerateReturnDebugBreak(MacroAssembler* masm); |
| 757 static void GenerateCallFunctionStubDebugBreak(MacroAssembler* masm); |
| 758 static void GenerateCallConstructStubDebugBreak(MacroAssembler* masm); |
| 759 static void GenerateCallConstructStubRecordDebugBreak(MacroAssembler* masm); |
| 760 static void GenerateSlotDebugBreak(MacroAssembler* masm); |
| 761 static void GeneratePlainReturnLiveEdit(MacroAssembler* masm); |
| 762 |
| 763 // FrameDropper is a code replacement for a JavaScript frame with possibly |
| 764 // several frames above. |
| 765 // There is no calling conventions here, because it never actually gets |
| 766 // called, it only gets returned to. |
| 767 static void GenerateFrameDropperLiveEdit(MacroAssembler* masm); |
| 768 }; |
| 769 |
| 930 | 770 |
| 931 } } // namespace v8::internal | 771 } } // namespace v8::internal |
| 932 | 772 |
| 933 #endif // V8_DEBUG_H_ | 773 #endif // V8_DEBUG_H_ |
| OLD | NEW |