diff options
Diffstat (limited to 'chromium/v8/src/debug.h')
-rw-r--r-- | chromium/v8/src/debug.h | 1039 |
1 files changed, 369 insertions, 670 deletions
diff --git a/chromium/v8/src/debug.h b/chromium/v8/src/debug.h index 8e71ea67052..7f9b1a2eb02 100644 --- a/chromium/v8/src/debug.h +++ b/chromium/v8/src/debug.h @@ -1,56 +1,31 @@ // Copyright 2012 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. #ifndef V8_DEBUG_H_ #define V8_DEBUG_H_ -#include "allocation.h" -#include "arguments.h" -#include "assembler.h" -#include "debug-agent.h" -#include "execution.h" -#include "factory.h" -#include "flags.h" -#include "frames-inl.h" -#include "hashmap.h" -#include "platform.h" -#include "platform/socket.h" -#include "string-stream.h" -#include "v8threads.h" - -#ifdef ENABLE_DEBUGGER_SUPPORT -#include "../include/v8-debug.h" +#include "src/allocation.h" +#include "src/arguments.h" +#include "src/assembler.h" +#include "src/execution.h" +#include "src/factory.h" +#include "src/flags.h" +#include "src/frames-inl.h" +#include "src/hashmap.h" +#include "src/liveedit.h" +#include "src/platform.h" +#include "src/string-stream.h" +#include "src/v8threads.h" + +#include "include/v8-debug.h" namespace v8 { namespace internal { // Forward declarations. -class EnterDebugger; +class DebugScope; // Step actions. NOTE: These values are in macros.py as well. @@ -175,8 +150,7 @@ class BreakLocationIterator { // the cache is the script id. class ScriptCache : private HashMap { public: - explicit ScriptCache(Isolate* isolate) - : HashMap(ScriptMatch), isolate_(isolate), collected_scripts_(10) {} + explicit ScriptCache(Isolate* isolate); virtual ~ScriptCache() { Clear(); } // Add script to the cache. @@ -194,16 +168,12 @@ class ScriptCache : private HashMap { return ComputeIntegerHash(key, v8::internal::kZeroHashSeed); } - // Scripts match if their keys (script id) match. - static bool ScriptMatch(void* key1, void* key2) { return key1 == key2; } - // Clear the cache releasing all the weak handles. void Clear(); // Weak handle callback for scripts in the cache. - static void HandleWeakScript(v8::Isolate* isolate, - v8::Persistent<v8::Value>* obj, - void* data); + static void HandleWeakScript( + const v8::WeakCallbackData<v8::Value, void>& data); Isolate* isolate_; // List used during GC to temporarily store id's of collected scripts. @@ -230,415 +200,6 @@ class DebugInfoListNode { DebugInfoListNode* next_; }; -// This class contains the debugger support. The main purpose is to handle -// setting break points in the code. -// -// This class controls the debug info for all functions which currently have -// active breakpoints in them. This debug info is held in the heap root object -// debug_info which is a FixedArray. Each entry in this list is of class -// DebugInfo. -class Debug { - public: - void SetUp(bool create_heap_objects); - bool Load(); - void Unload(); - bool IsLoaded() { return !debug_context_.is_null(); } - bool InDebugger() { return thread_local_.debugger_entry_ != NULL; } - void PreemptionWhileInDebugger(); - void Iterate(ObjectVisitor* v); - - Object* Break(Arguments args); - void SetBreakPoint(Handle<JSFunction> function, - Handle<Object> break_point_object, - int* source_position); - bool SetBreakPointForScript(Handle<Script> script, - Handle<Object> break_point_object, - int* source_position, - BreakPositionAlignment alignment); - void ClearBreakPoint(Handle<Object> break_point_object); - void ClearAllBreakPoints(); - void FloodWithOneShot(Handle<JSFunction> function); - void FloodBoundFunctionWithOneShot(Handle<JSFunction> function); - void FloodHandlerWithOneShot(); - void ChangeBreakOnException(ExceptionBreakType type, bool enable); - bool IsBreakOnException(ExceptionBreakType type); - void PrepareStep(StepAction step_action, - int step_count, - StackFrame::Id frame_id); - void ClearStepping(); - void ClearStepOut(); - bool IsStepping() { return thread_local_.step_count_ > 0; } - bool StepNextContinue(BreakLocationIterator* break_location_iterator, - JavaScriptFrame* frame); - static Handle<DebugInfo> GetDebugInfo(Handle<SharedFunctionInfo> shared); - static bool HasDebugInfo(Handle<SharedFunctionInfo> shared); - - void PrepareForBreakPoints(); - - // This function is used in FunctionNameUsing* tests. - Object* FindSharedFunctionInfoInScript(Handle<Script> script, int position); - - // Returns whether the operation succeeded. Compilation can only be triggered - // if a valid closure is passed as the second argument, otherwise the shared - // function needs to be compiled already. - bool EnsureDebugInfo(Handle<SharedFunctionInfo> shared, - Handle<JSFunction> function); - - // Returns true if the current stub call is patched to call the debugger. - static bool IsDebugBreak(Address addr); - // Returns true if the current return statement has been patched to be - // a debugger breakpoint. - static bool IsDebugBreakAtReturn(RelocInfo* rinfo); - - // Check whether a code stub with the specified major key is a possible break - // point location. - static bool IsSourceBreakStub(Code* code); - static bool IsBreakStub(Code* code); - - // Find the builtin to use for invoking the debug break - static Handle<Code> FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode); - - static Handle<Object> GetSourceBreakLocations( - Handle<SharedFunctionInfo> shared, - BreakPositionAlignment position_aligment); - - // Getter for the debug_context. - inline Handle<Context> debug_context() { return debug_context_; } - - // Check whether a global object is the debug global object. - bool IsDebugGlobal(GlobalObject* global); - - // Check whether this frame is just about to return. - bool IsBreakAtReturn(JavaScriptFrame* frame); - - // Fast check to see if any break points are active. - inline bool has_break_points() { return has_break_points_; } - - void NewBreak(StackFrame::Id break_frame_id); - void SetBreak(StackFrame::Id break_frame_id, int break_id); - StackFrame::Id break_frame_id() { - return thread_local_.break_frame_id_; - } - int break_id() { return thread_local_.break_id_; } - - bool StepInActive() { return thread_local_.step_into_fp_ != 0; } - void HandleStepIn(Handle<JSFunction> function, - Handle<Object> holder, - Address fp, - bool is_constructor); - Address step_in_fp() { return thread_local_.step_into_fp_; } - Address* step_in_fp_addr() { return &thread_local_.step_into_fp_; } - - bool StepOutActive() { return thread_local_.step_out_fp_ != 0; } - Address step_out_fp() { return thread_local_.step_out_fp_; } - - EnterDebugger* debugger_entry() { - return thread_local_.debugger_entry_; - } - void set_debugger_entry(EnterDebugger* entry) { - thread_local_.debugger_entry_ = entry; - } - - // Check whether any of the specified interrupts are pending. - bool is_interrupt_pending(InterruptFlag what) { - return (thread_local_.pending_interrupts_ & what) != 0; - } - - // Set specified interrupts as pending. - void set_interrupts_pending(InterruptFlag what) { - thread_local_.pending_interrupts_ |= what; - } - - // Clear specified interrupts from pending. - void clear_interrupt_pending(InterruptFlag what) { - thread_local_.pending_interrupts_ &= ~static_cast<int>(what); - } - - // Getter and setter for the disable break state. - bool disable_break() { return disable_break_; } - void set_disable_break(bool disable_break) { - disable_break_ = disable_break; - } - - // Getters for the current exception break state. - bool break_on_exception() { return break_on_exception_; } - bool break_on_uncaught_exception() { - return break_on_uncaught_exception_; - } - - enum AddressId { - k_after_break_target_address, - k_debug_break_return_address, - k_debug_break_slot_address, - k_restarter_frame_function_pointer - }; - - // Support for setting the address to jump to when returning from break point. - Address* after_break_target_address() { - return reinterpret_cast<Address*>(&thread_local_.after_break_target_); - } - Address* restarter_frame_function_pointer_address() { - Object*** address = &thread_local_.restarter_frame_function_pointer_; - return reinterpret_cast<Address*>(address); - } - - // Support for saving/restoring registers when handling debug break calls. - Object** register_address(int r) { - return ®isters_[r]; - } - - // Access to the debug break on return code. - Code* debug_break_return() { return debug_break_return_; } - Code** debug_break_return_address() { - return &debug_break_return_; - } - - // Access to the debug break in debug break slot code. - Code* debug_break_slot() { return debug_break_slot_; } - Code** debug_break_slot_address() { - return &debug_break_slot_; - } - - static const int kEstimatedNofDebugInfoEntries = 16; - static const int kEstimatedNofBreakPointsInFunction = 16; - - // Passed to MakeWeak. - static void HandleWeakDebugInfo(v8::Isolate* isolate, - v8::Persistent<v8::Value>* obj, - void* data); - - friend class Debugger; - friend Handle<FixedArray> GetDebuggedFunctions(); // In test-debug.cc - friend void CheckDebuggerUnloaded(bool check_functions); // In test-debug.cc - - // Threading support. - char* ArchiveDebug(char* to); - char* RestoreDebug(char* from); - static int ArchiveSpacePerThread(); - void FreeThreadResources() { } - - // Mirror cache handling. - void ClearMirrorCache(); - - // Script cache handling. - void CreateScriptCache(); - void DestroyScriptCache(); - void AddScriptToScriptCache(Handle<Script> script); - Handle<FixedArray> GetLoadedScripts(); - - // Garbage collection notifications. - void AfterGarbageCollection(); - - // Code generator routines. - static void GenerateSlot(MacroAssembler* masm); - static void GenerateLoadICDebugBreak(MacroAssembler* masm); - static void GenerateStoreICDebugBreak(MacroAssembler* masm); - static void GenerateKeyedLoadICDebugBreak(MacroAssembler* masm); - static void GenerateKeyedStoreICDebugBreak(MacroAssembler* masm); - static void GenerateCompareNilICDebugBreak(MacroAssembler* masm); - static void GenerateReturnDebugBreak(MacroAssembler* masm); - static void GenerateCallFunctionStubDebugBreak(MacroAssembler* masm); - static void GenerateCallFunctionStubRecordDebugBreak(MacroAssembler* masm); - static void GenerateCallConstructStubDebugBreak(MacroAssembler* masm); - static void GenerateCallConstructStubRecordDebugBreak(MacroAssembler* masm); - static void GenerateSlotDebugBreak(MacroAssembler* masm); - static void GeneratePlainReturnLiveEdit(MacroAssembler* masm); - - // FrameDropper is a code replacement for a JavaScript frame with possibly - // several frames above. - // There is no calling conventions here, because it never actually gets - // called, it only gets returned to. - static void GenerateFrameDropperLiveEdit(MacroAssembler* masm); - - // Called from stub-cache.cc. - static void GenerateCallICDebugBreak(MacroAssembler* masm); - - // Describes how exactly a frame has been dropped from stack. - enum FrameDropMode { - // No frame has been dropped. - FRAMES_UNTOUCHED, - // The top JS frame had been calling IC stub. IC stub mustn't be called now. - FRAME_DROPPED_IN_IC_CALL, - // The top JS frame had been calling debug break slot stub. Patch the - // address this stub jumps to in the end. - FRAME_DROPPED_IN_DEBUG_SLOT_CALL, - // The top JS frame had been calling some C++ function. The return address - // gets patched automatically. - FRAME_DROPPED_IN_DIRECT_CALL, - FRAME_DROPPED_IN_RETURN_CALL, - CURRENTLY_SET_MODE - }; - - void FramesHaveBeenDropped(StackFrame::Id new_break_frame_id, - FrameDropMode mode, - Object** restarter_frame_function_pointer); - - // Initializes an artificial stack frame. The data it contains is used for: - // a. successful work of frame dropper code which eventually gets control, - // b. being compatible with regular stack structure for various stack - // iterators. - // Returns address of stack allocated pointer to restarted function, - // the value that is called 'restarter_frame_function_pointer'. The value - // at this address (possibly updated by GC) may be used later when preparing - // 'step in' operation. - static Object** SetUpFrameDropperFrame(StackFrame* bottom_js_frame, - Handle<Code> code); - - static const int kFrameDropperFrameSize; - - // Architecture-specific constant. - static const bool kFrameDropperSupported; - - /** - * Defines layout of a stack frame that supports padding. This is a regular - * internal frame that has a flexible stack structure. LiveEdit can shift - * its lower part up the stack, taking up the 'padding' space when additional - * stack memory is required. - * Such frame is expected immediately above the topmost JavaScript frame. - * - * Stack Layout: - * --- Top - * LiveEdit routine frames - * --- - * C frames of debug handler - * --- - * ... - * --- - * An internal frame that has n padding words: - * - any number of words as needed by code -- upper part of frame - * - padding size: a Smi storing n -- current size of padding - * - padding: n words filled with kPaddingValue in form of Smi - * - 3 context/type words of a regular InternalFrame - * - fp - * --- - * Topmost JavaScript frame - * --- - * ... - * --- Bottom - */ - class FramePaddingLayout : public AllStatic { - public: - // Architecture-specific constant. - static const bool kIsSupported; - - // A size of frame base including fp. Padding words starts right above - // the base. - static const int kFrameBaseSize = 4; - - // A number of words that should be reserved on stack for the LiveEdit use. - // Normally equals 1. Stored on stack in form of Smi. - static const int kInitialSize; - // A value that padding words are filled with (in form of Smi). Going - // bottom-top, the first word not having this value is a counter word. - static const int kPaddingValue; - }; - - private: - explicit Debug(Isolate* isolate); - ~Debug(); - - static bool CompileDebuggerScript(Isolate* isolate, int index); - void ClearOneShot(); - void ActivateStepIn(StackFrame* frame); - void ClearStepIn(); - void ActivateStepOut(StackFrame* frame); - void ClearStepNext(); - // Returns whether the compile succeeded. - void RemoveDebugInfo(Handle<DebugInfo> debug_info); - void SetAfterBreakTarget(JavaScriptFrame* frame); - Handle<Object> CheckBreakPoints(Handle<Object> break_point); - bool CheckBreakPoint(Handle<Object> break_point_object); - - // Global handle to debug context where all the debugger JavaScript code is - // loaded. - Handle<Context> debug_context_; - - // Boolean state indicating whether any break points are set. - bool has_break_points_; - - // Cache of all scripts in the heap. - ScriptCache* script_cache_; - - // List of active debug info objects. - DebugInfoListNode* debug_info_list_; - - bool disable_break_; - bool break_on_exception_; - bool break_on_uncaught_exception_; - - // Per-thread data. - class ThreadLocal { - public: - // Counter for generating next break id. - int break_count_; - - // Current break id. - int break_id_; - - // Frame id for the frame of the current break. - StackFrame::Id break_frame_id_; - - // Step action for last step performed. - StepAction last_step_action_; - - // Source statement position from last step next action. - int last_statement_position_; - - // Number of steps left to perform before debug event. - int step_count_; - - // Frame pointer from last step next action. - Address last_fp_; - - // Number of queued steps left to perform before debug event. - int queued_step_count_; - - // Frame pointer for frame from which step in was performed. - Address step_into_fp_; - - // Frame pointer for the frame where debugger should be called when current - // step out action is completed. - Address step_out_fp_; - - // Storage location for jump when exiting debug break calls. - Address after_break_target_; - - // Stores the way how LiveEdit has patched the stack. It is used when - // debugger returns control back to user script. - FrameDropMode frame_drop_mode_; - - // Top debugger entry. - EnterDebugger* debugger_entry_; - - // Pending interrupts scheduled while debugging. - int pending_interrupts_; - - // When restarter frame is on stack, stores the address - // of the pointer to function being restarted. Otherwise (most of the time) - // stores NULL. This pointer is used with 'step in' implementation. - Object** restarter_frame_function_pointer_; - }; - - // Storage location for registers when handling debug break calls - JSCallerSavedBuffer registers_; - ThreadLocal thread_local_; - void ThreadInit(); - - // Code to call for handling debug break on return. - Code* debug_break_return_; - - // Code to call for handling debug break in debug break slots. - Code* debug_break_slot_; - - Isolate* isolate_; - - friend class Isolate; - - DISALLOW_COPY_AND_ASSIGN(Debug); -}; - - -DECLARE_RUNTIME_FUNCTION(Object*, Debug_Break); // Message delivered to the message handler callback. This is either a debugger @@ -723,7 +284,6 @@ class CommandMessage { static CommandMessage New(const Vector<uint16_t>& command, v8::Debug::ClientData* data); CommandMessage(); - ~CommandMessage(); // Deletes user data and disposes of the text. void Dispose(); @@ -737,6 +297,7 @@ class CommandMessage { v8::Debug::ClientData* client_data_; }; + // A Queue of CommandMessage objects. A thread-safe version is // LockingCommandMessageQueue, based on this class. class CommandMessageQueue BASE_EMBEDDED { @@ -758,9 +319,6 @@ class CommandMessageQueue BASE_EMBEDDED { }; -class MessageDispatchHelperThread; - - // LockingCommandMessageQueue is a thread-safe circular buffer of CommandMessage // messages. The message data is not managed by LockingCommandMessageQueue. // Pointers to the data are passed in and out. Implemented by adding a @@ -780,296 +338,437 @@ class LockingCommandMessageQueue BASE_EMBEDDED { }; -class Debugger { +class PromiseOnStack { public: - ~Debugger(); - - void DebugRequest(const uint16_t* json_request, int length); - - Handle<Object> MakeJSObject(Vector<const char> constructor_name, - int argc, - Handle<Object> argv[], - bool* caught_exception); - Handle<Object> MakeExecutionState(bool* caught_exception); - Handle<Object> MakeBreakEvent(Handle<Object> exec_state, - Handle<Object> break_points_hit, - bool* caught_exception); - Handle<Object> MakeExceptionEvent(Handle<Object> exec_state, - Handle<Object> exception, - bool uncaught, - bool* caught_exception); - Handle<Object> MakeNewFunctionEvent(Handle<Object> func, - bool* caught_exception); - Handle<Object> MakeCompileEvent(Handle<Script> script, - bool before, - bool* caught_exception); - Handle<Object> MakeScriptCollectedEvent(int id, - bool* caught_exception); - void OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue); - void OnException(Handle<Object> exception, bool uncaught); - void OnBeforeCompile(Handle<Script> script); + PromiseOnStack(Isolate* isolate, + PromiseOnStack* prev, + Handle<JSFunction> getter); + ~PromiseOnStack(); + StackHandler* handler() { return handler_; } + Handle<JSFunction> getter() { return getter_; } + PromiseOnStack* prev() { return prev_; } + private: + Isolate* isolate_; + StackHandler* handler_; + Handle<JSFunction> getter_; + PromiseOnStack* prev_; +}; + +// This class contains the debugger support. The main purpose is to handle +// setting break points in the code. +// +// This class controls the debug info for all functions which currently have +// active breakpoints in them. This debug info is held in the heap root object +// debug_info which is a FixedArray. Each entry in this list is of class +// DebugInfo. +class Debug { + public: enum AfterCompileFlags { NO_AFTER_COMPILE_FLAGS, SEND_WHEN_DEBUGGING }; + + // Debug event triggers. + void OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue); + void OnException(Handle<Object> exception, bool uncaught); + void OnBeforeCompile(Handle<Script> script); void OnAfterCompile(Handle<Script> script, AfterCompileFlags after_compile_flags); void OnScriptCollected(int id); - void ProcessDebugEvent(v8::DebugEvent event, - Handle<JSObject> event_data, - bool auto_continue); - void NotifyMessageHandler(v8::DebugEvent event, - Handle<JSObject> exec_state, - Handle<JSObject> event_data, - bool auto_continue); + + // API facing. void SetEventListener(Handle<Object> callback, Handle<Object> data); - void SetMessageHandler(v8::Debug::MessageHandler2 handler); - void SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler, - TimeDelta period); - void SetDebugMessageDispatchHandler( - v8::Debug::DebugMessageDispatchHandler handler, - bool provide_locker); - - // Invoke the message handler function. - void InvokeMessageHandler(MessageImpl message); + void SetMessageHandler(v8::Debug::MessageHandler handler); + void EnqueueCommandMessage(Vector<const uint16_t> command, + v8::Debug::ClientData* client_data = NULL); + // Enqueue a debugger command to the command queue for event listeners. + void EnqueueDebugCommand(v8::Debug::ClientData* client_data = NULL); + MUST_USE_RESULT MaybeHandle<Object> Call(Handle<JSFunction> fun, + Handle<Object> data); + Handle<Context> GetDebugContext(); + void HandleDebugBreak(); + void ProcessDebugMessages(bool debug_command_only); - // Add a debugger command to the command queue. - void ProcessCommand(Vector<const uint16_t> command, - v8::Debug::ClientData* client_data = NULL); + // Internal logic + bool Load(); + void Break(Arguments args, JavaScriptFrame*); + void SetAfterBreakTarget(JavaScriptFrame* frame); - // Check whether there are commands in the command queue. - bool HasCommands(); + // Scripts handling. + Handle<FixedArray> GetLoadedScripts(); - // Enqueue a debugger command to the command queue for event listeners. - void EnqueueDebugCommand(v8::Debug::ClientData* client_data = NULL); + // Break point handling. + bool SetBreakPoint(Handle<JSFunction> function, + Handle<Object> break_point_object, + int* source_position); + bool SetBreakPointForScript(Handle<Script> script, + Handle<Object> break_point_object, + int* source_position, + BreakPositionAlignment alignment); + void ClearBreakPoint(Handle<Object> break_point_object); + void ClearAllBreakPoints(); + void FloodWithOneShot(Handle<JSFunction> function); + void FloodBoundFunctionWithOneShot(Handle<JSFunction> function); + void FloodHandlerWithOneShot(); + void ChangeBreakOnException(ExceptionBreakType type, bool enable); + bool IsBreakOnException(ExceptionBreakType type); + + // Stepping handling. + void PrepareStep(StepAction step_action, + int step_count, + StackFrame::Id frame_id); + void ClearStepping(); + void ClearStepOut(); + bool IsStepping() { return thread_local_.step_count_ > 0; } + bool StepNextContinue(BreakLocationIterator* break_location_iterator, + JavaScriptFrame* frame); + bool StepInActive() { return thread_local_.step_into_fp_ != 0; } + void HandleStepIn(Handle<JSFunction> function, + Handle<Object> holder, + Address fp, + bool is_constructor); + bool StepOutActive() { return thread_local_.step_out_fp_ != 0; } - Handle<Object> Call(Handle<JSFunction> fun, - Handle<Object> data, - bool* pending_exception); + // Purge all code objects that have no debug break slots. + void PrepareForBreakPoints(); - // Start the debugger agent listening on the provided port. - bool StartAgent(const char* name, int port, - bool wait_for_connection = false); + // Returns whether the operation succeeded. Compilation can only be triggered + // if a valid closure is passed as the second argument, otherwise the shared + // function needs to be compiled already. + bool EnsureDebugInfo(Handle<SharedFunctionInfo> shared, + Handle<JSFunction> function); + static Handle<DebugInfo> GetDebugInfo(Handle<SharedFunctionInfo> shared); + static bool HasDebugInfo(Handle<SharedFunctionInfo> shared); - // Stop the debugger agent. - void StopAgent(); + // This function is used in FunctionNameUsing* tests. + Object* FindSharedFunctionInfoInScript(Handle<Script> script, int position); - // Blocks until the agent has started listening for connections - void WaitForAgent(); + // Returns true if the current stub call is patched to call the debugger. + static bool IsDebugBreak(Address addr); + // Returns true if the current return statement has been patched to be + // a debugger breakpoint. + static bool IsDebugBreakAtReturn(RelocInfo* rinfo); - void CallMessageDispatchHandler(); + static Handle<Object> GetSourceBreakLocations( + Handle<SharedFunctionInfo> shared, + BreakPositionAlignment position_aligment); - Handle<Context> GetDebugContext(); + // Check whether a global object is the debug global object. + bool IsDebugGlobal(GlobalObject* global); - // Unload the debugger if possible. Only called when no debugger is currently - // active. - void UnloadDebugger(); - friend void ForceUnloadDebugger(); // In test-debug.cc + // Check whether this frame is just about to return. + bool IsBreakAtReturn(JavaScriptFrame* frame); - inline bool EventActive(v8::DebugEvent event) { - LockGuard<RecursiveMutex> lock_guard(debugger_access_); + // Promise handling. + void PromiseHandlePrologue(Handle<JSFunction> promise_getter); + void PromiseHandleEpilogue(); - // Check whether the message handler was been cleared. - if (debugger_unload_pending_) { - if (isolate_->debug()->debugger_entry() == NULL) { - UnloadDebugger(); - } - } + // Support for LiveEdit + void FramesHaveBeenDropped(StackFrame::Id new_break_frame_id, + LiveEdit::FrameDropMode mode, + Object** restarter_frame_function_pointer); - if (((event == v8::BeforeCompile) || (event == v8::AfterCompile)) && - !FLAG_debug_compile_events) { - return false; + // Passed to MakeWeak. + static void HandleWeakDebugInfo( + const v8::WeakCallbackData<v8::Value, void>& data); - } else if ((event == v8::ScriptCollected) && - !FLAG_debug_script_collected_events) { - return false; - } + // Threading support. + char* ArchiveDebug(char* to); + char* RestoreDebug(char* from); + static int ArchiveSpacePerThread(); + void FreeThreadResources() { } - // Currently argument event is not used. - return !compiling_natives_ && Debugger::IsDebuggerActive(); - } + // Record function from which eval was called. + static void RecordEvalCaller(Handle<Script> script); - void set_compiling_natives(bool compiling_natives) { - compiling_natives_ = compiling_natives; - } - bool compiling_natives() const { return compiling_natives_; } - void set_loading_debugger(bool v) { is_loading_debugger_ = v; } - bool is_loading_debugger() const { return is_loading_debugger_; } + // Garbage collection notifications. + void AfterGarbageCollection(); + + // Flags and states. + DebugScope* debugger_entry() { return thread_local_.current_debug_scope_; } + inline Handle<Context> debug_context() { return debug_context_; } void set_live_edit_enabled(bool v) { live_edit_enabled_ = v; } bool live_edit_enabled() const { return FLAG_enable_liveedit && live_edit_enabled_ ; } - void set_force_debugger_active(bool force_debugger_active) { - force_debugger_active_ = force_debugger_active; + + inline bool is_active() const { return is_active_; } + inline bool is_loaded() const { return !debug_context_.is_null(); } + inline bool has_break_points() const { return has_break_points_; } + inline bool in_debug_scope() const { + return thread_local_.current_debug_scope_ != NULL; + } + void set_disable_break(bool v) { break_disabled_ = v; } + + StackFrame::Id break_frame_id() { return thread_local_.break_frame_id_; } + int break_id() { return thread_local_.break_id_; } + + // Support for embedding into generated code. + Address after_break_target_address() { + return reinterpret_cast<Address>(&after_break_target_); + } + + Address restarter_frame_function_pointer_address() { + Object*** address = &thread_local_.restarter_frame_function_pointer_; + return reinterpret_cast<Address>(address); } - bool force_debugger_active() const { return force_debugger_active_; } - bool IsDebuggerActive(); + Address step_in_fp_addr() { + return reinterpret_cast<Address>(&thread_local_.step_into_fp_); + } private: - explicit Debugger(Isolate* isolate); + explicit Debug(Isolate* isolate); + + void UpdateState(); + void Unload(); + void SetNextBreakId() { + thread_local_.break_id_ = ++thread_local_.break_count_; + } + + // Check whether there are commands in the command queue. + inline bool has_commands() const { return !command_queue_.IsEmpty(); } + inline bool ignore_events() const { return is_suppressed_ || !is_active_; } + + // Constructors for debug event objects. + MUST_USE_RESULT MaybeHandle<Object> MakeJSObject( + const char* constructor_name, + int argc, + Handle<Object> argv[]); + MUST_USE_RESULT MaybeHandle<Object> MakeExecutionState(); + MUST_USE_RESULT MaybeHandle<Object> MakeBreakEvent( + Handle<Object> break_points_hit); + MUST_USE_RESULT MaybeHandle<Object> MakeExceptionEvent( + Handle<Object> exception, + bool uncaught, + Handle<Object> promise); + MUST_USE_RESULT MaybeHandle<Object> MakeCompileEvent( + Handle<Script> script, bool before); + MUST_USE_RESULT MaybeHandle<Object> MakeScriptCollectedEvent(int id); + + // Mirror cache handling. + void ClearMirrorCache(); + + // Returns a promise if it does not have a reject handler. + Handle<Object> GetPromiseForUncaughtException(); void CallEventCallback(v8::DebugEvent event, Handle<Object> exec_state, Handle<Object> event_data, v8::Debug::ClientData* client_data); - void CallCEventCallback(v8::DebugEvent event, - Handle<Object> exec_state, - Handle<Object> event_data, - v8::Debug::ClientData* client_data); - void CallJSEventCallback(v8::DebugEvent event, - Handle<Object> exec_state, - Handle<Object> event_data); - void ListenersChanged(); - - RecursiveMutex* debugger_access_; // Mutex guarding debugger variables. - Handle<Object> event_listener_; // Global handle to listener. + void ProcessDebugEvent(v8::DebugEvent event, + Handle<JSObject> event_data, + bool auto_continue); + void NotifyMessageHandler(v8::DebugEvent event, + Handle<JSObject> exec_state, + Handle<JSObject> event_data, + bool auto_continue); + void InvokeMessageHandler(MessageImpl message); + + static bool CompileDebuggerScript(Isolate* isolate, int index); + void ClearOneShot(); + void ActivateStepIn(StackFrame* frame); + void ClearStepIn(); + void ActivateStepOut(StackFrame* frame); + void ClearStepNext(); + // Returns whether the compile succeeded. + void RemoveDebugInfo(Handle<DebugInfo> debug_info); + Handle<Object> CheckBreakPoints(Handle<Object> break_point); + bool CheckBreakPoint(Handle<Object> break_point_object); + + inline void AssertDebugContext() { + ASSERT(isolate_->context() == *debug_context()); + ASSERT(in_debug_scope()); + } + + void ThreadInit(); + + // Global handles. + Handle<Context> debug_context_; + Handle<Object> event_listener_; Handle<Object> event_listener_data_; - bool compiling_natives_; // Are we compiling natives? - bool is_loading_debugger_; // Are we loading the debugger? - bool live_edit_enabled_; // Enable LiveEdit. - bool never_unload_debugger_; // Can we unload the debugger? - bool force_debugger_active_; // Activate debugger without event listeners. - v8::Debug::MessageHandler2 message_handler_; - bool debugger_unload_pending_; // Was message handler cleared? - v8::Debug::HostDispatchHandler host_dispatch_handler_; - Mutex dispatch_handler_access_; // Mutex guarding dispatch handler. - v8::Debug::DebugMessageDispatchHandler debug_message_dispatch_handler_; - MessageDispatchHelperThread* message_dispatch_helper_thread_; - TimeDelta host_dispatch_period_; - - DebuggerAgent* agent_; + + v8::Debug::MessageHandler message_handler_; static const int kQueueInitialSize = 4; - LockingCommandMessageQueue command_queue_; Semaphore command_received_; // Signaled for each command received. + LockingCommandMessageQueue command_queue_; LockingCommandMessageQueue event_command_queue_; + bool is_active_; + bool is_suppressed_; + bool live_edit_enabled_; + bool has_break_points_; + bool break_disabled_; + bool break_on_exception_; + bool break_on_uncaught_exception_; + + ScriptCache* script_cache_; // Cache of all scripts in the heap. + DebugInfoListNode* debug_info_list_; // List of active debug info objects. + + // Storage location for jump when exiting debug break calls. + // Note that this address is not GC safe. It should be computed immediately + // before returning to the DebugBreakCallHelper. + Address after_break_target_; + + // Per-thread data. + class ThreadLocal { + public: + // Top debugger entry. + DebugScope* current_debug_scope_; + + // Counter for generating next break id. + int break_count_; + + // Current break id. + int break_id_; + + // Frame id for the frame of the current break. + StackFrame::Id break_frame_id_; + + // Step action for last step performed. + StepAction last_step_action_; + + // Source statement position from last step next action. + int last_statement_position_; + + // Number of steps left to perform before debug event. + int step_count_; + + // Frame pointer from last step next action. + Address last_fp_; + + // Number of queued steps left to perform before debug event. + int queued_step_count_; + + // Frame pointer for frame from which step in was performed. + Address step_into_fp_; + + // Frame pointer for the frame where debugger should be called when current + // step out action is completed. + Address step_out_fp_; + + // Stores the way how LiveEdit has patched the stack. It is used when + // debugger returns control back to user script. + LiveEdit::FrameDropMode frame_drop_mode_; + + // When restarter frame is on stack, stores the address + // of the pointer to function being restarted. Otherwise (most of the time) + // stores NULL. This pointer is used with 'step in' implementation. + Object** restarter_frame_function_pointer_; + + // When a promise is being resolved, we may want to trigger a debug event + // if we catch a throw. For this purpose we remember the try-catch + // handler address that would catch the exception. We also hold onto a + // closure that returns a promise if the exception is considered uncaught. + // Due to the possibility of reentry we use a linked list. + PromiseOnStack* promise_on_stack_; + }; + + // Storage location for registers when handling debug break calls + ThreadLocal thread_local_; + Isolate* isolate_; - friend class EnterDebugger; friend class Isolate; + friend class DebugScope; + friend class DisableBreak; + friend class LiveEdit; + friend class SuppressDebug; + + friend Handle<FixedArray> GetDebuggedFunctions(); // In test-debug.cc + friend void CheckDebuggerUnloaded(bool check_functions); // In test-debug.cc - DISALLOW_COPY_AND_ASSIGN(Debugger); + DISALLOW_COPY_AND_ASSIGN(Debug); }; -// This class is used for entering the debugger. Create an instance in the stack -// to enter the debugger. This will set the current break state, make sure the -// debugger is loaded and switch to the debugger context. If the debugger for -// some reason could not be entered FailedToEnter will return true. -class EnterDebugger BASE_EMBEDDED { - public: - explicit EnterDebugger(Isolate* isolate); - ~EnterDebugger(); +DECLARE_RUNTIME_FUNCTION(Debug_Break); - // Check whether the debugger could be entered. - inline bool FailedToEnter() { return load_failed_; } - // Check whether there are any JavaScript frames on the stack. - inline bool HasJavaScriptFrames() { return has_js_frames_; } +// This scope is used to load and enter the debug context and create a new +// break state. Leaving the scope will restore the previous state. +// On failure to load, FailedToEnter returns true. +class DebugScope BASE_EMBEDDED { + public: + explicit DebugScope(Debug* debug); + ~DebugScope(); + + // Check whether loading was successful. + inline bool failed() { return failed_; } // Get the active context from before entering the debugger. inline Handle<Context> GetContext() { return save_.context(); } private: - Isolate* isolate_; - EnterDebugger* prev_; // Previous debugger entry if entered recursively. - JavaScriptFrameIterator it_; - const bool has_js_frames_; // Were there any JavaScript frames? + Isolate* isolate() { return debug_->isolate_; } + + Debug* debug_; + DebugScope* prev_; // Previous scope if entered recursively. StackFrame::Id break_frame_id_; // Previous break frame id. - int break_id_; // Previous break id. - bool load_failed_; // Did the debugger fail to load? - SaveContext save_; // Saves previous context. + int break_id_; // Previous break id. + bool failed_; // Did the debug context fail to load? + SaveContext save_; // Saves previous context. }; // Stack allocated class for disabling break. class DisableBreak BASE_EMBEDDED { public: - explicit DisableBreak(Isolate* isolate, bool disable_break) - : isolate_(isolate) { - prev_disable_break_ = isolate_->debug()->disable_break(); - isolate_->debug()->set_disable_break(disable_break); - } - ~DisableBreak() { - isolate_->debug()->set_disable_break(prev_disable_break_); + explicit DisableBreak(Debug* debug, bool disable_break) + : debug_(debug), old_state_(debug->break_disabled_) { + debug_->break_disabled_ = disable_break; } + ~DisableBreak() { debug_->break_disabled_ = old_state_; } private: - Isolate* isolate_; - // The previous state of the disable break used to restore the value when this - // object is destructed. - bool prev_disable_break_; + Debug* debug_; + bool old_state_; + DISALLOW_COPY_AND_ASSIGN(DisableBreak); }; -// Debug_Address encapsulates the Address pointers used in generating debug -// code. -class Debug_Address { +class SuppressDebug BASE_EMBEDDED { public: - explicit Debug_Address(Debug::AddressId id) : id_(id) { } - - static Debug_Address AfterBreakTarget() { - return Debug_Address(Debug::k_after_break_target_address); - } - - static Debug_Address DebugBreakReturn() { - return Debug_Address(Debug::k_debug_break_return_address); - } - - static Debug_Address RestarterFrameFunctionPointer() { - return Debug_Address(Debug::k_restarter_frame_function_pointer); - } - - Address address(Isolate* isolate) const { - Debug* debug = isolate->debug(); - switch (id_) { - case Debug::k_after_break_target_address: - return reinterpret_cast<Address>(debug->after_break_target_address()); - case Debug::k_debug_break_return_address: - return reinterpret_cast<Address>(debug->debug_break_return_address()); - case Debug::k_debug_break_slot_address: - return reinterpret_cast<Address>(debug->debug_break_slot_address()); - case Debug::k_restarter_frame_function_pointer: - return reinterpret_cast<Address>( - debug->restarter_frame_function_pointer_address()); - default: - UNREACHABLE(); - return NULL; - } + explicit SuppressDebug(Debug* debug) + : debug_(debug), old_state_(debug->is_suppressed_) { + debug_->is_suppressed_ = true; } + ~SuppressDebug() { debug_->is_suppressed_ = old_state_; } private: - Debug::AddressId id_; + Debug* debug_; + bool old_state_; + DISALLOW_COPY_AND_ASSIGN(SuppressDebug); }; -// The optional thread that Debug Agent may use to temporary call V8 to process -// pending debug requests if debuggee is not running V8 at the moment. -// Techincally it does not call V8 itself, rather it asks embedding program -// to do this via v8::Debug::HostDispatchHandler -class MessageDispatchHelperThread: public Thread { - public: - explicit MessageDispatchHelperThread(Isolate* isolate); - ~MessageDispatchHelperThread() {} - - void Schedule(); - private: - void Run(); - - Isolate* isolate_; - Semaphore sem_; - Mutex mutex_; - bool already_signalled_; +// Code generator routines. +class DebugCodegen : public AllStatic { + public: + static void GenerateSlot(MacroAssembler* masm); + static void GenerateCallICStubDebugBreak(MacroAssembler* masm); + static void GenerateLoadICDebugBreak(MacroAssembler* masm); + static void GenerateStoreICDebugBreak(MacroAssembler* masm); + static void GenerateKeyedLoadICDebugBreak(MacroAssembler* masm); + static void GenerateKeyedStoreICDebugBreak(MacroAssembler* masm); + static void GenerateCompareNilICDebugBreak(MacroAssembler* masm); + static void GenerateReturnDebugBreak(MacroAssembler* masm); + static void GenerateCallFunctionStubDebugBreak(MacroAssembler* masm); + static void GenerateCallConstructStubDebugBreak(MacroAssembler* masm); + static void GenerateCallConstructStubRecordDebugBreak(MacroAssembler* masm); + static void GenerateSlotDebugBreak(MacroAssembler* masm); + static void GeneratePlainReturnLiveEdit(MacroAssembler* masm); - DISALLOW_COPY_AND_ASSIGN(MessageDispatchHelperThread); + // FrameDropper is a code replacement for a JavaScript frame with possibly + // several frames above. + // There is no calling conventions here, because it never actually gets + // called, it only gets returned to. + static void GenerateFrameDropperLiveEdit(MacroAssembler* masm); }; } } // namespace v8::internal -#endif // ENABLE_DEBUGGER_SUPPORT - #endif // V8_DEBUG_H_ |