Simplify debugger state.
R=ulan@chromium.org Review URL: https://codereview.chromium.org/287873005 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21346 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
5cfca21295
commit
2d1a75d608
@ -2120,20 +2120,18 @@ bool Genesis::InstallSpecialObjects(Handle<Context> native_context) {
|
|||||||
|
|
||||||
// Expose the debug global object in global if a name for it is specified.
|
// Expose the debug global object in global if a name for it is specified.
|
||||||
if (FLAG_expose_debug_as != NULL && strlen(FLAG_expose_debug_as) != 0) {
|
if (FLAG_expose_debug_as != NULL && strlen(FLAG_expose_debug_as) != 0) {
|
||||||
Debug* debug = isolate->debug();
|
|
||||||
// If loading fails we just bail out without installing the
|
// If loading fails we just bail out without installing the
|
||||||
// debugger but without tanking the whole context.
|
// debugger but without tanking the whole context.
|
||||||
|
Debug* debug = isolate->debug();
|
||||||
if (!debug->Load()) return true;
|
if (!debug->Load()) return true;
|
||||||
|
Handle<Context> debug_context = debug->debug_context();
|
||||||
// Set the security token for the debugger context to the same as
|
// Set the security token for the debugger context to the same as
|
||||||
// the shell native context to allow calling between these (otherwise
|
// the shell native context to allow calling between these (otherwise
|
||||||
// exposing debug global object doesn't make much sense).
|
// exposing debug global object doesn't make much sense).
|
||||||
debug->debug_context()->set_security_token(
|
debug_context->set_security_token(native_context->security_token());
|
||||||
native_context->security_token());
|
|
||||||
|
|
||||||
Handle<String> debug_string =
|
Handle<String> debug_string =
|
||||||
factory->InternalizeUtf8String(FLAG_expose_debug_as);
|
factory->InternalizeUtf8String(FLAG_expose_debug_as);
|
||||||
Handle<Object> global_proxy(
|
Handle<Object> global_proxy(debug_context->global_proxy(), isolate);
|
||||||
debug->debug_context()->global_proxy(), isolate);
|
|
||||||
RETURN_ON_EXCEPTION_VALUE(
|
RETURN_ON_EXCEPTION_VALUE(
|
||||||
isolate,
|
isolate,
|
||||||
JSObject::SetLocalPropertyIgnoreAttributes(
|
JSObject::SetLocalPropertyIgnoreAttributes(
|
||||||
|
@ -753,11 +753,12 @@ void Shell::InstallUtilityScript(Isolate* isolate) {
|
|||||||
// Install the debugger object in the utility scope
|
// Install the debugger object in the utility scope
|
||||||
i::Debug* debug = reinterpret_cast<i::Isolate*>(isolate)->debug();
|
i::Debug* debug = reinterpret_cast<i::Isolate*>(isolate)->debug();
|
||||||
debug->Load();
|
debug->Load();
|
||||||
|
i::Handle<i::Context> debug_context = debug->debug_context();
|
||||||
i::Handle<i::JSObject> js_debug
|
i::Handle<i::JSObject> js_debug
|
||||||
= i::Handle<i::JSObject>(debug->debug_context()->global_object());
|
= i::Handle<i::JSObject>(debug_context->global_object());
|
||||||
utility_context->Global()->Set(String::NewFromUtf8(isolate, "$debug"),
|
utility_context->Global()->Set(String::NewFromUtf8(isolate, "$debug"),
|
||||||
Utils::ToLocal(js_debug));
|
Utils::ToLocal(js_debug));
|
||||||
debug->debug_context()->set_security_token(
|
debug_context->set_security_token(
|
||||||
reinterpret_cast<i::Isolate*>(isolate)->heap()->undefined_value());
|
reinterpret_cast<i::Isolate*>(isolate)->heap()->undefined_value());
|
||||||
|
|
||||||
// Run the d8 shell utility script in the utility context
|
// Run the d8 shell utility script in the utility context
|
||||||
|
170
src/debug.cc
170
src/debug.cc
@ -45,10 +45,6 @@ Debug::Debug(Isolate* isolate)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Debug::~Debug() {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static v8::Handle<v8::Context> GetDebugEventContext(Isolate* isolate) {
|
static v8::Handle<v8::Context> GetDebugEventContext(Isolate* isolate) {
|
||||||
Handle<Context> context = isolate->debug()->debugger_entry()->GetContext();
|
Handle<Context> context = isolate->debug()->debugger_entry()->GetContext();
|
||||||
// Isolate::context() may have been NULL when "script collected" event
|
// Isolate::context() may have been NULL when "script collected" event
|
||||||
@ -694,9 +690,7 @@ bool Debug::CompileDebuggerScript(Isolate* isolate, int index) {
|
|||||||
HandleScope scope(isolate);
|
HandleScope scope(isolate);
|
||||||
|
|
||||||
// Bail out if the index is invalid.
|
// Bail out if the index is invalid.
|
||||||
if (index == -1) {
|
if (index == -1) return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find source and name for the requested script.
|
// Find source and name for the requested script.
|
||||||
Handle<String> source_code =
|
Handle<String> source_code =
|
||||||
@ -762,13 +756,11 @@ bool Debug::Load() {
|
|||||||
// Return if debugger is already loaded.
|
// Return if debugger is already loaded.
|
||||||
if (IsLoaded()) return true;
|
if (IsLoaded()) return true;
|
||||||
|
|
||||||
Debugger* debugger = isolate_->debugger();
|
|
||||||
|
|
||||||
// Bail out if we're already in the process of compiling the native
|
// Bail out if we're already in the process of compiling the native
|
||||||
// JavaScript source code for the debugger.
|
// 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
|
// Disable breakpoints and interrupts while compiling and running the
|
||||||
// debugger scripts including the context creation code.
|
// debugger scripts including the context creation code.
|
||||||
DisableBreak disable(isolate_, true);
|
DisableBreak disable(isolate_, true);
|
||||||
@ -793,14 +785,13 @@ bool Debug::Load() {
|
|||||||
// Expose the builtins object in the debugger context.
|
// Expose the builtins object in the debugger context.
|
||||||
Handle<String> key = isolate_->factory()->InternalizeOneByteString(
|
Handle<String> key = isolate_->factory()->InternalizeOneByteString(
|
||||||
STATIC_ASCII_VECTOR("builtins"));
|
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(
|
RETURN_ON_EXCEPTION_VALUE(
|
||||||
isolate_,
|
isolate_,
|
||||||
JSReceiver::SetProperty(global,
|
JSReceiver::SetProperty(global, key, builtin, NONE, SLOPPY),
|
||||||
key,
|
|
||||||
Handle<Object>(global->builtins(), isolate_),
|
|
||||||
NONE,
|
|
||||||
SLOPPY),
|
|
||||||
false);
|
false);
|
||||||
|
|
||||||
// Compile the JavaScript for the debugger in the debugger context.
|
// Compile the JavaScript for the debugger in the debugger context.
|
||||||
@ -812,32 +803,24 @@ bool Debug::Load() {
|
|||||||
caught_exception = caught_exception ||
|
caught_exception = caught_exception ||
|
||||||
!CompileDebuggerScript(isolate_, Natives::GetIndex("liveedit"));
|
!CompileDebuggerScript(isolate_, Natives::GetIndex("liveedit"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we mark the debugger as not loading before we might
|
|
||||||
// return.
|
|
||||||
|
|
||||||
// Check for caught exceptions.
|
// Check for caught exceptions.
|
||||||
if (caught_exception) return false;
|
if (caught_exception) return false;
|
||||||
|
|
||||||
// Debugger loaded, create debugger context global handle.
|
|
||||||
debug_context_ = Handle<Context>::cast(
|
debug_context_ = Handle<Context>::cast(
|
||||||
isolate_->global_handles()->Create(*context));
|
isolate_->global_handles()->Create(*context));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Debug::Unload() {
|
void Debug::Unload() {
|
||||||
// Return debugger is not loaded.
|
// Return debugger is not loaded.
|
||||||
if (!IsLoaded()) {
|
if (!IsLoaded()) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear the script cache.
|
// Clear the script cache.
|
||||||
DestroyScriptCache();
|
DestroyScriptCache();
|
||||||
|
|
||||||
// Clear debugger context global handle.
|
// 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>();
|
debug_context_ = Handle<Context>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -854,7 +837,7 @@ Object* Debug::Break(Arguments args) {
|
|||||||
JavaScriptFrame* frame = it.frame();
|
JavaScriptFrame* frame = it.frame();
|
||||||
|
|
||||||
// Just continue if breaks are disabled or debugger cannot be loaded.
|
// Just continue if breaks are disabled or debugger cannot be loaded.
|
||||||
if (disable_break() || !Load()) {
|
if (disable_break()) {
|
||||||
SetAfterBreakTarget(frame);
|
SetAfterBreakTarget(frame);
|
||||||
return heap->undefined_value();
|
return heap->undefined_value();
|
||||||
}
|
}
|
||||||
@ -2629,9 +2612,7 @@ Debugger::Debugger(Isolate* isolate)
|
|||||||
is_active_(false),
|
is_active_(false),
|
||||||
ignore_debugger_(false),
|
ignore_debugger_(false),
|
||||||
live_edit_enabled_(true),
|
live_edit_enabled_(true),
|
||||||
never_unload_debugger_(false),
|
|
||||||
message_handler_(NULL),
|
message_handler_(NULL),
|
||||||
debugger_unload_pending_(false),
|
|
||||||
command_queue_(isolate->logger(), kQueueInitialSize),
|
command_queue_(isolate->logger(), kQueueInitialSize),
|
||||||
command_received_(0),
|
command_received_(0),
|
||||||
event_command_queue_(isolate->logger(), kQueueInitialSize),
|
event_command_queue_(isolate->logger(), kQueueInitialSize),
|
||||||
@ -2988,36 +2969,17 @@ void Debugger::CallJSEventCallback(v8::DebugEvent event,
|
|||||||
|
|
||||||
|
|
||||||
Handle<Context> Debugger::GetDebugContext() {
|
Handle<Context> Debugger::GetDebugContext() {
|
||||||
never_unload_debugger_ = true;
|
|
||||||
EnterDebugger debugger(isolate_);
|
EnterDebugger debugger(isolate_);
|
||||||
return isolate_->debug()->debug_context();
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Debugger::NotifyMessageHandler(v8::DebugEvent event,
|
void Debugger::NotifyMessageHandler(v8::DebugEvent event,
|
||||||
Handle<JSObject> exec_state,
|
Handle<JSObject> exec_state,
|
||||||
Handle<JSObject> event_data,
|
Handle<JSObject> event_data,
|
||||||
bool auto_continue) {
|
bool auto_continue) {
|
||||||
|
ASSERT(is_active_);
|
||||||
HandleScope scope(isolate_);
|
HandleScope scope(isolate_);
|
||||||
|
|
||||||
if (!isolate_->debug()->Load()) return;
|
|
||||||
|
|
||||||
// Process the individual events.
|
// Process the individual events.
|
||||||
bool sendEventMessage = false;
|
bool sendEventMessage = false;
|
||||||
switch (event) {
|
switch (event) {
|
||||||
@ -3145,77 +3107,60 @@ void Debugger::NotifyMessageHandler(v8::DebugEvent event,
|
|||||||
|
|
||||||
void Debugger::SetEventListener(Handle<Object> callback,
|
void Debugger::SetEventListener(Handle<Object> callback,
|
||||||
Handle<Object> data) {
|
Handle<Object> data) {
|
||||||
HandleScope scope(isolate_);
|
|
||||||
GlobalHandles* global_handles = isolate_->global_handles();
|
GlobalHandles* global_handles = isolate_->global_handles();
|
||||||
|
|
||||||
// Clear the global handles for the event listener and the event listener data
|
// Remove existing entry.
|
||||||
// object.
|
GlobalHandles::Destroy(event_listener_.location());
|
||||||
if (!event_listener_.is_null()) {
|
event_listener_ = Handle<Object>();
|
||||||
GlobalHandles::Destroy(
|
GlobalHandles::Destroy(event_listener_data_.location());
|
||||||
reinterpret_cast<Object**>(event_listener_.location()));
|
event_listener_data_ = Handle<Object>();
|
||||||
event_listener_ = Handle<Object>();
|
|
||||||
}
|
|
||||||
if (!event_listener_data_.is_null()) {
|
|
||||||
GlobalHandles::Destroy(
|
|
||||||
reinterpret_cast<Object**>(event_listener_data_.location()));
|
|
||||||
event_listener_data_ = Handle<Object>();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there is a new debug event listener register it together with its data
|
// Set new entry.
|
||||||
// object.
|
|
||||||
if (!callback->IsUndefined() && !callback->IsNull()) {
|
if (!callback->IsUndefined() && !callback->IsNull()) {
|
||||||
event_listener_ = Handle<Object>::cast(
|
event_listener_ = global_handles->Create(*callback);
|
||||||
global_handles->Create(*callback));
|
if (data.is_null()) data = isolate_->factory()->undefined_value();
|
||||||
if (data.is_null()) {
|
event_listener_data_ = global_handles->Create(*data);
|
||||||
data = isolate_->factory()->undefined_value();
|
|
||||||
}
|
|
||||||
event_listener_data_ = Handle<Object>::cast(
|
|
||||||
global_handles->Create(*data));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ListenersChanged();
|
UpdateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Debugger::SetMessageHandler(v8::Debug::MessageHandler handler) {
|
void Debugger::SetMessageHandler(v8::Debug::MessageHandler handler) {
|
||||||
LockGuard<RecursiveMutex> with(&debugger_access_);
|
|
||||||
|
|
||||||
message_handler_ = handler;
|
message_handler_ = handler;
|
||||||
ListenersChanged();
|
UpdateState();
|
||||||
if (handler == NULL) {
|
if (handler == NULL && isolate_->debug()->InDebugger()) {
|
||||||
// Send an empty command to the debugger if in a break to make JavaScript
|
// Send an empty command to the debugger if in a break to make JavaScript
|
||||||
// run again if the debugger is closed.
|
// 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() {
|
void Debugger::UpdateState() {
|
||||||
LockGuard<RecursiveMutex> with(&debugger_access_);
|
bool activate = message_handler_ != NULL ||
|
||||||
is_active_ = message_handler_ != NULL || !event_listener_.is_null();
|
!event_listener_.is_null() ||
|
||||||
if (is_active_) {
|
isolate_->debug()->InDebugger();
|
||||||
// Disable the compilation cache when the debugger is active.
|
if (!is_active_ && activate) {
|
||||||
|
// Note that the debug context could have already been loaded to
|
||||||
|
// bootstrap test cases.
|
||||||
isolate_->compilation_cache()->Disable();
|
isolate_->compilation_cache()->Disable();
|
||||||
debugger_unload_pending_ = false;
|
activate = isolate_->debug()->Load();
|
||||||
} else {
|
} else if (is_active_ && !activate) {
|
||||||
isolate_->compilation_cache()->Enable();
|
isolate_->compilation_cache()->Enable();
|
||||||
// Unload the debugger if event listener and message handler cleared.
|
isolate_->debug()->ClearAllBreakPoints();
|
||||||
// Schedule this for later, because we may be in non-V8 thread.
|
isolate_->debug()->Unload();
|
||||||
debugger_unload_pending_ = true;
|
|
||||||
}
|
}
|
||||||
|
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
|
// Calls the registered debug message handler. This callback is part of the
|
||||||
// public API.
|
// public API.
|
||||||
void Debugger::InvokeMessageHandler(MessageImpl message) {
|
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 +3204,6 @@ void Debugger::EnqueueDebugCommand(v8::Debug::ClientData* client_data) {
|
|||||||
|
|
||||||
MaybeHandle<Object> Debugger::Call(Handle<JSFunction> fun,
|
MaybeHandle<Object> Debugger::Call(Handle<JSFunction> fun,
|
||||||
Handle<Object> data) {
|
Handle<Object> data) {
|
||||||
// When calling functions in the debugger prevent it from beeing unloaded.
|
|
||||||
Debugger::never_unload_debugger_ = true;
|
|
||||||
|
|
||||||
// Enter the debugger.
|
// Enter the debugger.
|
||||||
EnterDebugger debugger(isolate_);
|
EnterDebugger debugger(isolate_);
|
||||||
if (debugger.FailedToEnter()) {
|
if (debugger.FailedToEnter()) {
|
||||||
@ -3288,10 +3230,9 @@ MaybeHandle<Object> Debugger::Call(Handle<JSFunction> fun,
|
|||||||
EnterDebugger::EnterDebugger(Isolate* isolate)
|
EnterDebugger::EnterDebugger(Isolate* isolate)
|
||||||
: isolate_(isolate),
|
: isolate_(isolate),
|
||||||
prev_(isolate_->debug()->debugger_entry()),
|
prev_(isolate_->debug()->debugger_entry()),
|
||||||
it_(isolate_),
|
|
||||||
has_js_frames_(!it_.done()),
|
|
||||||
save_(isolate_) {
|
save_(isolate_) {
|
||||||
Debug* debug = isolate_->debug();
|
Debug* debug = isolate_->debug();
|
||||||
|
|
||||||
// Link recursive debugger entry.
|
// Link recursive debugger entry.
|
||||||
debug->set_debugger_entry(this);
|
debug->set_debugger_entry(this);
|
||||||
|
|
||||||
@ -3301,25 +3242,24 @@ EnterDebugger::EnterDebugger(Isolate* isolate)
|
|||||||
|
|
||||||
// Create the new break info. If there is no JavaScript frames there is no
|
// Create the new break info. If there is no JavaScript frames there is no
|
||||||
// break frame id.
|
// break frame id.
|
||||||
if (has_js_frames_) {
|
JavaScriptFrameIterator it(isolate_);
|
||||||
debug->NewBreak(it_.frame()->id());
|
has_js_frames_ = !it.done();
|
||||||
} else {
|
debug->NewBreak(has_js_frames_ ? it.frame()->id() : StackFrame::NO_ID);
|
||||||
debug->NewBreak(StackFrame::NO_ID);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
isolate_->debugger()->UpdateState();
|
||||||
// Make sure that debugger is loaded and enter the debugger context.
|
// Make sure that debugger is loaded and enter the debugger context.
|
||||||
load_failed_ = !debug->Load();
|
// The previous context is kept in save_.
|
||||||
if (!load_failed_) {
|
load_failed_ = !debug->IsLoaded();
|
||||||
// NOTE the member variable save which saves the previous context before
|
if (!load_failed_) isolate_->set_context(*debug->debug_context());
|
||||||
// this change.
|
|
||||||
isolate_->set_context(*debug->debug_context());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
EnterDebugger::~EnterDebugger() {
|
EnterDebugger::~EnterDebugger() {
|
||||||
Debug* debug = isolate_->debug();
|
Debug* debug = isolate_->debug();
|
||||||
|
|
||||||
|
// Leaving this debugger entry.
|
||||||
|
debug->set_debugger_entry(prev_);
|
||||||
|
|
||||||
// Restore to the previous break state.
|
// Restore to the previous break state.
|
||||||
debug->SetBreak(break_frame_id_, break_id_);
|
debug->SetBreak(break_frame_id_, break_id_);
|
||||||
|
|
||||||
@ -3351,15 +3291,9 @@ EnterDebugger::~EnterDebugger() {
|
|||||||
if (isolate_->debugger()->HasCommands()) {
|
if (isolate_->debugger()->HasCommands()) {
|
||||||
isolate_->stack_guard()->RequestDebugCommand();
|
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.
|
isolate_->debugger()->UpdateState();
|
||||||
debug->set_debugger_entry(prev_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
91
src/debug.h
91
src/debug.h
@ -490,7 +490,6 @@ class Debug {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
explicit Debug(Isolate* isolate);
|
explicit Debug(Isolate* isolate);
|
||||||
~Debug();
|
|
||||||
|
|
||||||
static bool CompileDebuggerScript(Isolate* isolate, int index);
|
static bool CompileDebuggerScript(Isolate* isolate, int index);
|
||||||
void ClearOneShot();
|
void ClearOneShot();
|
||||||
@ -743,25 +742,6 @@ class LockingCommandMessageQueue BASE_EMBEDDED {
|
|||||||
|
|
||||||
class Debugger {
|
class Debugger {
|
||||||
public:
|
public:
|
||||||
~Debugger();
|
|
||||||
|
|
||||||
void DebugRequest(const uint16_t* json_request, int length);
|
|
||||||
|
|
||||||
MUST_USE_RESULT MaybeHandle<Object> MakeJSObject(
|
|
||||||
Vector<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);
|
|
||||||
|
|
||||||
void OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue);
|
void OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue);
|
||||||
void OnException(Handle<Object> exception, bool uncaught);
|
void OnException(Handle<Object> exception, bool uncaught);
|
||||||
void OnBeforeCompile(Handle<Script> script);
|
void OnBeforeCompile(Handle<Script> script);
|
||||||
@ -773,13 +753,7 @@ class Debugger {
|
|||||||
void OnAfterCompile(Handle<Script> script,
|
void OnAfterCompile(Handle<Script> script,
|
||||||
AfterCompileFlags after_compile_flags);
|
AfterCompileFlags after_compile_flags);
|
||||||
void OnScriptCollected(int id);
|
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);
|
|
||||||
void SetEventListener(Handle<Object> callback, Handle<Object> data);
|
void SetEventListener(Handle<Object> callback, Handle<Object> data);
|
||||||
void SetMessageHandler(v8::Debug::MessageHandler handler);
|
void SetMessageHandler(v8::Debug::MessageHandler handler);
|
||||||
|
|
||||||
@ -798,36 +772,13 @@ class Debugger {
|
|||||||
|
|
||||||
Handle<Context> GetDebugContext();
|
Handle<Context> GetDebugContext();
|
||||||
|
|
||||||
// Unload the debugger if possible. Only called when no debugger is currently
|
|
||||||
// active.
|
|
||||||
void UnloadDebugger();
|
|
||||||
friend void ForceUnloadDebugger(); // In test-debug.cc
|
|
||||||
|
|
||||||
inline bool EventActive() {
|
|
||||||
LockGuard<RecursiveMutex> lock_guard(&debugger_access_);
|
|
||||||
|
|
||||||
// Check whether the message handler was been cleared.
|
|
||||||
// TODO(yangguo): handle loading and unloading of the debugger differently.
|
|
||||||
if (debugger_unload_pending_) {
|
|
||||||
if (isolate_->debug()->debugger_entry() == NULL) {
|
|
||||||
UnloadDebugger();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Currently argument event is not used.
|
|
||||||
return !ignore_debugger_ && is_active_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ignore_debugger() const { return ignore_debugger_; }
|
bool ignore_debugger() const { return ignore_debugger_; }
|
||||||
void set_live_edit_enabled(bool v) { live_edit_enabled_ = v; }
|
void set_live_edit_enabled(bool v) { live_edit_enabled_ = v; }
|
||||||
bool live_edit_enabled() const {
|
bool live_edit_enabled() const {
|
||||||
return FLAG_enable_liveedit && live_edit_enabled_ ;
|
return FLAG_enable_liveedit && live_edit_enabled_ ;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_active() {
|
bool is_active() { return is_active_; }
|
||||||
LockGuard<RecursiveMutex> lock_guard(&debugger_access_);
|
|
||||||
return is_active_;
|
|
||||||
}
|
|
||||||
|
|
||||||
class IgnoreScope {
|
class IgnoreScope {
|
||||||
public:
|
public:
|
||||||
@ -849,6 +800,22 @@ class Debugger {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
explicit Debugger(Isolate* isolate);
|
explicit Debugger(Isolate* isolate);
|
||||||
|
~Debugger();
|
||||||
|
|
||||||
|
MUST_USE_RESULT MaybeHandle<Object> MakeJSObject(
|
||||||
|
Vector<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);
|
||||||
|
|
||||||
void CallEventCallback(v8::DebugEvent event,
|
void CallEventCallback(v8::DebugEvent event,
|
||||||
Handle<Object> exec_state,
|
Handle<Object> exec_state,
|
||||||
@ -861,18 +828,31 @@ class Debugger {
|
|||||||
void CallJSEventCallback(v8::DebugEvent event,
|
void CallJSEventCallback(v8::DebugEvent event,
|
||||||
Handle<Object> exec_state,
|
Handle<Object> exec_state,
|
||||||
Handle<Object> event_data);
|
Handle<Object> event_data);
|
||||||
void ListenersChanged();
|
void UpdateState();
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
// Invoke the message handler function.
|
// Invoke the message handler function.
|
||||||
void InvokeMessageHandler(MessageImpl message);
|
void InvokeMessageHandler(MessageImpl message);
|
||||||
|
|
||||||
RecursiveMutex debugger_access_; // Mutex guarding debugger variables.
|
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_;
|
||||||
|
}
|
||||||
|
|
||||||
Handle<Object> event_listener_; // Global handle to listener.
|
Handle<Object> event_listener_; // Global handle to listener.
|
||||||
Handle<Object> event_listener_data_;
|
Handle<Object> event_listener_data_;
|
||||||
bool is_active_;
|
bool is_active_;
|
||||||
bool ignore_debugger_; // Are we temporarily ignoring the debugger?
|
bool ignore_debugger_; // Are we temporarily ignoring the debugger?
|
||||||
bool live_edit_enabled_; // Enable LiveEdit.
|
bool live_edit_enabled_; // Enable LiveEdit.
|
||||||
bool never_unload_debugger_; // Can we unload the debugger?
|
|
||||||
v8::Debug::MessageHandler message_handler_;
|
v8::Debug::MessageHandler message_handler_;
|
||||||
bool debugger_unload_pending_; // Was message handler cleared?
|
bool debugger_unload_pending_; // Was message handler cleared?
|
||||||
|
|
||||||
@ -911,8 +891,7 @@ class EnterDebugger BASE_EMBEDDED {
|
|||||||
private:
|
private:
|
||||||
Isolate* isolate_;
|
Isolate* isolate_;
|
||||||
EnterDebugger* prev_; // Previous debugger entry if entered recursively.
|
EnterDebugger* prev_; // Previous debugger entry if entered recursively.
|
||||||
JavaScriptFrameIterator it_;
|
bool has_js_frames_; // Were there any JavaScript frames?
|
||||||
const bool has_js_frames_; // Were there any JavaScript frames?
|
|
||||||
StackFrame::Id break_frame_id_; // Previous break frame id.
|
StackFrame::Id break_frame_id_; // Previous break frame id.
|
||||||
int break_id_; // Previous break id.
|
int break_id_; // Previous break id.
|
||||||
bool load_failed_; // Did the debugger fail to load?
|
bool load_failed_; // Did the debugger fail to load?
|
||||||
|
@ -714,9 +714,6 @@ void Execution::DebugBreakHelper(Isolate* isolate) {
|
|||||||
|
|
||||||
void Execution::ProcessDebugMessages(Isolate* isolate,
|
void Execution::ProcessDebugMessages(Isolate* isolate,
|
||||||
bool debug_command_only) {
|
bool debug_command_only) {
|
||||||
// Assert that we are on the main thread of the isolate.
|
|
||||||
ASSERT(ThreadId::Current().Equals(isolate->thread_id()));
|
|
||||||
|
|
||||||
isolate->stack_guard()->ClearDebugCommand();
|
isolate->stack_guard()->ClearDebugCommand();
|
||||||
|
|
||||||
StackLimitCheck check(isolate);
|
StackLimitCheck check(isolate);
|
||||||
|
@ -1546,8 +1546,6 @@ void Isolate::Deinit() {
|
|||||||
if (state_ == INITIALIZED) {
|
if (state_ == INITIALIZED) {
|
||||||
TRACE_ISOLATE(deinit);
|
TRACE_ISOLATE(deinit);
|
||||||
|
|
||||||
debugger()->UnloadDebugger();
|
|
||||||
|
|
||||||
if (concurrent_recompilation_enabled()) {
|
if (concurrent_recompilation_enabled()) {
|
||||||
optimizing_compiler_thread_->Stop();
|
optimizing_compiler_thread_->Stop();
|
||||||
delete optimizing_compiler_thread_;
|
delete optimizing_compiler_thread_;
|
||||||
|
@ -11042,8 +11042,9 @@ RUNTIME_FUNCTION(Runtime_DebugIndexedInterceptorElementValue) {
|
|||||||
|
|
||||||
|
|
||||||
static bool CheckExecutionState(Isolate* isolate, int break_id) {
|
static bool CheckExecutionState(Isolate* isolate, int break_id) {
|
||||||
return (isolate->debug()->break_id() != 0 &&
|
return !isolate->debug()->debug_context().is_null() &&
|
||||||
break_id == isolate->debug()->break_id());
|
isolate->debug()->break_id() != 0 &&
|
||||||
|
isolate->debug()->break_id() == break_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -98,10 +98,11 @@ class DebugLocalContext {
|
|||||||
v8::internal::Isolate* isolate =
|
v8::internal::Isolate* isolate =
|
||||||
reinterpret_cast<v8::internal::Isolate*>(context_->GetIsolate());
|
reinterpret_cast<v8::internal::Isolate*>(context_->GetIsolate());
|
||||||
v8::internal::Factory* factory = isolate->factory();
|
v8::internal::Factory* factory = isolate->factory();
|
||||||
v8::internal::Debug* debug = isolate->debug();
|
|
||||||
// Expose the debug context global object in the global object for testing.
|
// Expose the debug context global object in the global object for testing.
|
||||||
debug->Load();
|
CHECK(isolate->debug()->Load());
|
||||||
debug->debug_context()->set_security_token(
|
Handle<v8::internal::Context> debug_context =
|
||||||
|
isolate->debug()->debug_context();
|
||||||
|
debug_context->set_security_token(
|
||||||
v8::Utils::OpenHandle(*context_)->security_token());
|
v8::Utils::OpenHandle(*context_)->security_token());
|
||||||
|
|
||||||
Handle<JSGlobalProxy> global(Handle<JSGlobalProxy>::cast(
|
Handle<JSGlobalProxy> global(Handle<JSGlobalProxy>::cast(
|
||||||
@ -109,7 +110,7 @@ class DebugLocalContext {
|
|||||||
Handle<v8::internal::String> debug_string =
|
Handle<v8::internal::String> debug_string =
|
||||||
factory->InternalizeOneByteString(STATIC_ASCII_VECTOR("debug"));
|
factory->InternalizeOneByteString(STATIC_ASCII_VECTOR("debug"));
|
||||||
v8::internal::Runtime::SetObjectProperty(isolate, global, debug_string,
|
v8::internal::Runtime::SetObjectProperty(isolate, global, debug_string,
|
||||||
Handle<Object>(debug->debug_context()->global_proxy(), isolate),
|
Handle<Object>(debug_context->global_proxy(), isolate),
|
||||||
DONT_ENUM,
|
DONT_ENUM,
|
||||||
::v8::internal::SLOPPY).Check();
|
::v8::internal::SLOPPY).Check();
|
||||||
}
|
}
|
||||||
@ -421,12 +422,6 @@ void CheckDebuggerUnloaded(bool check_functions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ForceUnloadDebugger() {
|
|
||||||
CcTest::i_isolate()->debugger()->never_unload_debugger_ = false;
|
|
||||||
CcTest::i_isolate()->debugger()->UnloadDebugger();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace v8::internal
|
} } // namespace v8::internal
|
||||||
|
|
||||||
|
|
||||||
@ -5500,13 +5495,12 @@ static void CheckDataParameter(
|
|||||||
v8::String::NewFromUtf8(args.GetIsolate(), "Test");
|
v8::String::NewFromUtf8(args.GetIsolate(), "Test");
|
||||||
CHECK(v8::Debug::Call(debugger_call_with_data, data)->IsString());
|
CHECK(v8::Debug::Call(debugger_call_with_data, data)->IsString());
|
||||||
|
|
||||||
CHECK(v8::Debug::Call(debugger_call_with_data).IsEmpty());
|
for (int i = 0; i < 3; i++) {
|
||||||
CHECK(v8::Debug::Call(debugger_call_with_data).IsEmpty());
|
v8::TryCatch catcher;
|
||||||
|
CHECK(v8::Debug::Call(debugger_call_with_data).IsEmpty());
|
||||||
v8::TryCatch catcher;
|
CHECK(catcher.HasCaught());
|
||||||
v8::Debug::Call(debugger_call_with_data);
|
CHECK(catcher.Exception()->IsString());
|
||||||
CHECK(catcher.HasCaught());
|
}
|
||||||
CHECK(catcher.Exception()->IsString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -6872,9 +6866,11 @@ TEST(CallingContextIsNotDebugContext) {
|
|||||||
|
|
||||||
TEST(DebugContextIsPreservedBetweenAccesses) {
|
TEST(DebugContextIsPreservedBetweenAccesses) {
|
||||||
v8::HandleScope scope(CcTest::isolate());
|
v8::HandleScope scope(CcTest::isolate());
|
||||||
|
v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
|
||||||
v8::Local<v8::Context> context1 = v8::Debug::GetDebugContext();
|
v8::Local<v8::Context> context1 = v8::Debug::GetDebugContext();
|
||||||
v8::Local<v8::Context> context2 = v8::Debug::GetDebugContext();
|
v8::Local<v8::Context> context2 = v8::Debug::GetDebugContext();
|
||||||
CHECK_EQ(*context1, *context2);
|
CHECK_EQ(*context1, *context2);
|
||||||
|
v8::Debug::SetDebugEventListener(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1888,7 +1888,7 @@ TEST(NoDebugObjectInSnapshot) {
|
|||||||
v8::HandleScope scope(env->GetIsolate());
|
v8::HandleScope scope(env->GetIsolate());
|
||||||
v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
|
v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
|
||||||
|
|
||||||
CcTest::i_isolate()->debug()->Load();
|
CHECK(CcTest::i_isolate()->debug()->Load());
|
||||||
CompileRun("foo = {};");
|
CompileRun("foo = {};");
|
||||||
const v8::HeapSnapshot* snapshot =
|
const v8::HeapSnapshot* snapshot =
|
||||||
heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
|
heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
|
||||||
|
@ -37,12 +37,13 @@ function TestCase(fun, frame_number) {
|
|||||||
var exception = false;
|
var exception = false;
|
||||||
var codeSnippet = undefined;
|
var codeSnippet = undefined;
|
||||||
var resultPositions = undefined;
|
var resultPositions = undefined;
|
||||||
|
var step = 0;
|
||||||
|
|
||||||
function listener(event, exec_state, event_data, data) {
|
function listener(event, exec_state, event_data, data) {
|
||||||
try {
|
try {
|
||||||
if (event == Debug.DebugEvent.Break ||
|
if (event == Debug.DebugEvent.Break ||
|
||||||
event == Debug.DebugEvent.Exception) {
|
event == Debug.DebugEvent.Exception) {
|
||||||
Debug.setListener(null);
|
if (step++ > 0) return;
|
||||||
assertHasLineMark(/pause/, exec_state.frame(0));
|
assertHasLineMark(/pause/, exec_state.frame(0));
|
||||||
assertHasLineMark(/positions/, exec_state.frame(frame_number));
|
assertHasLineMark(/positions/, exec_state.frame(frame_number));
|
||||||
var frame = exec_state.frame(frame_number);
|
var frame = exec_state.frame(frame_number);
|
||||||
|
Loading…
Reference in New Issue
Block a user