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" |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
195 Handle<DebugInfo> debug_info() { return debug_info_; } | 195 Handle<DebugInfo> debug_info() { return debug_info_; } |
196 | 196 |
197 private: | 197 private: |
198 // Global (weak) handle to the debug info object. | 198 // Global (weak) handle to the debug info object. |
199 Handle<DebugInfo> debug_info_; | 199 Handle<DebugInfo> debug_info_; |
200 | 200 |
201 // Next pointer for linked list. | 201 // Next pointer for linked list. |
202 DebugInfoListNode* next_; | 202 DebugInfoListNode* next_; |
203 }; | 203 }; |
204 | 204 |
| 205 |
| 206 |
| 207 // Message delivered to the message handler callback. This is either a debugger |
| 208 // event or the response to a command. |
| 209 class MessageImpl: public v8::Debug::Message { |
| 210 public: |
| 211 // Create a message object for a debug event. |
| 212 static MessageImpl NewEvent(DebugEvent event, |
| 213 bool running, |
| 214 Handle<JSObject> exec_state, |
| 215 Handle<JSObject> event_data); |
| 216 |
| 217 // Create a message object for the response to a debug command. |
| 218 static MessageImpl NewResponse(DebugEvent event, |
| 219 bool running, |
| 220 Handle<JSObject> exec_state, |
| 221 Handle<JSObject> event_data, |
| 222 Handle<String> response_json, |
| 223 v8::Debug::ClientData* client_data); |
| 224 |
| 225 // Implementation of interface v8::Debug::Message. |
| 226 virtual bool IsEvent() const; |
| 227 virtual bool IsResponse() const; |
| 228 virtual DebugEvent GetEvent() const; |
| 229 virtual bool WillStartRunning() const; |
| 230 virtual v8::Handle<v8::Object> GetExecutionState() const; |
| 231 virtual v8::Handle<v8::Object> GetEventData() const; |
| 232 virtual v8::Handle<v8::String> GetJSON() const; |
| 233 virtual v8::Handle<v8::Context> GetEventContext() const; |
| 234 virtual v8::Debug::ClientData* GetClientData() const; |
| 235 virtual v8::Isolate* GetIsolate() const; |
| 236 |
| 237 private: |
| 238 MessageImpl(bool is_event, |
| 239 DebugEvent event, |
| 240 bool running, |
| 241 Handle<JSObject> exec_state, |
| 242 Handle<JSObject> event_data, |
| 243 Handle<String> response_json, |
| 244 v8::Debug::ClientData* client_data); |
| 245 |
| 246 bool is_event_; // Does this message represent a debug event? |
| 247 DebugEvent event_; // Debug event causing the break. |
| 248 bool running_; // Will the VM start running after this event? |
| 249 Handle<JSObject> exec_state_; // Current execution state. |
| 250 Handle<JSObject> event_data_; // Data associated with the event. |
| 251 Handle<String> response_json_; // Response JSON if message holds a response. |
| 252 v8::Debug::ClientData* client_data_; // Client data passed with the request. |
| 253 }; |
| 254 |
| 255 |
| 256 // Details of the debug event delivered to the debug event listener. |
| 257 class EventDetailsImpl : public v8::Debug::EventDetails { |
| 258 public: |
| 259 EventDetailsImpl(DebugEvent event, |
| 260 Handle<JSObject> exec_state, |
| 261 Handle<JSObject> event_data, |
| 262 Handle<Object> callback_data, |
| 263 v8::Debug::ClientData* client_data); |
| 264 virtual DebugEvent GetEvent() const; |
| 265 virtual v8::Handle<v8::Object> GetExecutionState() const; |
| 266 virtual v8::Handle<v8::Object> GetEventData() const; |
| 267 virtual v8::Handle<v8::Context> GetEventContext() const; |
| 268 virtual v8::Handle<v8::Value> GetCallbackData() const; |
| 269 virtual v8::Debug::ClientData* GetClientData() const; |
| 270 private: |
| 271 DebugEvent event_; // Debug event causing the break. |
| 272 Handle<JSObject> exec_state_; // Current execution state. |
| 273 Handle<JSObject> event_data_; // Data associated with the event. |
| 274 Handle<Object> callback_data_; // User data passed with the callback |
| 275 // when it was registered. |
| 276 v8::Debug::ClientData* client_data_; // Data passed to DebugBreakForCommand. |
| 277 }; |
| 278 |
| 279 |
| 280 // Message send by user to v8 debugger or debugger output message. |
| 281 // In addition to command text it may contain a pointer to some user data |
| 282 // which are expected to be passed along with the command reponse to message |
| 283 // handler. |
| 284 class CommandMessage { |
| 285 public: |
| 286 static CommandMessage New(const Vector<uint16_t>& command, |
| 287 v8::Debug::ClientData* data); |
| 288 CommandMessage(); |
| 289 ~CommandMessage(); |
| 290 |
| 291 // Deletes user data and disposes of the text. |
| 292 void Dispose(); |
| 293 Vector<uint16_t> text() const { return text_; } |
| 294 v8::Debug::ClientData* client_data() const { return client_data_; } |
| 295 private: |
| 296 CommandMessage(const Vector<uint16_t>& text, |
| 297 v8::Debug::ClientData* data); |
| 298 |
| 299 Vector<uint16_t> text_; |
| 300 v8::Debug::ClientData* client_data_; |
| 301 }; |
| 302 |
| 303 |
| 304 // A Queue of CommandMessage objects. A thread-safe version is |
| 305 // LockingCommandMessageQueue, based on this class. |
| 306 class CommandMessageQueue BASE_EMBEDDED { |
| 307 public: |
| 308 explicit CommandMessageQueue(int size); |
| 309 ~CommandMessageQueue(); |
| 310 bool IsEmpty() const { return start_ == end_; } |
| 311 CommandMessage Get(); |
| 312 void Put(const CommandMessage& message); |
| 313 void Clear() { start_ = end_ = 0; } // Queue is empty after Clear(). |
| 314 private: |
| 315 // Doubles the size of the message queue, and copies the messages. |
| 316 void Expand(); |
| 317 |
| 318 CommandMessage* messages_; |
| 319 int start_; |
| 320 int end_; |
| 321 int size_; // The size of the queue buffer. Queue can hold size-1 messages. |
| 322 }; |
| 323 |
| 324 |
| 325 // LockingCommandMessageQueue is a thread-safe circular buffer of CommandMessage |
| 326 // messages. The message data is not managed by LockingCommandMessageQueue. |
| 327 // Pointers to the data are passed in and out. Implemented by adding a |
| 328 // Mutex to CommandMessageQueue. Includes logging of all puts and gets. |
| 329 class LockingCommandMessageQueue BASE_EMBEDDED { |
| 330 public: |
| 331 LockingCommandMessageQueue(Logger* logger, int size); |
| 332 bool IsEmpty() const; |
| 333 CommandMessage Get(); |
| 334 void Put(const CommandMessage& message); |
| 335 void Clear(); |
| 336 private: |
| 337 Logger* logger_; |
| 338 CommandMessageQueue queue_; |
| 339 mutable Mutex mutex_; |
| 340 DISALLOW_COPY_AND_ASSIGN(LockingCommandMessageQueue); |
| 341 }; |
| 342 |
| 343 |
205 // This class contains the debugger support. The main purpose is to handle | 344 // This class contains the debugger support. The main purpose is to handle |
206 // setting break points in the code. | 345 // setting break points in the code. |
207 // | 346 // |
208 // This class controls the debug info for all functions which currently have | 347 // 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 | 348 // 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 | 349 // debug_info which is a FixedArray. Each entry in this list is of class |
211 // DebugInfo. | 350 // DebugInfo. |
212 class Debug { | 351 class Debug { |
213 public: | 352 public: |
| 353 void OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue); |
| 354 void OnException(Handle<Object> exception, bool uncaught); |
| 355 void OnBeforeCompile(Handle<Script> script); |
| 356 |
| 357 enum AfterCompileFlags { |
| 358 NO_AFTER_COMPILE_FLAGS, |
| 359 SEND_WHEN_DEBUGGING |
| 360 }; |
| 361 void OnAfterCompile(Handle<Script> script, |
| 362 AfterCompileFlags after_compile_flags); |
| 363 void OnScriptCollected(int id); |
| 364 |
| 365 void SetEventListener(Handle<Object> callback, Handle<Object> data); |
| 366 void SetMessageHandler(v8::Debug::MessageHandler handler); |
| 367 |
| 368 // Add a debugger command to the command queue. |
| 369 void EnqueueCommandMessage(Vector<const uint16_t> command, |
| 370 v8::Debug::ClientData* client_data = NULL); |
| 371 |
| 372 // Check whether there are commands in the command queue. |
| 373 bool HasCommands(); |
| 374 |
| 375 // Enqueue a debugger command to the command queue for event listeners. |
| 376 void EnqueueDebugCommand(v8::Debug::ClientData* client_data = NULL); |
| 377 |
| 378 MUST_USE_RESULT MaybeHandle<Object> Call(Handle<JSFunction> fun, |
| 379 Handle<Object> data); |
| 380 |
| 381 Handle<Context> GetDebugContext(); |
| 382 |
| 383 bool ignore_debugger() const { return ignore_debugger_; } |
| 384 void set_live_edit_enabled(bool v) { live_edit_enabled_ = v; } |
| 385 bool live_edit_enabled() const { |
| 386 return FLAG_enable_liveedit && live_edit_enabled_ ; |
| 387 } |
| 388 |
| 389 bool is_active() { return is_active_; } |
| 390 |
| 391 class IgnoreScope { |
| 392 public: |
| 393 explicit IgnoreScope(Debug* debug) |
| 394 : debug_(debug), |
| 395 old_state_(debug->ignore_debugger_) { |
| 396 debug_->ignore_debugger_ = true; |
| 397 } |
| 398 |
| 399 ~IgnoreScope() { |
| 400 debug_->ignore_debugger_ = old_state_; |
| 401 } |
| 402 |
| 403 private: |
| 404 Debug* debug_; |
| 405 bool old_state_; |
| 406 DISALLOW_COPY_AND_ASSIGN(IgnoreScope); |
| 407 }; |
| 408 |
| 409 |
214 bool Load(); | 410 bool Load(); |
215 void Unload(); | 411 void Unload(); |
216 bool IsLoaded() { return !debug_context_.is_null(); } | 412 bool IsLoaded() { return !debug_context_.is_null(); } |
217 bool InDebugger() { return thread_local_.debugger_entry_ != NULL; } | 413 bool InDebugger() { return thread_local_.debugger_entry_ != NULL; } |
218 | 414 |
219 Object* Break(Arguments args); | 415 Object* Break(Arguments args); |
220 bool SetBreakPoint(Handle<JSFunction> function, | 416 bool SetBreakPoint(Handle<JSFunction> function, |
221 Handle<Object> break_point_object, | 417 Handle<Object> break_point_object, |
222 int* source_position); | 418 int* source_position); |
223 bool SetBreakPointForScript(Handle<Script> script, | 419 bool SetBreakPointForScript(Handle<Script> script, |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
351 return reinterpret_cast<Address>(address); | 547 return reinterpret_cast<Address>(address); |
352 } | 548 } |
353 | 549 |
354 static const int kEstimatedNofDebugInfoEntries = 16; | 550 static const int kEstimatedNofDebugInfoEntries = 16; |
355 static const int kEstimatedNofBreakPointsInFunction = 16; | 551 static const int kEstimatedNofBreakPointsInFunction = 16; |
356 | 552 |
357 // Passed to MakeWeak. | 553 // Passed to MakeWeak. |
358 static void HandleWeakDebugInfo( | 554 static void HandleWeakDebugInfo( |
359 const v8::WeakCallbackData<v8::Value, void>& data); | 555 const v8::WeakCallbackData<v8::Value, void>& data); |
360 | 556 |
361 friend class Debugger; | |
362 friend Handle<FixedArray> GetDebuggedFunctions(); // In test-debug.cc | 557 friend Handle<FixedArray> GetDebuggedFunctions(); // In test-debug.cc |
363 friend void CheckDebuggerUnloaded(bool check_functions); // In test-debug.cc | 558 friend void CheckDebuggerUnloaded(bool check_functions); // In test-debug.cc |
364 | 559 |
365 // Threading support. | 560 // Threading support. |
366 char* ArchiveDebug(char* to); | 561 char* ArchiveDebug(char* to); |
367 char* RestoreDebug(char* from); | 562 char* RestoreDebug(char* from); |
368 static int ArchiveSpacePerThread(); | 563 static int ArchiveSpacePerThread(); |
369 void FreeThreadResources() { } | 564 void FreeThreadResources() { } |
370 | 565 |
371 // Mirror cache handling. | 566 // Mirror cache handling. |
372 void ClearMirrorCache(); | 567 void ClearMirrorCache(); |
373 | 568 |
374 // Script cache handling. | 569 // Script cache handling. |
375 void CreateScriptCache(); | 570 void CreateScriptCache(); |
376 void DestroyScriptCache(); | 571 void DestroyScriptCache(); |
377 void AddScriptToScriptCache(Handle<Script> script); | 572 void AddScriptToScriptCache(Handle<Script> script); |
378 Handle<FixedArray> GetLoadedScripts(); | 573 Handle<FixedArray> GetLoadedScripts(); |
379 | 574 |
380 // Record function from which eval was called. | 575 // Record function from which eval was called. |
381 static void RecordEvalCaller(Handle<Script> script); | 576 static void RecordEvalCaller(Handle<Script> script); |
382 | 577 |
383 // Garbage collection notifications. | 578 // Garbage collection notifications. |
384 void AfterGarbageCollection(); | 579 void AfterGarbageCollection(); |
385 | 580 |
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. | 581 // Describes how exactly a frame has been dropped from stack. |
408 enum FrameDropMode { | 582 enum FrameDropMode { |
409 // No frame has been dropped. | 583 // No frame has been dropped. |
410 FRAMES_UNTOUCHED, | 584 FRAMES_UNTOUCHED, |
411 // The top JS frame had been calling IC stub. IC stub mustn't be called now. | 585 // The top JS frame had been calling IC stub. IC stub mustn't be called now. |
412 FRAME_DROPPED_IN_IC_CALL, | 586 FRAME_DROPPED_IN_IC_CALL, |
413 // The top JS frame had been calling debug break slot stub. Patch the | 587 // The top JS frame had been calling debug break slot stub. Patch the |
414 // address this stub jumps to in the end. | 588 // address this stub jumps to in the end. |
415 FRAME_DROPPED_IN_DEBUG_SLOT_CALL, | 589 FRAME_DROPPED_IN_DEBUG_SLOT_CALL, |
416 // The top JS frame had been calling some C++ function. The return address | 590 // The top JS frame had been calling some C++ function. The return address |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
480 // Normally equals 1. Stored on stack in form of Smi. | 654 // Normally equals 1. Stored on stack in form of Smi. |
481 static const int kInitialSize; | 655 static const int kInitialSize; |
482 // A value that padding words are filled with (in form of Smi). Going | 656 // 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. | 657 // bottom-top, the first word not having this value is a counter word. |
484 static const int kPaddingValue; | 658 static const int kPaddingValue; |
485 }; | 659 }; |
486 | 660 |
487 private: | 661 private: |
488 explicit Debug(Isolate* isolate); | 662 explicit Debug(Isolate* isolate); |
489 | 663 |
| 664 MUST_USE_RESULT MaybeHandle<Object> MakeJSObject( |
| 665 Vector<const char> constructor_name, |
| 666 int argc, |
| 667 Handle<Object> argv[]); |
| 668 MUST_USE_RESULT MaybeHandle<Object> MakeExecutionState(); |
| 669 MUST_USE_RESULT MaybeHandle<Object> MakeBreakEvent( |
| 670 Handle<Object> break_points_hit); |
| 671 MUST_USE_RESULT MaybeHandle<Object> MakeExceptionEvent( |
| 672 Handle<Object> exception, |
| 673 bool uncaught, |
| 674 Handle<Object> promise); |
| 675 MUST_USE_RESULT MaybeHandle<Object> MakeCompileEvent( |
| 676 Handle<Script> script, bool before); |
| 677 MUST_USE_RESULT MaybeHandle<Object> MakeScriptCollectedEvent(int id); |
| 678 |
| 679 void CallEventCallback(v8::DebugEvent event, |
| 680 Handle<Object> exec_state, |
| 681 Handle<Object> event_data, |
| 682 v8::Debug::ClientData* client_data); |
| 683 void CallCEventCallback(v8::DebugEvent event, |
| 684 Handle<Object> exec_state, |
| 685 Handle<Object> event_data, |
| 686 v8::Debug::ClientData* client_data); |
| 687 void CallJSEventCallback(v8::DebugEvent event, |
| 688 Handle<Object> exec_state, |
| 689 Handle<Object> event_data); |
| 690 void UpdateState(); |
| 691 |
| 692 void ProcessDebugEvent(v8::DebugEvent event, |
| 693 Handle<JSObject> event_data, |
| 694 bool auto_continue); |
| 695 void NotifyMessageHandler(v8::DebugEvent event, |
| 696 Handle<JSObject> exec_state, |
| 697 Handle<JSObject> event_data, |
| 698 bool auto_continue); |
| 699 |
| 700 // Invoke the message handler function. |
| 701 void InvokeMessageHandler(MessageImpl message); |
| 702 |
| 703 inline bool EventActive() { |
| 704 // Check whether the message handler was been cleared. |
| 705 // TODO(yangguo): handle loading and unloading of the debugger differently. |
| 706 // Currently argument event is not used. |
| 707 return !ignore_debugger_ && is_active_; |
| 708 } |
| 709 |
490 static bool CompileDebuggerScript(Isolate* isolate, int index); | 710 static bool CompileDebuggerScript(Isolate* isolate, int index); |
491 void ClearOneShot(); | 711 void ClearOneShot(); |
492 void ActivateStepIn(StackFrame* frame); | 712 void ActivateStepIn(StackFrame* frame); |
493 void ClearStepIn(); | 713 void ClearStepIn(); |
494 void ActivateStepOut(StackFrame* frame); | 714 void ActivateStepOut(StackFrame* frame); |
495 void ClearStepNext(); | 715 void ClearStepNext(); |
496 // Returns whether the compile succeeded. | 716 // Returns whether the compile succeeded. |
497 void RemoveDebugInfo(Handle<DebugInfo> debug_info); | 717 void RemoveDebugInfo(Handle<DebugInfo> debug_info); |
498 void SetAfterBreakTarget(JavaScriptFrame* frame); | 718 void SetAfterBreakTarget(JavaScriptFrame* frame); |
499 Handle<Object> CheckBreakPoints(Handle<Object> break_point); | 719 Handle<Object> CheckBreakPoints(Handle<Object> break_point); |
500 bool CheckBreakPoint(Handle<Object> break_point_object); | 720 bool CheckBreakPoint(Handle<Object> break_point_object); |
501 | 721 |
502 void EnsureFunctionHasDebugBreakSlots(Handle<JSFunction> function); | 722 void EnsureFunctionHasDebugBreakSlots(Handle<JSFunction> function); |
503 void RecompileAndRelocateSuspendedGenerators( | 723 void RecompileAndRelocateSuspendedGenerators( |
504 const List<Handle<JSGeneratorObject> > &suspended_generators); | 724 const List<Handle<JSGeneratorObject> > &suspended_generators); |
505 | 725 |
506 // Global handle to debug context where all the debugger JavaScript code is | 726 void ThreadInit(); |
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 | 727 |
523 class PromiseOnStack { | 728 class PromiseOnStack { |
524 public: | 729 public: |
525 PromiseOnStack(Isolate* isolate, | 730 PromiseOnStack(Isolate* isolate, |
526 PromiseOnStack* prev, | 731 PromiseOnStack* prev, |
527 Handle<JSFunction> getter); | 732 Handle<JSFunction> getter); |
528 ~PromiseOnStack(); | 733 ~PromiseOnStack(); |
529 StackHandler* handler() { return handler_; } | 734 StackHandler* handler() { return handler_; } |
530 Handle<JSFunction> getter() { return getter_; } | 735 Handle<JSFunction> getter() { return getter_; } |
531 PromiseOnStack* prev() { return prev_; } | 736 PromiseOnStack* prev() { return prev_; } |
532 private: | 737 private: |
533 Isolate* isolate_; | 738 Isolate* isolate_; |
534 StackHandler* handler_; | 739 StackHandler* handler_; |
535 Handle<JSFunction> getter_; | 740 Handle<JSFunction> getter_; |
536 PromiseOnStack* prev_; | 741 PromiseOnStack* prev_; |
537 }; | 742 }; |
538 | 743 |
| 744 // Global handles. |
| 745 Handle<Context> debug_context_; |
| 746 Handle<Object> event_listener_; |
| 747 Handle<Object> event_listener_data_; |
| 748 |
| 749 v8::Debug::MessageHandler message_handler_; |
| 750 |
| 751 static const int kQueueInitialSize = 4; |
| 752 Semaphore command_received_; // Signaled for each command received. |
| 753 LockingCommandMessageQueue command_queue_; |
| 754 LockingCommandMessageQueue event_command_queue_; |
| 755 |
| 756 bool is_active_; |
| 757 bool ignore_debugger_; |
| 758 bool live_edit_enabled_; |
| 759 bool has_break_points_; |
| 760 bool disable_break_; |
| 761 bool break_on_exception_; |
| 762 bool break_on_uncaught_exception_; |
| 763 |
| 764 ScriptCache* script_cache_; // Cache of all scripts in the heap. |
| 765 DebugInfoListNode* debug_info_list_; // List of active debug info objects. |
| 766 |
539 // Per-thread data. | 767 // Per-thread data. |
540 class ThreadLocal { | 768 class ThreadLocal { |
541 public: | 769 public: |
542 // Counter for generating next break id. | 770 // Counter for generating next break id. |
543 int break_count_; | 771 int break_count_; |
544 | 772 |
545 // Current break id. | 773 // Current break id. |
546 int break_id_; | 774 int break_id_; |
547 | 775 |
548 // Frame id for the frame of the current break. | 776 // Frame id for the frame of the current break. |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
591 // When a promise is being resolved, we may want to trigger a debug event | 819 // 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 | 820 // 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 | 821 // handler address that would catch the exception. We also hold onto a |
594 // closure that returns a promise if the exception is considered uncaught. | 822 // closure that returns a promise if the exception is considered uncaught. |
595 // Due to the possibility of reentry we use a linked list. | 823 // Due to the possibility of reentry we use a linked list. |
596 PromiseOnStack* promise_on_stack_; | 824 PromiseOnStack* promise_on_stack_; |
597 }; | 825 }; |
598 | 826 |
599 // Storage location for registers when handling debug break calls | 827 // Storage location for registers when handling debug break calls |
600 ThreadLocal thread_local_; | 828 ThreadLocal thread_local_; |
601 void ThreadInit(); | |
602 | 829 |
603 Isolate* isolate_; | 830 Isolate* isolate_; |
604 | 831 |
605 friend class Isolate; | 832 friend class Isolate; |
| 833 friend class EnterDebugger; |
606 | 834 |
607 DISALLOW_COPY_AND_ASSIGN(Debug); | 835 DISALLOW_COPY_AND_ASSIGN(Debug); |
608 }; | 836 }; |
609 | 837 |
610 | 838 |
611 DECLARE_RUNTIME_FUNCTION(Debug_Break); | 839 DECLARE_RUNTIME_FUNCTION(Debug_Break); |
612 | 840 |
613 | 841 |
614 // Message delivered to the message handler callback. This is either a debugger | |
615 // event or the response to a command. | |
616 class MessageImpl: public v8::Debug::Message { | |
617 public: | |
618 // Create a message object for a debug event. | |
619 static MessageImpl NewEvent(DebugEvent event, | |
620 bool running, | |
621 Handle<JSObject> exec_state, | |
622 Handle<JSObject> event_data); | |
623 | |
624 // Create a message object for the response to a debug command. | |
625 static MessageImpl NewResponse(DebugEvent event, | |
626 bool running, | |
627 Handle<JSObject> exec_state, | |
628 Handle<JSObject> event_data, | |
629 Handle<String> response_json, | |
630 v8::Debug::ClientData* client_data); | |
631 | |
632 // Implementation of interface v8::Debug::Message. | |
633 virtual bool IsEvent() const; | |
634 virtual bool IsResponse() const; | |
635 virtual DebugEvent GetEvent() const; | |
636 virtual bool WillStartRunning() const; | |
637 virtual v8::Handle<v8::Object> GetExecutionState() const; | |
638 virtual v8::Handle<v8::Object> GetEventData() const; | |
639 virtual v8::Handle<v8::String> GetJSON() const; | |
640 virtual v8::Handle<v8::Context> GetEventContext() const; | |
641 virtual v8::Debug::ClientData* GetClientData() const; | |
642 virtual v8::Isolate* GetIsolate() const; | |
643 | |
644 private: | |
645 MessageImpl(bool is_event, | |
646 DebugEvent event, | |
647 bool running, | |
648 Handle<JSObject> exec_state, | |
649 Handle<JSObject> event_data, | |
650 Handle<String> response_json, | |
651 v8::Debug::ClientData* client_data); | |
652 | |
653 bool is_event_; // Does this message represent a debug event? | |
654 DebugEvent event_; // Debug event causing the break. | |
655 bool running_; // Will the VM start running after this event? | |
656 Handle<JSObject> exec_state_; // Current execution state. | |
657 Handle<JSObject> event_data_; // Data associated with the event. | |
658 Handle<String> response_json_; // Response JSON if message holds a response. | |
659 v8::Debug::ClientData* client_data_; // Client data passed with the request. | |
660 }; | |
661 | |
662 | |
663 // Details of the debug event delivered to the debug event listener. | |
664 class EventDetailsImpl : public v8::Debug::EventDetails { | |
665 public: | |
666 EventDetailsImpl(DebugEvent event, | |
667 Handle<JSObject> exec_state, | |
668 Handle<JSObject> event_data, | |
669 Handle<Object> callback_data, | |
670 v8::Debug::ClientData* client_data); | |
671 virtual DebugEvent GetEvent() const; | |
672 virtual v8::Handle<v8::Object> GetExecutionState() const; | |
673 virtual v8::Handle<v8::Object> GetEventData() const; | |
674 virtual v8::Handle<v8::Context> GetEventContext() const; | |
675 virtual v8::Handle<v8::Value> GetCallbackData() const; | |
676 virtual v8::Debug::ClientData* GetClientData() const; | |
677 private: | |
678 DebugEvent event_; // Debug event causing the break. | |
679 Handle<JSObject> exec_state_; // Current execution state. | |
680 Handle<JSObject> event_data_; // Data associated with the event. | |
681 Handle<Object> callback_data_; // User data passed with the callback | |
682 // when it was registered. | |
683 v8::Debug::ClientData* client_data_; // Data passed to DebugBreakForCommand. | |
684 }; | |
685 | |
686 | |
687 // 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 | |
689 // which are expected to be passed along with the command reponse to message | |
690 // handler. | |
691 class CommandMessage { | |
692 public: | |
693 static CommandMessage New(const Vector<uint16_t>& command, | |
694 v8::Debug::ClientData* data); | |
695 CommandMessage(); | |
696 ~CommandMessage(); | |
697 | |
698 // Deletes user data and disposes of the text. | |
699 void Dispose(); | |
700 Vector<uint16_t> text() const { return text_; } | |
701 v8::Debug::ClientData* client_data() const { return client_data_; } | |
702 private: | |
703 CommandMessage(const Vector<uint16_t>& text, | |
704 v8::Debug::ClientData* data); | |
705 | |
706 Vector<uint16_t> text_; | |
707 v8::Debug::ClientData* client_data_; | |
708 }; | |
709 | |
710 // A Queue of CommandMessage objects. A thread-safe version is | |
711 // LockingCommandMessageQueue, based on this class. | |
712 class CommandMessageQueue BASE_EMBEDDED { | |
713 public: | |
714 explicit CommandMessageQueue(int size); | |
715 ~CommandMessageQueue(); | |
716 bool IsEmpty() const { return start_ == end_; } | |
717 CommandMessage Get(); | |
718 void Put(const CommandMessage& message); | |
719 void Clear() { start_ = end_ = 0; } // Queue is empty after Clear(). | |
720 private: | |
721 // Doubles the size of the message queue, and copies the messages. | |
722 void Expand(); | |
723 | |
724 CommandMessage* messages_; | |
725 int start_; | |
726 int end_; | |
727 int size_; // The size of the queue buffer. Queue can hold size-1 messages. | |
728 }; | |
729 | |
730 | |
731 class MessageDispatchHelperThread; | |
732 | |
733 | |
734 // LockingCommandMessageQueue is a thread-safe circular buffer of CommandMessage | |
735 // messages. The message data is not managed by LockingCommandMessageQueue. | |
736 // Pointers to the data are passed in and out. Implemented by adding a | |
737 // Mutex to CommandMessageQueue. Includes logging of all puts and gets. | |
738 class LockingCommandMessageQueue BASE_EMBEDDED { | |
739 public: | |
740 LockingCommandMessageQueue(Logger* logger, int size); | |
741 bool IsEmpty() const; | |
742 CommandMessage Get(); | |
743 void Put(const CommandMessage& message); | |
744 void Clear(); | |
745 private: | |
746 Logger* logger_; | |
747 CommandMessageQueue queue_; | |
748 mutable Mutex mutex_; | |
749 DISALLOW_COPY_AND_ASSIGN(LockingCommandMessageQueue); | |
750 }; | |
751 | |
752 | |
753 class Debugger { | |
754 public: | |
755 void OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue); | |
756 void OnException(Handle<Object> exception, bool uncaught); | |
757 void OnBeforeCompile(Handle<Script> script); | |
758 | |
759 enum AfterCompileFlags { | |
760 NO_AFTER_COMPILE_FLAGS, | |
761 SEND_WHEN_DEBUGGING | |
762 }; | |
763 void OnAfterCompile(Handle<Script> script, | |
764 AfterCompileFlags after_compile_flags); | |
765 void OnScriptCollected(int id); | |
766 | |
767 void SetEventListener(Handle<Object> callback, Handle<Object> data); | |
768 void SetMessageHandler(v8::Debug::MessageHandler handler); | |
769 | |
770 // Add a debugger command to the command queue. | |
771 void EnqueueCommandMessage(Vector<const uint16_t> command, | |
772 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. | |
778 void EnqueueDebugCommand(v8::Debug::ClientData* client_data = NULL); | |
779 | |
780 MUST_USE_RESULT MaybeHandle<Object> Call(Handle<JSFunction> fun, | |
781 Handle<Object> data); | |
782 | |
783 Handle<Context> GetDebugContext(); | |
784 | |
785 bool ignore_debugger() const { return ignore_debugger_; } | |
786 void set_live_edit_enabled(bool v) { live_edit_enabled_ = v; } | |
787 bool live_edit_enabled() const { | |
788 return FLAG_enable_liveedit && live_edit_enabled_ ; | |
789 } | |
790 | |
791 bool is_active() { return is_active_; } | |
792 | |
793 class IgnoreScope { | |
794 public: | |
795 explicit IgnoreScope(Debugger* debugger) | |
796 : debugger_(debugger), | |
797 old_state_(debugger_->ignore_debugger_) { | |
798 debugger_->ignore_debugger_ = true; | |
799 } | |
800 | |
801 ~IgnoreScope() { | |
802 debugger_->ignore_debugger_ = old_state_; | |
803 } | |
804 | |
805 private: | |
806 Debugger* debugger_; | |
807 bool old_state_; | |
808 DISALLOW_COPY_AND_ASSIGN(IgnoreScope); | |
809 }; | |
810 | |
811 private: | |
812 explicit Debugger(Isolate* isolate); | |
813 ~Debugger(); | |
814 | |
815 MUST_USE_RESULT MaybeHandle<Object> MakeJSObject( | |
816 Vector<const char> constructor_name, | |
817 int argc, | |
818 Handle<Object> argv[]); | |
819 MUST_USE_RESULT MaybeHandle<Object> MakeExecutionState(); | |
820 MUST_USE_RESULT MaybeHandle<Object> MakeBreakEvent( | |
821 Handle<Object> break_points_hit); | |
822 MUST_USE_RESULT MaybeHandle<Object> MakeExceptionEvent( | |
823 Handle<Object> exception, | |
824 bool uncaught, | |
825 Handle<Object> promise); | |
826 MUST_USE_RESULT MaybeHandle<Object> MakeCompileEvent( | |
827 Handle<Script> script, bool before); | |
828 MUST_USE_RESULT MaybeHandle<Object> MakeScriptCollectedEvent(int id); | |
829 | |
830 void CallEventCallback(v8::DebugEvent event, | |
831 Handle<Object> exec_state, | |
832 Handle<Object> event_data, | |
833 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, | |
844 Handle<JSObject> event_data, | |
845 bool auto_continue); | |
846 void NotifyMessageHandler(v8::DebugEvent event, | |
847 Handle<JSObject> exec_state, | |
848 Handle<JSObject> event_data, | |
849 bool auto_continue); | |
850 | |
851 // Invoke the message handler function. | |
852 void InvokeMessageHandler(MessageImpl message); | |
853 | |
854 inline bool EventActive() { | |
855 // Check whether the message handler was been cleared. | |
856 // TODO(yangguo): handle loading and unloading of the debugger differently. | |
857 // Currently argument event is not used. | |
858 return !ignore_debugger_ && is_active_; | |
859 } | |
860 | |
861 Handle<Object> event_listener_; // Global handle to listener. | |
862 Handle<Object> event_listener_data_; | |
863 bool is_active_; | |
864 bool ignore_debugger_; // Are we temporarily ignoring the debugger? | |
865 bool live_edit_enabled_; // Enable LiveEdit. | |
866 v8::Debug::MessageHandler message_handler_; | |
867 bool debugger_unload_pending_; // Was message handler cleared? | |
868 | |
869 static const int kQueueInitialSize = 4; | |
870 LockingCommandMessageQueue command_queue_; | |
871 Semaphore command_received_; // Signaled for each command received. | |
872 LockingCommandMessageQueue event_command_queue_; | |
873 | |
874 Isolate* isolate_; | |
875 | |
876 friend class EnterDebugger; | |
877 friend class Isolate; | |
878 | |
879 DISALLOW_COPY_AND_ASSIGN(Debugger); | |
880 }; | |
881 | |
882 | |
883 // This class is used for entering the debugger. Create an instance in the stack | 842 // This class is used for entering the debugger. Create an instance in the stack |
884 // to enter the debugger. This will set the current break state, make sure the | 843 // to enter the debugger. This will set the current break state, make sure the |
885 // debugger is loaded and switch to the debugger context. If the debugger for | 844 // debugger is loaded and switch to the debugger context. If the debugger for |
886 // some reason could not be entered FailedToEnter will return true. | 845 // some reason could not be entered FailedToEnter will return true. |
887 class EnterDebugger BASE_EMBEDDED { | 846 class EnterDebugger BASE_EMBEDDED { |
888 public: | 847 public: |
889 explicit EnterDebugger(Isolate* isolate); | 848 explicit EnterDebugger(Isolate* isolate); |
890 ~EnterDebugger(); | 849 ~EnterDebugger(); |
891 | 850 |
892 // Check whether the debugger could be entered. | 851 // Check whether the debugger could be entered. |
(...skipping 28 matching lines...) Expand all Loading... |
921 isolate_->debug()->set_disable_break(prev_disable_break_); | 880 isolate_->debug()->set_disable_break(prev_disable_break_); |
922 } | 881 } |
923 | 882 |
924 private: | 883 private: |
925 Isolate* isolate_; | 884 Isolate* isolate_; |
926 // The previous state of the disable break used to restore the value when this | 885 // The previous state of the disable break used to restore the value when this |
927 // object is destructed. | 886 // object is destructed. |
928 bool prev_disable_break_; | 887 bool prev_disable_break_; |
929 }; | 888 }; |
930 | 889 |
| 890 |
| 891 // Code generator routines. |
| 892 class DebugCodegen : public AllStatic { |
| 893 public: |
| 894 static void GenerateSlot(MacroAssembler* masm); |
| 895 static void GenerateCallICStubDebugBreak(MacroAssembler* masm); |
| 896 static void GenerateLoadICDebugBreak(MacroAssembler* masm); |
| 897 static void GenerateStoreICDebugBreak(MacroAssembler* masm); |
| 898 static void GenerateKeyedLoadICDebugBreak(MacroAssembler* masm); |
| 899 static void GenerateKeyedStoreICDebugBreak(MacroAssembler* masm); |
| 900 static void GenerateCompareNilICDebugBreak(MacroAssembler* masm); |
| 901 static void GenerateReturnDebugBreak(MacroAssembler* masm); |
| 902 static void GenerateCallFunctionStubDebugBreak(MacroAssembler* masm); |
| 903 static void GenerateCallConstructStubDebugBreak(MacroAssembler* masm); |
| 904 static void GenerateCallConstructStubRecordDebugBreak(MacroAssembler* masm); |
| 905 static void GenerateSlotDebugBreak(MacroAssembler* masm); |
| 906 static void GeneratePlainReturnLiveEdit(MacroAssembler* masm); |
| 907 |
| 908 // FrameDropper is a code replacement for a JavaScript frame with possibly |
| 909 // several frames above. |
| 910 // There is no calling conventions here, because it never actually gets |
| 911 // called, it only gets returned to. |
| 912 static void GenerateFrameDropperLiveEdit(MacroAssembler* masm); |
| 913 }; |
| 914 |
931 } } // namespace v8::internal | 915 } } // namespace v8::internal |
932 | 916 |
933 #endif // V8_DEBUG_H_ | 917 #endif // V8_DEBUG_H_ |
OLD | NEW |