Index: src/debug.cc |
diff --git a/src/debug.cc b/src/debug.cc |
index e3cbf326c8e533bd97702bc8285c92270d41522b..a994eb008511c44574ade6986d6463ea53f1c70e 100644 |
--- a/src/debug.cc |
+++ b/src/debug.cc |
@@ -45,10 +45,6 @@ Debug::Debug(Isolate* isolate) |
} |
-Debug::~Debug() { |
-} |
- |
- |
static v8::Handle<v8::Context> GetDebugEventContext(Isolate* isolate) { |
Handle<Context> context = isolate->debug()->debugger_entry()->GetContext(); |
// Isolate::context() may have been NULL when "script collected" event |
@@ -694,9 +690,7 @@ bool Debug::CompileDebuggerScript(Isolate* isolate, int index) { |
HandleScope scope(isolate); |
// Bail out if the index is invalid. |
- if (index == -1) { |
- return false; |
- } |
+ if (index == -1) return false; |
// Find source and name for the requested script. |
Handle<String> source_code = |
@@ -762,13 +756,11 @@ bool Debug::Load() { |
// Return if debugger is already loaded. |
if (IsLoaded()) return true; |
- Debugger* debugger = isolate_->debugger(); |
- |
// Bail out if we're already in the process of compiling the native |
// JavaScript source code for the debugger. |
- if (debugger->ignore_debugger()) return false; |
+ if (isolate_->debugger()->ignore_debugger()) return false; |
+ Debugger::IgnoreScope during_create(isolate_->debugger()); |
- Debugger::IgnoreScope during_load(debugger); |
// Disable breakpoints and interrupts while compiling and running the |
// debugger scripts including the context creation code. |
DisableBreak disable(isolate_, true); |
@@ -793,14 +785,13 @@ bool Debug::Load() { |
// Expose the builtins object in the debugger context. |
Handle<String> key = isolate_->factory()->InternalizeOneByteString( |
STATIC_ASCII_VECTOR("builtins")); |
- Handle<GlobalObject> global = Handle<GlobalObject>(context->global_object()); |
+ Handle<GlobalObject> global = |
+ Handle<GlobalObject>(context->global_object(), isolate_); |
+ Handle<JSBuiltinsObject> builtin = |
+ Handle<JSBuiltinsObject>(global->builtins(), isolate_); |
RETURN_ON_EXCEPTION_VALUE( |
isolate_, |
- JSReceiver::SetProperty(global, |
- key, |
- Handle<Object>(global->builtins(), isolate_), |
- NONE, |
- SLOPPY), |
+ JSReceiver::SetProperty(global, key, builtin, NONE, SLOPPY), |
false); |
// Compile the JavaScript for the debugger in the debugger context. |
@@ -812,32 +803,24 @@ bool Debug::Load() { |
caught_exception = caught_exception || |
!CompileDebuggerScript(isolate_, Natives::GetIndex("liveedit")); |
} |
- |
- // Make sure we mark the debugger as not loading before we might |
- // return. |
- |
// Check for caught exceptions. |
if (caught_exception) return false; |
- // Debugger loaded, create debugger context global handle. |
debug_context_ = Handle<Context>::cast( |
isolate_->global_handles()->Create(*context)); |
- |
return true; |
} |
void Debug::Unload() { |
// Return debugger is not loaded. |
- if (!IsLoaded()) { |
- return; |
- } |
+ if (!IsLoaded()) return; |
// Clear the script cache. |
DestroyScriptCache(); |
// Clear debugger context global handle. |
- GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_context_.location())); |
+ GlobalHandles::Destroy(Handle<Object>::cast(debug_context_).location()); |
debug_context_ = Handle<Context>(); |
} |
@@ -854,7 +837,7 @@ Object* Debug::Break(Arguments args) { |
JavaScriptFrame* frame = it.frame(); |
// Just continue if breaks are disabled or debugger cannot be loaded. |
- if (disable_break() || !Load()) { |
+ if (disable_break()) { |
SetAfterBreakTarget(frame); |
return heap->undefined_value(); |
} |
@@ -2629,9 +2612,7 @@ Debugger::Debugger(Isolate* isolate) |
is_active_(false), |
ignore_debugger_(false), |
live_edit_enabled_(true), |
- never_unload_debugger_(false), |
message_handler_(NULL), |
- debugger_unload_pending_(false), |
command_queue_(isolate->logger(), kQueueInitialSize), |
command_received_(0), |
event_command_queue_(isolate->logger(), kQueueInitialSize), |
@@ -2988,25 +2969,9 @@ void Debugger::CallJSEventCallback(v8::DebugEvent event, |
Handle<Context> Debugger::GetDebugContext() { |
- never_unload_debugger_ = true; |
EnterDebugger debugger(isolate_); |
- return isolate_->debug()->debug_context(); |
-} |
- |
- |
-void Debugger::UnloadDebugger() { |
- Debug* debug = isolate_->debug(); |
- |
- // Make sure that there are no breakpoints left. |
- debug->ClearAllBreakPoints(); |
- |
- // Unload the debugger if feasible. |
- if (!never_unload_debugger_) { |
- debug->Unload(); |
- } |
- |
- // Clear the flag indicating that the debugger should be unloaded. |
- debugger_unload_pending_ = false; |
+ // The global handle may be destroyed soon after. Return it reboxed. |
+ return handle(*isolate_->debug()->debug_context(), isolate_); |
} |
@@ -3014,10 +2979,8 @@ void Debugger::NotifyMessageHandler(v8::DebugEvent event, |
Handle<JSObject> exec_state, |
Handle<JSObject> event_data, |
bool auto_continue) { |
+ ASSERT(is_active_); |
HandleScope scope(isolate_); |
- |
- if (!isolate_->debug()->Load()) return; |
- |
// Process the individual events. |
bool sendEventMessage = false; |
switch (event) { |
@@ -3145,77 +3108,60 @@ void Debugger::NotifyMessageHandler(v8::DebugEvent event, |
void Debugger::SetEventListener(Handle<Object> callback, |
Handle<Object> data) { |
- HandleScope scope(isolate_); |
GlobalHandles* global_handles = isolate_->global_handles(); |
- // Clear the global handles for the event listener and the event listener data |
- // object. |
- if (!event_listener_.is_null()) { |
- GlobalHandles::Destroy( |
- reinterpret_cast<Object**>(event_listener_.location())); |
- event_listener_ = Handle<Object>(); |
- } |
- if (!event_listener_data_.is_null()) { |
- GlobalHandles::Destroy( |
- reinterpret_cast<Object**>(event_listener_data_.location())); |
- event_listener_data_ = Handle<Object>(); |
- } |
+ // Remove existing entry. |
+ GlobalHandles::Destroy(event_listener_.location()); |
+ event_listener_ = Handle<Object>(); |
+ GlobalHandles::Destroy(event_listener_data_.location()); |
+ event_listener_data_ = Handle<Object>(); |
- // If there is a new debug event listener register it together with its data |
- // object. |
+ // Set new entry. |
if (!callback->IsUndefined() && !callback->IsNull()) { |
- event_listener_ = Handle<Object>::cast( |
- global_handles->Create(*callback)); |
- if (data.is_null()) { |
- data = isolate_->factory()->undefined_value(); |
- } |
- event_listener_data_ = Handle<Object>::cast( |
- global_handles->Create(*data)); |
+ event_listener_ = global_handles->Create(*callback); |
+ if (data.is_null()) data = isolate_->factory()->undefined_value(); |
+ event_listener_data_ = global_handles->Create(*data); |
} |
- ListenersChanged(); |
+ UpdateState(); |
} |
void Debugger::SetMessageHandler(v8::Debug::MessageHandler handler) { |
- LockGuard<RecursiveMutex> with(&debugger_access_); |
- |
message_handler_ = handler; |
- ListenersChanged(); |
- if (handler == NULL) { |
+ UpdateState(); |
+ if (handler == NULL && isolate_->debug()->InDebugger()) { |
// Send an empty command to the debugger if in a break to make JavaScript |
// run again if the debugger is closed. |
- if (isolate_->debug()->InDebugger()) { |
- EnqueueCommandMessage(Vector<const uint16_t>::empty()); |
- } |
+ EnqueueCommandMessage(Vector<const uint16_t>::empty()); |
} |
} |
-void Debugger::ListenersChanged() { |
- LockGuard<RecursiveMutex> with(&debugger_access_); |
- is_active_ = message_handler_ != NULL || !event_listener_.is_null(); |
- if (is_active_) { |
- // Disable the compilation cache when the debugger is active. |
+void Debugger::UpdateState() { |
+ bool activate = message_handler_ != NULL || |
+ !event_listener_.is_null() || |
+ isolate_->debug()->InDebugger(); |
+ if (!is_active_ && activate) { |
+ // Note that the debug context could have already been loaded to |
+ // bootstrap test cases. |
isolate_->compilation_cache()->Disable(); |
- debugger_unload_pending_ = false; |
- } else { |
+ activate = isolate_->debug()->Load(); |
+ } else if (is_active_ && !activate) { |
isolate_->compilation_cache()->Enable(); |
- // Unload the debugger if event listener and message handler cleared. |
- // Schedule this for later, because we may be in non-V8 thread. |
- debugger_unload_pending_ = true; |
+ isolate_->debug()->ClearAllBreakPoints(); |
+ isolate_->debug()->Unload(); |
} |
+ is_active_ = activate; |
+ // At this point the debug context is loaded iff the debugger is active. |
+ ASSERT(isolate_->debug()->IsLoaded() == is_active_); |
} |
// Calls the registered debug message handler. This callback is part of the |
// public API. |
void Debugger::InvokeMessageHandler(MessageImpl message) { |
- LockGuard<RecursiveMutex> with(&debugger_access_); |
- |
- if (message_handler_ != NULL) { |
- message_handler_(message); |
- } |
+ if (message_handler_ != NULL) message_handler_(message); |
} |
@@ -3259,9 +3205,6 @@ void Debugger::EnqueueDebugCommand(v8::Debug::ClientData* client_data) { |
MaybeHandle<Object> Debugger::Call(Handle<JSFunction> fun, |
Handle<Object> data) { |
- // When calling functions in the debugger prevent it from beeing unloaded. |
- Debugger::never_unload_debugger_ = true; |
- |
// Enter the debugger. |
EnterDebugger debugger(isolate_); |
if (debugger.FailedToEnter()) { |
@@ -3288,10 +3231,9 @@ MaybeHandle<Object> Debugger::Call(Handle<JSFunction> fun, |
EnterDebugger::EnterDebugger(Isolate* isolate) |
: isolate_(isolate), |
prev_(isolate_->debug()->debugger_entry()), |
- it_(isolate_), |
- has_js_frames_(!it_.done()), |
save_(isolate_) { |
Debug* debug = isolate_->debug(); |
+ |
// Link recursive debugger entry. |
debug->set_debugger_entry(this); |
@@ -3301,25 +3243,24 @@ EnterDebugger::EnterDebugger(Isolate* isolate) |
// Create the new break info. If there is no JavaScript frames there is no |
// break frame id. |
- if (has_js_frames_) { |
- debug->NewBreak(it_.frame()->id()); |
- } else { |
- debug->NewBreak(StackFrame::NO_ID); |
- } |
+ JavaScriptFrameIterator it(isolate_); |
+ has_js_frames_ = !it.done(); |
+ debug->NewBreak(has_js_frames_ ? it.frame()->id() : StackFrame::NO_ID); |
+ isolate_->debugger()->UpdateState(); |
// Make sure that debugger is loaded and enter the debugger context. |
- load_failed_ = !debug->Load(); |
- if (!load_failed_) { |
- // NOTE the member variable save which saves the previous context before |
- // this change. |
- isolate_->set_context(*debug->debug_context()); |
- } |
+ // The previous context is kept in save_. |
+ load_failed_ = !debug->IsLoaded(); |
+ if (!load_failed_) isolate_->set_context(*debug->debug_context()); |
} |
EnterDebugger::~EnterDebugger() { |
Debug* debug = isolate_->debug(); |
+ // Leaving this debugger entry. |
+ debug->set_debugger_entry(prev_); |
+ |
// Restore to the previous break state. |
debug->SetBreak(break_frame_id_, break_id_); |
@@ -3351,15 +3292,9 @@ EnterDebugger::~EnterDebugger() { |
if (isolate_->debugger()->HasCommands()) { |
isolate_->stack_guard()->RequestDebugCommand(); |
} |
- |
- // If leaving the debugger with the debugger no longer active unload it. |
- if (!isolate_->debugger()->is_active()) { |
- isolate_->debugger()->UnloadDebugger(); |
- } |
} |
- // Leaving this debugger entry. |
- debug->set_debugger_entry(prev_); |
+ isolate_->debugger()->UpdateState(); |
} |