Improved code generation infrastructure by doing simple register allocation and constant folding and propagation.
Optimized regular expression matching by avoiding to create intermediate string arrays and by flattening nested array representations of RegExp data.
Traverse a few stack frames when recording profiler samples to include partial call graphs in the profiling output.
Added support for using OProfile to profile generated code.
Added remote debugging support to the D8 developer shell.
Optimized creation of nested literals like JSON objects.
Fixed a bug in garbage collecting unused maps and turned it on by default (--collect-maps).
Added support for running tests under Valgrind.
git-svn-id: http://v8.googlecode.com/svn/trunk@1495 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/debug.h b/src/debug.h
index 1d534d6..9f4e047 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -31,14 +31,21 @@
#include "../include/v8-debug.h"
#include "assembler.h"
#include "code-stubs.h"
+#include "debug-agent.h"
#include "execution.h"
#include "factory.h"
#include "platform.h"
#include "string-stream.h"
+#include "v8threads.h"
namespace v8 { namespace internal {
+
+// Forward declarations.
+class EnterDebugger;
+
+
// Step actions. NOTE: These values are in macros.py as well.
enum StepAction {
StepNone = -1, // Stepping not prepared.
@@ -165,7 +172,8 @@
static bool Load();
static void Unload();
static bool IsLoaded() { return !debug_context_.is_null(); }
- static bool InDebugger() { return Top::is_break(); }
+ static bool InDebugger() { return thread_local_.debugger_entry_ != NULL; }
+ static void PreemptionWhileInDebugger();
static void Iterate(ObjectVisitor* v);
static Object* Break(Arguments args);
@@ -210,6 +218,16 @@
// Fast check to see if any break points are active.
inline static bool has_break_points() { return has_break_points_; }
+ static void NewBreak(StackFrame::Id break_frame_id);
+ static void SetBreak(StackFrame::Id break_frame_id, int break_id);
+ static StackFrame::Id break_frame_id() {
+ return thread_local_.break_frame_id_;
+ }
+ static int break_id() { return thread_local_.break_id_; }
+
+
+
+
static bool StepInActive() { return thread_local_.step_into_fp_ != 0; }
static void HandleStepIn(Handle<JSFunction> function,
Address fp,
@@ -217,6 +235,20 @@
static Address step_in_fp() { return thread_local_.step_into_fp_; }
static Address* step_in_fp_addr() { return &thread_local_.step_into_fp_; }
+ static EnterDebugger* debugger_entry() {
+ return thread_local_.debugger_entry_;
+ }
+ static void set_debugger_entry(EnterDebugger* entry) {
+ thread_local_.debugger_entry_ = entry;
+ }
+
+ static bool preemption_pending() {
+ return thread_local_.preemption_pending_;
+ }
+ static void set_preemption_pending(bool preemption_pending) {
+ thread_local_.preemption_pending_ = preemption_pending;
+ }
+
// Getter and setter for the disable break state.
static bool disable_break() { return disable_break_; }
static void set_disable_break(bool disable_break) {
@@ -312,9 +344,18 @@
static bool break_on_exception_;
static bool break_on_uncaught_exception_;
- // Per-thread:
+ // 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_;
@@ -332,6 +373,12 @@
// Storage location for jump when exiting debug break calls.
Address after_break_target_;
+
+ // Top debugger entry.
+ EnterDebugger* debugger_entry_;
+
+ // Preemption happened while debugging.
+ bool preemption_pending_;
};
// Storage location for registers when handling debug break calls
@@ -391,6 +438,9 @@
Handle<Object> data,
bool* pending_exception);
+ // Start the debugger agent listening on the provided port.
+ static bool StartAgent(int port);
+
inline static bool EventActive(v8::DebugEvent event) {
// Currently argument event is not used.
return !Debugger::compiling_natives_ && Debugger::debugger_active_;
@@ -419,6 +469,8 @@
static v8::DebugHostDispatchHandler host_dispatch_handler_;
static void* host_dispatch_handler_data_;
+ static DebuggerAgent* agent_;
+
friend class DebugMessageThread;
};
@@ -513,17 +565,34 @@
// some reason could not be entered FailedToEnter will return true.
class EnterDebugger BASE_EMBEDDED {
public:
- EnterDebugger() : has_js_frames_(!it_.done()) {
+ EnterDebugger()
+ : prev_(Debug::debugger_entry()),
+ has_js_frames_(!it_.done()) {
+ ASSERT(!Debug::preemption_pending());
+
+ // Link recursive debugger entry.
+ Debug::set_debugger_entry(this);
+
+ // If a preemption is pending when first entering the debugger clear it as
+ // we don't want preemption happening while executing JavaScript in the
+ // debugger. When recursively entering the debugger the preemption flag
+ // cannot be set as this is disabled while in the debugger (see
+ // RuntimePreempt).
+ if (prev_ == NULL && StackGuard::IsPreempted()) {
+ StackGuard::Continue(PREEMPT);
+ }
+ ASSERT(!StackGuard::IsPreempted());
+
// Store the previous break id and frame id.
- break_id_ = Top::break_id();
- break_frame_id_ = Top::break_frame_id();
+ break_id_ = Debug::break_id();
+ break_frame_id_ = Debug::break_frame_id();
// Create the new break info. If there is no JavaScript frames there is no
// break frame id.
if (has_js_frames_) {
- Top::new_break(it_.frame()->id());
+ Debug::NewBreak(it_.frame()->id());
} else {
- Top::new_break(StackFrame::NO_ID);
+ Debug::NewBreak(StackFrame::NO_ID);
}
// Make sure that debugger is loaded and enter the debugger context.
@@ -537,7 +606,18 @@
~EnterDebugger() {
// Restore to the previous break state.
- Top::set_break(break_frame_id_, break_id_);
+ Debug::SetBreak(break_frame_id_, break_id_);
+
+ // Request preemption when leaving the last debugger entry and a preemption
+ // had been recorded while debugging. This is to avoid starvation in some
+ // debugging scenarios.
+ if (prev_ == NULL && Debug::preemption_pending()) {
+ StackGuard::Preempt();
+ Debug::set_preemption_pending(false);
+ }
+
+ // Leaving this debugger entry.
+ Debug::set_debugger_entry(prev_);
}
// Check whether the debugger could be entered.
@@ -547,6 +627,7 @@
inline bool HasJavaScriptFrames() { return has_js_frames_; }
private:
+ EnterDebugger* prev_; // Previous debugger entry if entered recursively.
JavaScriptFrameIterator it_;
const bool has_js_frames_; // Were there any JavaScript frames?
StackFrame::Id break_frame_id_; // Previous break frame id.