| Index: src/debug.h
|
| diff --git a/src/debug.h b/src/debug.h
|
| index e0f3ea09770c9266021d51b8c59f72554b511cc6..06e60523fd3b9ddd2875fab810a2d6c7b44e2c36 100644
|
| --- a/src/debug.h
|
| +++ b/src/debug.h
|
| @@ -13,6 +13,7 @@
|
| #include "flags.h"
|
| #include "frames-inl.h"
|
| #include "hashmap.h"
|
| +#include "liveedit.h"
|
| #include "platform.h"
|
| #include "string-stream.h"
|
| #include "v8threads.h"
|
| @@ -24,7 +25,7 @@ namespace internal {
|
|
|
|
|
| // Forward declarations.
|
| -class EnterDebugger;
|
| +class DebugScope;
|
|
|
|
|
| // Step actions. NOTE: These values are in macros.py as well.
|
| @@ -149,10 +150,7 @@ class BreakLocationIterator {
|
| // the cache is the script id.
|
| class ScriptCache : private HashMap {
|
| public:
|
| - explicit ScriptCache(Isolate* isolate)
|
| - : HashMap(HashMap::PointersMatch),
|
| - isolate_(isolate),
|
| - collected_scripts_(10) {}
|
| + explicit ScriptCache(Isolate* isolate);
|
| virtual ~ScriptCache() { Clear(); }
|
|
|
| // Add script to the cache.
|
| @@ -202,413 +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:
|
| - bool Load();
|
| - void Unload();
|
| - bool IsLoaded() { return !debug_context_.is_null(); }
|
| - bool InDebugger() { return thread_local_.debugger_entry_ != NULL; }
|
| -
|
| - Object* Break(Arguments args);
|
| - 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);
|
| -
|
| - void PromiseHandlePrologue(Handle<JSFunction> promise_getter);
|
| - void PromiseHandleEpilogue();
|
| - // Returns a promise if it does not have a reject handler.
|
| - Handle<Object> GetPromiseForUncaughtException();
|
| -
|
| - 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 has_pending_interrupt() {
|
| - return thread_local_.has_pending_interrupt_;
|
| - }
|
| -
|
| - // Set specified interrupts as pending.
|
| - void set_has_pending_interrupt(bool value) {
|
| - thread_local_.has_pending_interrupt_ = value;
|
| - }
|
| -
|
| - // 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_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);
|
| - }
|
| -
|
| - static const int kEstimatedNofDebugInfoEntries = 16;
|
| - static const int kEstimatedNofBreakPointsInFunction = 16;
|
| -
|
| - // Passed to MakeWeak.
|
| - static void HandleWeakDebugInfo(
|
| - const v8::WeakCallbackData<v8::Value, 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();
|
| -
|
| - // Record function from which eval was called.
|
| - static void RecordEvalCaller(Handle<Script> script);
|
| -
|
| - // Garbage collection notifications.
|
| - void AfterGarbageCollection();
|
| -
|
| - // Code generator routines.
|
| - 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);
|
| -
|
| - // 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);
|
| -
|
| - // 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);
|
| -
|
| - 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);
|
| -
|
| - void EnsureFunctionHasDebugBreakSlots(Handle<JSFunction> function);
|
| - void RecompileAndRelocateSuspendedGenerators(
|
| - const List<Handle<JSGeneratorObject> > &suspended_generators);
|
| -
|
| - // 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_;
|
| -
|
| - class PromiseOnStack {
|
| - public:
|
| - 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_;
|
| - };
|
| -
|
| - // 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.
|
| - bool has_pending_interrupt_;
|
| -
|
| - // 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_;
|
| - void ThreadInit();
|
| -
|
| - Isolate* isolate_;
|
| -
|
| - friend class Isolate;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(Debug);
|
| -};
|
| -
|
| -
|
| -DECLARE_RUNTIME_FUNCTION(Debug_Break);
|
|
|
|
|
| // Message delivered to the message handler callback. This is either a debugger
|
| @@ -693,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();
|
| @@ -707,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 {
|
| @@ -728,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
|
| @@ -750,70 +338,202 @@ class LockingCommandMessageQueue BASE_EMBEDDED {
|
| };
|
|
|
|
|
| -class Debugger {
|
| +class PromiseOnStack {
|
| public:
|
| - 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);
|
|
|
| + // API facing.
|
| void SetEventListener(Handle<Object> callback, Handle<Object> data);
|
| void SetMessageHandler(v8::Debug::MessageHandler handler);
|
| -
|
| - // Add a debugger command to the command queue.
|
| void EnqueueCommandMessage(Vector<const uint16_t> command,
|
| v8::Debug::ClientData* client_data = NULL);
|
| -
|
| - // Check whether there are commands in the command queue.
|
| - bool HasCommands();
|
| -
|
| // 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);
|
| +
|
| + // Internal logic
|
| + bool Load();
|
| + void Break(Arguments args, JavaScriptFrame*);
|
| + void SetAfterBreakTarget(JavaScriptFrame* frame);
|
| +
|
| + // Scripts handling.
|
| + Handle<FixedArray> GetLoadedScripts();
|
| +
|
| + // 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; }
|
| +
|
| + // Purge all code objects that have no debug break slots.
|
| + void PrepareForBreakPoints();
|
| +
|
| + // 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);
|
| +
|
| + // This function is used in FunctionNameUsing* tests.
|
| + Object* FindSharedFunctionInfoInScript(Handle<Script> script, int position);
|
| +
|
| + // 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);
|
| +
|
| + static Handle<Object> GetSourceBreakLocations(
|
| + Handle<SharedFunctionInfo> shared,
|
| + BreakPositionAlignment position_aligment);
|
| +
|
| + // 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);
|
| +
|
| + // Promise handling.
|
| + void PromiseHandlePrologue(Handle<JSFunction> promise_getter);
|
| + void PromiseHandleEpilogue();
|
| +
|
| + // Support for LiveEdit
|
| + void FramesHaveBeenDropped(StackFrame::Id new_break_frame_id,
|
| + LiveEdit::FrameDropMode mode,
|
| + Object** restarter_frame_function_pointer);
|
| +
|
| + // Passed to MakeWeak.
|
| + static void HandleWeakDebugInfo(
|
| + const v8::WeakCallbackData<v8::Value, void>& data);
|
|
|
| - bool ignore_debugger() const { return ignore_debugger_; }
|
| + // Threading support.
|
| + char* ArchiveDebug(char* to);
|
| + char* RestoreDebug(char* from);
|
| + static int ArchiveSpacePerThread();
|
| + void FreeThreadResources() { }
|
| +
|
| + // Record function from which eval was called.
|
| + static void RecordEvalCaller(Handle<Script> script);
|
| +
|
| + // 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_ ;
|
| }
|
|
|
| - bool is_active() { return is_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; }
|
|
|
| - class IgnoreScope {
|
| - public:
|
| - explicit IgnoreScope(Debugger* debugger)
|
| - : debugger_(debugger),
|
| - old_state_(debugger_->ignore_debugger_) {
|
| - debugger_->ignore_debugger_ = true;
|
| - }
|
| -
|
| - ~IgnoreScope() {
|
| - debugger_->ignore_debugger_ = old_state_;
|
| - }
|
| -
|
| - private:
|
| - Debugger* debugger_;
|
| - bool old_state_;
|
| - DISALLOW_COPY_AND_ASSIGN(IgnoreScope);
|
| - };
|
| + 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);
|
| + }
|
| +
|
| + Address step_in_fp_addr() {
|
| + return reinterpret_cast<Address>(&thread_local_.step_into_fp_);
|
| + }
|
|
|
| private:
|
| - explicit Debugger(Isolate* isolate);
|
| - ~Debugger();
|
| + 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(
|
| - Vector<const char> constructor_name,
|
| + const char* constructor_name,
|
| int argc,
|
| Handle<Object> argv[]);
|
| MUST_USE_RESULT MaybeHandle<Object> MakeExecutionState();
|
| @@ -827,19 +547,16 @@ class Debugger {
|
| 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 UpdateState();
|
| -
|
| void ProcessDebugEvent(v8::DebugEvent event,
|
| Handle<JSObject> event_data,
|
| bool auto_continue);
|
| @@ -847,87 +564,210 @@ class Debugger {
|
| Handle<JSObject> exec_state,
|
| Handle<JSObject> event_data,
|
| bool auto_continue);
|
| -
|
| - // Invoke the message handler function.
|
| void InvokeMessageHandler(MessageImpl message);
|
|
|
| - inline bool EventActive() {
|
| - // Check whether the message handler was been cleared.
|
| - // TODO(yangguo): handle loading and unloading of the debugger differently.
|
| - // Currently argument event is not used.
|
| - return !ignore_debugger_ && is_active_;
|
| + 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());
|
| }
|
|
|
| - Handle<Object> event_listener_; // Global handle to listener.
|
| + void ThreadInit();
|
| +
|
| + // Global handles.
|
| + Handle<Context> debug_context_;
|
| + Handle<Object> event_listener_;
|
| Handle<Object> event_listener_data_;
|
| - bool is_active_;
|
| - bool ignore_debugger_; // Are we temporarily ignoring the debugger?
|
| - bool live_edit_enabled_; // Enable LiveEdit.
|
| +
|
| v8::Debug::MessageHandler message_handler_;
|
| - bool debugger_unload_pending_; // Was message handler cleared?
|
|
|
| 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 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_; }
|
| +// 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 there are any JavaScript frames on the stack.
|
| - inline bool HasJavaScriptFrames() { return has_js_frames_; }
|
| + // 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.
|
| - 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);
|
| + explicit DisableBreak(Debug* debug, bool disable_break)
|
| + : debug_(debug), old_state_(debug->break_disabled_) {
|
| + debug_->break_disabled_ = disable_break;
|
| }
|
| - ~DisableBreak() {
|
| - isolate_->debug()->set_disable_break(prev_disable_break_);
|
| + ~DisableBreak() { debug_->break_disabled_ = old_state_; }
|
| +
|
| + private:
|
| + Debug* debug_;
|
| + bool old_state_;
|
| + DISALLOW_COPY_AND_ASSIGN(DisableBreak);
|
| +};
|
| +
|
| +
|
| +class SuppressDebug BASE_EMBEDDED {
|
| + public:
|
| + explicit SuppressDebug(Debug* debug)
|
| + : debug_(debug), old_state_(debug->is_suppressed_) {
|
| + debug_->is_suppressed_ = true;
|
| }
|
| + ~SuppressDebug() { debug_->is_suppressed_ = 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(SuppressDebug);
|
| +};
|
| +
|
| +
|
| +// 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);
|
| +
|
| + // 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 // V8_DEBUG_H_
|
|
|