summaryrefslogtreecommitdiffstats
path: root/chromium/v8/src/debug.h
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/v8/src/debug.h')
-rw-r--r--chromium/v8/src/debug.h1039
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 &registers_[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_