OLD | NEW |
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 18 matching lines...) Expand all Loading... |
29 #define V8_V8_DEBUG_H_ | 29 #define V8_V8_DEBUG_H_ |
30 | 30 |
31 #include "../include/v8-debug.h" | 31 #include "../include/v8-debug.h" |
32 #include "assembler.h" | 32 #include "assembler.h" |
33 #include "code-stubs.h" | 33 #include "code-stubs.h" |
34 #include "debug-agent.h" | 34 #include "debug-agent.h" |
35 #include "execution.h" | 35 #include "execution.h" |
36 #include "factory.h" | 36 #include "factory.h" |
37 #include "platform.h" | 37 #include "platform.h" |
38 #include "string-stream.h" | 38 #include "string-stream.h" |
| 39 #include "v8threads.h" |
39 | 40 |
40 | 41 |
41 namespace v8 { namespace internal { | 42 namespace v8 { namespace internal { |
42 | 43 |
| 44 |
| 45 // Forward declarations. |
| 46 class EnterDebugger; |
| 47 |
| 48 |
43 // Step actions. NOTE: These values are in macros.py as well. | 49 // Step actions. NOTE: These values are in macros.py as well. |
44 enum StepAction { | 50 enum StepAction { |
45 StepNone = -1, // Stepping not prepared. | 51 StepNone = -1, // Stepping not prepared. |
46 StepOut = 0, // Step out of the current function. | 52 StepOut = 0, // Step out of the current function. |
47 StepNext = 1, // Step to the next statement in the current function. | 53 StepNext = 1, // Step to the next statement in the current function. |
48 StepIn = 2, // Step into new functions invoked or the next statement | 54 StepIn = 2, // Step into new functions invoked or the next statement |
49 // in the current function. | 55 // in the current function. |
50 StepMin = 3, // Perform a minimum step in the current function. | 56 StepMin = 3, // Perform a minimum step in the current function. |
51 StepInMin = 4 // Step into new functions invoked or perform a minimum step | 57 StepInMin = 4 // Step into new functions invoked or perform a minimum step |
52 // in the current function. | 58 // in the current function. |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
159 // This class controls the debug info for all functions which currently have | 165 // This class controls the debug info for all functions which currently have |
160 // active breakpoints in them. This debug info is held in the heap root object | 166 // active breakpoints in them. This debug info is held in the heap root object |
161 // debug_info which is a FixedArray. Each entry in this list is of class | 167 // debug_info which is a FixedArray. Each entry in this list is of class |
162 // DebugInfo. | 168 // DebugInfo. |
163 class Debug { | 169 class Debug { |
164 public: | 170 public: |
165 static void Setup(bool create_heap_objects); | 171 static void Setup(bool create_heap_objects); |
166 static bool Load(); | 172 static bool Load(); |
167 static void Unload(); | 173 static void Unload(); |
168 static bool IsLoaded() { return !debug_context_.is_null(); } | 174 static bool IsLoaded() { return !debug_context_.is_null(); } |
169 static bool InDebugger() { return Top::is_break(); } | 175 static bool InDebugger() { return thread_local_.debugger_entry_ != NULL; } |
| 176 static void PreemptionWhileInDebugger(); |
170 static void Iterate(ObjectVisitor* v); | 177 static void Iterate(ObjectVisitor* v); |
171 | 178 |
172 static Object* Break(Arguments args); | 179 static Object* Break(Arguments args); |
173 static void SetBreakPoint(Handle<SharedFunctionInfo> shared, | 180 static void SetBreakPoint(Handle<SharedFunctionInfo> shared, |
174 int source_position, | 181 int source_position, |
175 Handle<Object> break_point_object); | 182 Handle<Object> break_point_object); |
176 static void ClearBreakPoint(Handle<Object> break_point_object); | 183 static void ClearBreakPoint(Handle<Object> break_point_object); |
177 static void ClearAllBreakPoints(); | 184 static void ClearAllBreakPoints(); |
178 static void FloodWithOneShot(Handle<SharedFunctionInfo> shared); | 185 static void FloodWithOneShot(Handle<SharedFunctionInfo> shared); |
179 static void FloodHandlerWithOneShot(); | 186 static void FloodHandlerWithOneShot(); |
(...skipping 24 matching lines...) Expand all Loading... |
204 | 211 |
205 // Getter for the debug_context. | 212 // Getter for the debug_context. |
206 inline static Handle<Context> debug_context() { return debug_context_; } | 213 inline static Handle<Context> debug_context() { return debug_context_; } |
207 | 214 |
208 // Check whether a global object is the debug global object. | 215 // Check whether a global object is the debug global object. |
209 static bool IsDebugGlobal(GlobalObject* global); | 216 static bool IsDebugGlobal(GlobalObject* global); |
210 | 217 |
211 // Fast check to see if any break points are active. | 218 // Fast check to see if any break points are active. |
212 inline static bool has_break_points() { return has_break_points_; } | 219 inline static bool has_break_points() { return has_break_points_; } |
213 | 220 |
| 221 static void NewBreak(StackFrame::Id break_frame_id); |
| 222 static void SetBreak(StackFrame::Id break_frame_id, int break_id); |
| 223 static StackFrame::Id break_frame_id() { |
| 224 return thread_local_.break_frame_id_; |
| 225 } |
| 226 static int break_id() { return thread_local_.break_id_; } |
| 227 |
| 228 |
| 229 |
| 230 |
214 static bool StepInActive() { return thread_local_.step_into_fp_ != 0; } | 231 static bool StepInActive() { return thread_local_.step_into_fp_ != 0; } |
215 static void HandleStepIn(Handle<JSFunction> function, | 232 static void HandleStepIn(Handle<JSFunction> function, |
216 Address fp, | 233 Address fp, |
217 bool is_constructor); | 234 bool is_constructor); |
218 static Address step_in_fp() { return thread_local_.step_into_fp_; } | 235 static Address step_in_fp() { return thread_local_.step_into_fp_; } |
219 static Address* step_in_fp_addr() { return &thread_local_.step_into_fp_; } | 236 static Address* step_in_fp_addr() { return &thread_local_.step_into_fp_; } |
220 | 237 |
| 238 static EnterDebugger* debugger_entry() { |
| 239 return thread_local_.debugger_entry_; |
| 240 } |
| 241 static void set_debugger_entry(EnterDebugger* entry) { |
| 242 thread_local_.debugger_entry_ = entry; |
| 243 } |
| 244 |
| 245 static bool preemption_pending() { |
| 246 return thread_local_.preemption_pending_; |
| 247 } |
| 248 static void set_preemption_pending(bool preemption_pending) { |
| 249 thread_local_.preemption_pending_ = preemption_pending; |
| 250 } |
| 251 |
221 // Getter and setter for the disable break state. | 252 // Getter and setter for the disable break state. |
222 static bool disable_break() { return disable_break_; } | 253 static bool disable_break() { return disable_break_; } |
223 static void set_disable_break(bool disable_break) { | 254 static void set_disable_break(bool disable_break) { |
224 disable_break_ = disable_break; | 255 disable_break_ = disable_break; |
225 } | 256 } |
226 | 257 |
227 // Getters for the current exception break state. | 258 // Getters for the current exception break state. |
228 static bool break_on_exception() { return break_on_exception_; } | 259 static bool break_on_exception() { return break_on_exception_; } |
229 static bool break_on_uncaught_exception() { | 260 static bool break_on_uncaught_exception() { |
230 return break_on_uncaught_exception_; | 261 return break_on_uncaught_exception_; |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
306 static Handle<Context> debug_context_; | 337 static Handle<Context> debug_context_; |
307 | 338 |
308 // Boolean state indicating whether any break points are set. | 339 // Boolean state indicating whether any break points are set. |
309 static bool has_break_points_; | 340 static bool has_break_points_; |
310 static DebugInfoListNode* debug_info_list_; | 341 static DebugInfoListNode* debug_info_list_; |
311 | 342 |
312 static bool disable_break_; | 343 static bool disable_break_; |
313 static bool break_on_exception_; | 344 static bool break_on_exception_; |
314 static bool break_on_uncaught_exception_; | 345 static bool break_on_uncaught_exception_; |
315 | 346 |
316 // Per-thread: | 347 // Per-thread data. |
317 class ThreadLocal { | 348 class ThreadLocal { |
318 public: | 349 public: |
| 350 // Counter for generating next break id. |
| 351 int break_count_; |
| 352 |
| 353 // Current break id. |
| 354 int break_id_; |
| 355 |
| 356 // Frame id for the frame of the current break. |
| 357 StackFrame::Id break_frame_id_; |
| 358 |
319 // Step action for last step performed. | 359 // Step action for last step performed. |
320 StepAction last_step_action_; | 360 StepAction last_step_action_; |
321 | 361 |
322 // Source statement position from last step next action. | 362 // Source statement position from last step next action. |
323 int last_statement_position_; | 363 int last_statement_position_; |
324 | 364 |
325 // Number of steps left to perform before debug event. | 365 // Number of steps left to perform before debug event. |
326 int step_count_; | 366 int step_count_; |
327 | 367 |
328 // Frame pointer from last step next action. | 368 // Frame pointer from last step next action. |
329 Address last_fp_; | 369 Address last_fp_; |
330 | 370 |
331 // Frame pointer for frame from which step in was performed. | 371 // Frame pointer for frame from which step in was performed. |
332 Address step_into_fp_; | 372 Address step_into_fp_; |
333 | 373 |
334 // Storage location for jump when exiting debug break calls. | 374 // Storage location for jump when exiting debug break calls. |
335 Address after_break_target_; | 375 Address after_break_target_; |
| 376 |
| 377 // Top debugger entry. |
| 378 EnterDebugger* debugger_entry_; |
| 379 |
| 380 // Preemption happened while debugging. |
| 381 bool preemption_pending_; |
336 }; | 382 }; |
337 | 383 |
338 // Storage location for registers when handling debug break calls | 384 // Storage location for registers when handling debug break calls |
339 static JSCallerSavedBuffer registers_; | 385 static JSCallerSavedBuffer registers_; |
340 static ThreadLocal thread_local_; | 386 static ThreadLocal thread_local_; |
341 static void ThreadInit(); | 387 static void ThreadInit(); |
342 | 388 |
343 // Code object for debug break return entry code. | 389 // Code object for debug break return entry code. |
344 static Code* debug_break_return_entry_; | 390 static Code* debug_break_return_entry_; |
345 | 391 |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
512 DISALLOW_COPY_AND_ASSIGN(DebugMessageThread); | 558 DISALLOW_COPY_AND_ASSIGN(DebugMessageThread); |
513 }; | 559 }; |
514 | 560 |
515 | 561 |
516 // This class is used for entering the debugger. Create an instance in the stack | 562 // This class is used for entering the debugger. Create an instance in the stack |
517 // to enter the debugger. This will set the current break state, make sure the | 563 // to enter the debugger. This will set the current break state, make sure the |
518 // debugger is loaded and switch to the debugger context. If the debugger for | 564 // debugger is loaded and switch to the debugger context. If the debugger for |
519 // some reason could not be entered FailedToEnter will return true. | 565 // some reason could not be entered FailedToEnter will return true. |
520 class EnterDebugger BASE_EMBEDDED { | 566 class EnterDebugger BASE_EMBEDDED { |
521 public: | 567 public: |
522 EnterDebugger() : has_js_frames_(!it_.done()) { | 568 EnterDebugger() |
| 569 : prev_(Debug::debugger_entry()), |
| 570 has_js_frames_(!it_.done()) { |
| 571 ASSERT(!Debug::preemption_pending()); |
| 572 |
| 573 // Link recursive debugger entry. |
| 574 Debug::set_debugger_entry(this); |
| 575 |
| 576 // If a preemption is pending when first entering the debugger clear it as |
| 577 // we don't want preemption happening while executing JavaScript in the |
| 578 // debugger. When recursively entering the debugger the preemption flag |
| 579 // cannot be set as this is disabled while in the debugger (see |
| 580 // RuntimePreempt). |
| 581 if (prev_ == NULL && StackGuard::IsPreempted()) { |
| 582 StackGuard::Continue(PREEMPT); |
| 583 } |
| 584 ASSERT(!StackGuard::IsPreempted()); |
| 585 |
523 // Store the previous break id and frame id. | 586 // Store the previous break id and frame id. |
524 break_id_ = Top::break_id(); | 587 break_id_ = Debug::break_id(); |
525 break_frame_id_ = Top::break_frame_id(); | 588 break_frame_id_ = Debug::break_frame_id(); |
526 | 589 |
527 // Create the new break info. If there is no JavaScript frames there is no | 590 // Create the new break info. If there is no JavaScript frames there is no |
528 // break frame id. | 591 // break frame id. |
529 if (has_js_frames_) { | 592 if (has_js_frames_) { |
530 Top::new_break(it_.frame()->id()); | 593 Debug::NewBreak(it_.frame()->id()); |
531 } else { | 594 } else { |
532 Top::new_break(StackFrame::NO_ID); | 595 Debug::NewBreak(StackFrame::NO_ID); |
533 } | 596 } |
534 | 597 |
535 // Make sure that debugger is loaded and enter the debugger context. | 598 // Make sure that debugger is loaded and enter the debugger context. |
536 load_failed_ = !Debug::Load(); | 599 load_failed_ = !Debug::Load(); |
537 if (!load_failed_) { | 600 if (!load_failed_) { |
538 // NOTE the member variable save which saves the previous context before | 601 // NOTE the member variable save which saves the previous context before |
539 // this change. | 602 // this change. |
540 Top::set_context(*Debug::debug_context()); | 603 Top::set_context(*Debug::debug_context()); |
541 } | 604 } |
542 } | 605 } |
543 | 606 |
544 ~EnterDebugger() { | 607 ~EnterDebugger() { |
545 // Restore to the previous break state. | 608 // Restore to the previous break state. |
546 Top::set_break(break_frame_id_, break_id_); | 609 Debug::SetBreak(break_frame_id_, break_id_); |
| 610 |
| 611 // Request preemption when leaving the last debugger entry and a preemption |
| 612 // had been recorded while debugging. This is to avoid starvation in some |
| 613 // debugging scenarios. |
| 614 if (prev_ == NULL && Debug::preemption_pending()) { |
| 615 StackGuard::Preempt(); |
| 616 Debug::set_preemption_pending(false); |
| 617 } |
| 618 |
| 619 // Leaving this debugger entry. |
| 620 Debug::set_debugger_entry(prev_); |
547 } | 621 } |
548 | 622 |
549 // Check whether the debugger could be entered. | 623 // Check whether the debugger could be entered. |
550 inline bool FailedToEnter() { return load_failed_; } | 624 inline bool FailedToEnter() { return load_failed_; } |
551 | 625 |
552 // Check whether there are any JavaScript frames on the stack. | 626 // Check whether there are any JavaScript frames on the stack. |
553 inline bool HasJavaScriptFrames() { return has_js_frames_; } | 627 inline bool HasJavaScriptFrames() { return has_js_frames_; } |
554 | 628 |
555 private: | 629 private: |
| 630 EnterDebugger* prev_; // Previous debugger entry if entered recursively. |
556 JavaScriptFrameIterator it_; | 631 JavaScriptFrameIterator it_; |
557 const bool has_js_frames_; // Were there any JavaScript frames? | 632 const bool has_js_frames_; // Were there any JavaScript frames? |
558 StackFrame::Id break_frame_id_; // Previous break frame id. | 633 StackFrame::Id break_frame_id_; // Previous break frame id. |
559 int break_id_; // Previous break id. | 634 int break_id_; // Previous break id. |
560 bool load_failed_; // Did the debugger fail to load? | 635 bool load_failed_; // Did the debugger fail to load? |
561 SaveContext save_; // Saves previous context. | 636 SaveContext save_; // Saves previous context. |
562 }; | 637 }; |
563 | 638 |
564 | 639 |
565 // Stack allocated class for disabling break. | 640 // Stack allocated class for disabling break. |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
618 } | 693 } |
619 private: | 694 private: |
620 Debug::AddressId id_; | 695 Debug::AddressId id_; |
621 int reg_; | 696 int reg_; |
622 }; | 697 }; |
623 | 698 |
624 | 699 |
625 } } // namespace v8::internal | 700 } } // namespace v8::internal |
626 | 701 |
627 #endif // V8_V8_DEBUG_H_ | 702 #endif // V8_V8_DEBUG_H_ |
OLD | NEW |