[debug] Revert debug API removal
Debugging API is still in use by Node. Revert "[debug] remove deprecated debug command message queue." This reverts commitabdbfc953d
. Revert "[debug] mark more unused debug API as deprecated." This reverts commitd5ada19ce7
. BUG=v8:5530 Review-Url: https://codereview.chromium.org/2537313005 Cr-Commit-Position: refs/heads/master@{#41427}
This commit is contained in:
parent
c2f526849b
commit
4292f32ed3
@ -16,9 +16,11 @@ namespace v8 {
|
||||
enum DebugEvent {
|
||||
Break = 1,
|
||||
Exception = 2,
|
||||
AfterCompile = 3,
|
||||
CompileError = 4,
|
||||
AsyncTaskEvent = 5,
|
||||
NewFunction = 3,
|
||||
BeforeCompile = 4,
|
||||
AfterCompile = 5,
|
||||
CompileError = 6,
|
||||
AsyncTaskEvent = 7,
|
||||
};
|
||||
|
||||
class V8_EXPORT Debug {
|
||||
@ -142,7 +144,7 @@ class V8_EXPORT Debug {
|
||||
*
|
||||
* \param message the debug message handler message object
|
||||
*
|
||||
* A MessageHandler does not take possession of the message data,
|
||||
* A MessageHandler2 does not take possession of the message data,
|
||||
* and must not rely on the data persisting after the handler returns.
|
||||
*/
|
||||
typedef void (*MessageHandler)(const Message& message);
|
||||
@ -164,8 +166,7 @@ class V8_EXPORT Debug {
|
||||
static void CancelDebugBreak(Isolate* isolate);
|
||||
|
||||
// Check if a debugger break is scheduled in the given isolate.
|
||||
V8_DEPRECATED("No longer supported",
|
||||
static bool CheckDebugBreak(Isolate* isolate));
|
||||
static bool CheckDebugBreak(Isolate* isolate);
|
||||
|
||||
// Message based interface. The message protocol is JSON.
|
||||
V8_DEPRECATED("No longer supported",
|
||||
@ -203,9 +204,8 @@ class V8_EXPORT Debug {
|
||||
/**
|
||||
* Returns a mirror object for the given object.
|
||||
*/
|
||||
V8_DEPRECATED("No longer supported",
|
||||
static MaybeLocal<Value> GetMirror(Local<Context> context,
|
||||
v8::Local<v8::Value> obj));
|
||||
static MaybeLocal<Value> GetMirror(Local<Context> context,
|
||||
v8::Local<v8::Value> obj);
|
||||
|
||||
/**
|
||||
* Makes V8 process all pending debug messages.
|
||||
@ -254,9 +254,7 @@ class V8_EXPORT Debug {
|
||||
* While in the debug context, this method returns the top-most non-debug
|
||||
* context, if it exists.
|
||||
*/
|
||||
V8_DEPRECATED(
|
||||
"No longer supported",
|
||||
static MaybeLocal<Context> GetDebuggedContext(Isolate* isolate));
|
||||
static MaybeLocal<Context> GetDebuggedContext(Isolate* isolate);
|
||||
|
||||
/**
|
||||
* Enable/disable LiveEdit functionality for the given Isolate
|
||||
|
39
src/api.cc
39
src/api.cc
@ -8734,7 +8734,9 @@ bool Debug::CheckDebugBreak(Isolate* isolate) {
|
||||
|
||||
void Debug::SetMessageHandler(Isolate* isolate,
|
||||
v8::Debug::MessageHandler handler) {
|
||||
UNIMPLEMENTED();
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
ENTER_V8(i_isolate);
|
||||
i_isolate->debug()->SetMessageHandler(handler);
|
||||
}
|
||||
|
||||
|
||||
@ -8742,7 +8744,9 @@ void Debug::SendCommand(Isolate* isolate,
|
||||
const uint16_t* command,
|
||||
int length,
|
||||
ClientData* client_data) {
|
||||
UNIMPLEMENTED();
|
||||
i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
internal_isolate->debug()->EnqueueCommandMessage(
|
||||
i::Vector<const uint16_t>(command, length), client_data);
|
||||
}
|
||||
|
||||
|
||||
@ -8767,11 +8771,28 @@ MaybeLocal<Value> Debug::Call(Local<Context> context,
|
||||
|
||||
MaybeLocal<Value> Debug::GetMirror(Local<Context> context,
|
||||
v8::Local<v8::Value> obj) {
|
||||
UNIMPLEMENTED();
|
||||
return MaybeLocal<Value>();
|
||||
PREPARE_FOR_EXECUTION(context, Debug, GetMirror, Value);
|
||||
i::Debug* isolate_debug = isolate->debug();
|
||||
has_pending_exception = !isolate_debug->Load();
|
||||
RETURN_ON_FAILED_EXECUTION(Value);
|
||||
i::Handle<i::JSObject> debug(isolate_debug->debug_context()->global_object());
|
||||
auto name = isolate->factory()->NewStringFromStaticChars("MakeMirror");
|
||||
auto fun_obj = i::JSReceiver::GetProperty(debug, name).ToHandleChecked();
|
||||
auto v8_fun = Utils::CallableToLocal(i::Handle<i::JSFunction>::cast(fun_obj));
|
||||
const int kArgc = 1;
|
||||
v8::Local<v8::Value> argv[kArgc] = {obj};
|
||||
Local<Value> result;
|
||||
has_pending_exception =
|
||||
!v8_fun->Call(context, Utils::ToLocal(debug), kArgc, argv)
|
||||
.ToLocal(&result);
|
||||
RETURN_ON_FAILED_EXECUTION(Value);
|
||||
RETURN_ESCAPED(result);
|
||||
}
|
||||
|
||||
void Debug::ProcessDebugMessages(Isolate* isolate) {
|
||||
reinterpret_cast<i::Isolate*>(isolate)->debug()->ProcessDebugMessages(true);
|
||||
}
|
||||
|
||||
void Debug::ProcessDebugMessages(Isolate* isolate) { UNIMPLEMENTED(); }
|
||||
|
||||
Local<Context> Debug::GetDebugContext(Isolate* isolate) {
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
@ -8781,8 +8802,12 @@ Local<Context> Debug::GetDebugContext(Isolate* isolate) {
|
||||
|
||||
|
||||
MaybeLocal<Context> Debug::GetDebuggedContext(Isolate* isolate) {
|
||||
UNIMPLEMENTED();
|
||||
return MaybeLocal<Context>();
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
ENTER_V8(i_isolate);
|
||||
if (!i_isolate->debug()->in_debug_scope()) return MaybeLocal<Context>();
|
||||
i::Handle<i::Object> calling = i_isolate->GetCallingNativeContext();
|
||||
if (calling.is_null()) return MaybeLocal<Context>();
|
||||
return Utils::ToLocal(i::Handle<i::Context>::cast(calling));
|
||||
}
|
||||
|
||||
void Debug::SetLiveEditEnabled(Isolate* isolate, bool enable) {
|
||||
|
@ -962,6 +962,8 @@ Handle<SharedFunctionInfo> CompileToplevel(CompilationInfo* info) {
|
||||
FixedArray* array = isolate->native_context()->embedder_data();
|
||||
script->set_context_data(array->get(v8::Context::kDebugIdIndex));
|
||||
|
||||
isolate->debug()->OnBeforeCompile(script);
|
||||
|
||||
Handle<SharedFunctionInfo> result;
|
||||
|
||||
{ VMState<COMPILER> state(info->isolate());
|
||||
|
@ -38,6 +38,9 @@ Debug::Debug(Isolate* isolate)
|
||||
: debug_context_(Handle<Context>()),
|
||||
event_listener_(Handle<Object>()),
|
||||
event_listener_data_(Handle<Object>()),
|
||||
message_handler_(NULL),
|
||||
command_received_(0),
|
||||
command_queue_(isolate->logger(), kQueueInitialSize),
|
||||
is_active_(false),
|
||||
is_suppressed_(false),
|
||||
live_edit_enabled_(true), // TODO(yangguo): set to false by default.
|
||||
@ -522,7 +525,7 @@ void Debug::Break(JavaScriptFrame* frame) {
|
||||
// Clear all current stepping setup.
|
||||
ClearStepping();
|
||||
// Notify the debug event listeners.
|
||||
OnDebugBreak(break_points_hit);
|
||||
OnDebugBreak(break_points_hit, false);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -566,7 +569,7 @@ void Debug::Break(JavaScriptFrame* frame) {
|
||||
|
||||
if (step_break) {
|
||||
// Notify the debug event listeners.
|
||||
OnDebugBreak(isolate_->factory()->undefined_value());
|
||||
OnDebugBreak(isolate_->factory()->undefined_value(), false);
|
||||
} else {
|
||||
// Re-prepare to continue.
|
||||
PrepareStep(step_action);
|
||||
@ -1744,11 +1747,11 @@ void Debug::OnException(Handle<Object> exception, Handle<Object> promise) {
|
||||
}
|
||||
|
||||
// Process debug event.
|
||||
ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data));
|
||||
ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data), false);
|
||||
// Return to continue execution from where the exception was thrown.
|
||||
}
|
||||
|
||||
void Debug::OnDebugBreak(Handle<Object> break_points_hit) {
|
||||
void Debug::OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue) {
|
||||
// The caller provided for DebugScope.
|
||||
AssertDebugContext();
|
||||
// Bail out if there is no listener for this event
|
||||
@ -1765,7 +1768,8 @@ void Debug::OnDebugBreak(Handle<Object> break_points_hit) {
|
||||
if (!MakeBreakEvent(break_points_hit).ToHandle(&event_data)) return;
|
||||
|
||||
// Process debug event.
|
||||
ProcessDebugEvent(v8::Break, Handle<JSObject>::cast(event_data));
|
||||
ProcessDebugEvent(v8::Break, Handle<JSObject>::cast(event_data),
|
||||
auto_continue);
|
||||
}
|
||||
|
||||
|
||||
@ -1773,6 +1777,9 @@ void Debug::OnCompileError(Handle<Script> script) {
|
||||
ProcessCompileEvent(v8::CompileError, script);
|
||||
}
|
||||
|
||||
void Debug::OnBeforeCompile(Handle<Script> script) {
|
||||
ProcessCompileEvent(v8::BeforeCompile, script);
|
||||
}
|
||||
|
||||
// Handle debugger actions when a new script is compiled.
|
||||
void Debug::OnAfterCompile(Handle<Script> script) {
|
||||
@ -1794,11 +1801,12 @@ void Debug::OnAsyncTaskEvent(Handle<String> type, Handle<Object> id,
|
||||
if (!MakeAsyncTaskEvent(type, id, name).ToHandle(&event_data)) return;
|
||||
|
||||
// Process debug event.
|
||||
ProcessDebugEvent(v8::AsyncTaskEvent, Handle<JSObject>::cast(event_data));
|
||||
ProcessDebugEvent(v8::AsyncTaskEvent, Handle<JSObject>::cast(event_data),
|
||||
true);
|
||||
}
|
||||
|
||||
void Debug::ProcessDebugEvent(v8::DebugEvent event,
|
||||
Handle<JSObject> event_data) {
|
||||
void Debug::ProcessDebugEvent(v8::DebugEvent event, Handle<JSObject> event_data,
|
||||
bool auto_continue) {
|
||||
HandleScope scope(isolate_);
|
||||
|
||||
// Create the execution state.
|
||||
@ -1806,8 +1814,15 @@ void Debug::ProcessDebugEvent(v8::DebugEvent event,
|
||||
// Bail out and don't call debugger if exception.
|
||||
if (!MakeExecutionState().ToHandle(&exec_state)) return;
|
||||
|
||||
// Notify registered debug event listener.
|
||||
if (!event_listener_.is_null()) {
|
||||
// First notify the message handler if any.
|
||||
if (message_handler_ != NULL) {
|
||||
NotifyMessageHandler(event, Handle<JSObject>::cast(exec_state), event_data,
|
||||
auto_continue);
|
||||
}
|
||||
// Notify registered debug event listener. This can be either a C or
|
||||
// a JavaScript function. Don't call event listener for v8::Break
|
||||
// here, if it's only a debug command -- they will be processed later.
|
||||
if ((event != v8::Break || !auto_continue) && !event_listener_.is_null()) {
|
||||
CallEventCallback(event, exec_state, event_data, NULL);
|
||||
}
|
||||
}
|
||||
@ -1859,6 +1874,7 @@ void Debug::ProcessCompileEvent(v8::DebugEvent event, Handle<Script> script) {
|
||||
}
|
||||
SuppressDebug while_processing(this);
|
||||
|
||||
bool in_nested_debug_scope = in_debug_scope();
|
||||
HandleScope scope(isolate_);
|
||||
DebugScope debug_scope(this);
|
||||
if (debug_scope.failed()) return;
|
||||
@ -1878,7 +1894,20 @@ void Debug::ProcessCompileEvent(v8::DebugEvent event, Handle<Script> script) {
|
||||
// Bail out and don't call debugger if exception.
|
||||
if (!MakeCompileEvent(script, event).ToHandle(&event_data)) return;
|
||||
|
||||
ProcessDebugEvent(event, Handle<JSObject>::cast(event_data));
|
||||
// Don't call NotifyMessageHandler if already in debug scope to avoid running
|
||||
// nested command loop.
|
||||
if (in_nested_debug_scope) {
|
||||
if (event_listener_.is_null()) return;
|
||||
// Create the execution state.
|
||||
Handle<Object> exec_state;
|
||||
// Bail out and don't call debugger if exception.
|
||||
if (!MakeExecutionState().ToHandle(&exec_state)) return;
|
||||
|
||||
CallEventCallback(event, exec_state, event_data, NULL);
|
||||
} else {
|
||||
// Process debug event.
|
||||
ProcessDebugEvent(event, Handle<JSObject>::cast(event_data), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1890,6 +1919,138 @@ Handle<Context> Debug::GetDebugContext() {
|
||||
return handle(*debug_context(), isolate_);
|
||||
}
|
||||
|
||||
void Debug::NotifyMessageHandler(v8::DebugEvent event,
|
||||
Handle<JSObject> exec_state,
|
||||
Handle<JSObject> event_data,
|
||||
bool auto_continue) {
|
||||
// Prevent other interrupts from triggering, for example API callbacks,
|
||||
// while dispatching message handler callbacks.
|
||||
PostponeInterruptsScope no_interrupts(isolate_);
|
||||
DCHECK(is_active_);
|
||||
HandleScope scope(isolate_);
|
||||
// Process the individual events.
|
||||
bool sendEventMessage = false;
|
||||
switch (event) {
|
||||
case v8::Break:
|
||||
sendEventMessage = !auto_continue;
|
||||
break;
|
||||
case v8::NewFunction:
|
||||
case v8::BeforeCompile:
|
||||
case v8::CompileError:
|
||||
case v8::AsyncTaskEvent:
|
||||
break;
|
||||
case v8::Exception:
|
||||
case v8::AfterCompile:
|
||||
sendEventMessage = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// The debug command interrupt flag might have been set when the command was
|
||||
// added. It should be enough to clear the flag only once while we are in the
|
||||
// debugger.
|
||||
DCHECK(in_debug_scope());
|
||||
isolate_->stack_guard()->ClearDebugCommand();
|
||||
|
||||
// Notify the debugger that a debug event has occurred unless auto continue is
|
||||
// active in which case no event is send.
|
||||
if (sendEventMessage) {
|
||||
MessageImpl message = MessageImpl::NewEvent(
|
||||
event, auto_continue, Handle<JSObject>::cast(exec_state),
|
||||
Handle<JSObject>::cast(event_data));
|
||||
InvokeMessageHandler(message);
|
||||
}
|
||||
|
||||
// If auto continue don't make the event cause a break, but process messages
|
||||
// in the queue if any. For script collected events don't even process
|
||||
// messages in the queue as the execution state might not be what is expected
|
||||
// by the client.
|
||||
if (auto_continue && !has_commands()) return;
|
||||
|
||||
// DebugCommandProcessor goes here.
|
||||
bool running = auto_continue;
|
||||
|
||||
Handle<Object> cmd_processor_ctor =
|
||||
JSReceiver::GetProperty(isolate_, exec_state, "debugCommandProcessor")
|
||||
.ToHandleChecked();
|
||||
Handle<Object> ctor_args[] = {isolate_->factory()->ToBoolean(running)};
|
||||
Handle<JSReceiver> cmd_processor = Handle<JSReceiver>::cast(
|
||||
Execution::Call(isolate_, cmd_processor_ctor, exec_state, 1, ctor_args)
|
||||
.ToHandleChecked());
|
||||
Handle<JSFunction> process_debug_request = Handle<JSFunction>::cast(
|
||||
JSReceiver::GetProperty(isolate_, cmd_processor, "processDebugRequest")
|
||||
.ToHandleChecked());
|
||||
Handle<Object> is_running =
|
||||
JSReceiver::GetProperty(isolate_, cmd_processor, "isRunning")
|
||||
.ToHandleChecked();
|
||||
|
||||
// Process requests from the debugger.
|
||||
do {
|
||||
// Wait for new command in the queue.
|
||||
command_received_.Wait();
|
||||
|
||||
// Get the command from the queue.
|
||||
CommandMessage command = command_queue_.Get();
|
||||
isolate_->logger()->DebugTag(
|
||||
"Got request from command queue, in interactive loop.");
|
||||
if (!is_active()) {
|
||||
// Delete command text and user data.
|
||||
command.Dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
Vector<const uc16> command_text(
|
||||
const_cast<const uc16*>(command.text().start()),
|
||||
command.text().length());
|
||||
Handle<String> request_text = isolate_->factory()
|
||||
->NewStringFromTwoByte(command_text)
|
||||
.ToHandleChecked();
|
||||
Handle<Object> request_args[] = {request_text};
|
||||
Handle<Object> answer_value;
|
||||
Handle<String> answer;
|
||||
MaybeHandle<Object> maybe_exception;
|
||||
MaybeHandle<Object> maybe_result =
|
||||
Execution::TryCall(isolate_, process_debug_request, cmd_processor, 1,
|
||||
request_args, &maybe_exception);
|
||||
|
||||
if (maybe_result.ToHandle(&answer_value)) {
|
||||
if (answer_value->IsUndefined(isolate_)) {
|
||||
answer = isolate_->factory()->empty_string();
|
||||
} else {
|
||||
answer = Handle<String>::cast(answer_value);
|
||||
}
|
||||
|
||||
// Log the JSON request/response.
|
||||
if (FLAG_trace_debug_json) {
|
||||
PrintF("%s\n", request_text->ToCString().get());
|
||||
PrintF("%s\n", answer->ToCString().get());
|
||||
}
|
||||
|
||||
Handle<Object> is_running_args[] = {answer};
|
||||
maybe_result = Execution::Call(isolate_, is_running, cmd_processor, 1,
|
||||
is_running_args);
|
||||
Handle<Object> result;
|
||||
if (!maybe_result.ToHandle(&result)) break;
|
||||
running = result->IsTrue(isolate_);
|
||||
} else {
|
||||
Handle<Object> exception;
|
||||
if (!maybe_exception.ToHandle(&exception)) break;
|
||||
Handle<Object> result;
|
||||
if (!Object::ToString(isolate_, exception).ToHandle(&result)) break;
|
||||
answer = Handle<String>::cast(result);
|
||||
}
|
||||
|
||||
// Return the result.
|
||||
MessageImpl message = MessageImpl::NewResponse(
|
||||
event, running, exec_state, event_data, answer, command.client_data());
|
||||
InvokeMessageHandler(message);
|
||||
command.Dispose();
|
||||
|
||||
// Return from debug event processing if either the VM is put into the
|
||||
// running state (through a continue command) or auto continue is active
|
||||
// and there are no more commands queued.
|
||||
} while (!running || has_commands());
|
||||
command_queue_.Clear();
|
||||
}
|
||||
|
||||
void Debug::SetEventListener(Handle<Object> callback,
|
||||
Handle<Object> data) {
|
||||
@ -1911,9 +2072,18 @@ void Debug::SetEventListener(Handle<Object> callback,
|
||||
UpdateState();
|
||||
}
|
||||
|
||||
void Debug::SetMessageHandler(v8::Debug::MessageHandler handler) {
|
||||
message_handler_ = handler;
|
||||
UpdateState();
|
||||
if (handler == NULL && in_debug_scope()) {
|
||||
// Send an empty command to the debugger if in a break to make JavaScript
|
||||
// run again if the debugger is closed.
|
||||
EnqueueCommandMessage(Vector<const uint16_t>::empty());
|
||||
}
|
||||
}
|
||||
|
||||
void Debug::UpdateState() {
|
||||
bool is_active = !event_listener_.is_null();
|
||||
bool is_active = message_handler_ != NULL || !event_listener_.is_null();
|
||||
if (is_active || in_debug_scope()) {
|
||||
// Note that the debug context could have already been loaded to
|
||||
// bootstrap test cases.
|
||||
@ -1926,6 +2096,30 @@ void Debug::UpdateState() {
|
||||
is_active_ = is_active;
|
||||
}
|
||||
|
||||
// Calls the registered debug message handler. This callback is part of the
|
||||
// public API.
|
||||
void Debug::InvokeMessageHandler(MessageImpl message) {
|
||||
if (message_handler_ != NULL) message_handler_(message);
|
||||
}
|
||||
|
||||
// Puts a command coming from the public API on the queue. Creates
|
||||
// a copy of the command string managed by the debugger. Up to this
|
||||
// point, the command data was managed by the API client. Called
|
||||
// by the API client thread.
|
||||
void Debug::EnqueueCommandMessage(Vector<const uint16_t> command,
|
||||
v8::Debug::ClientData* client_data) {
|
||||
// Need to cast away const.
|
||||
CommandMessage message = CommandMessage::New(
|
||||
Vector<uint16_t>(const_cast<uint16_t*>(command.start()),
|
||||
command.length()),
|
||||
client_data);
|
||||
isolate_->logger()->DebugTag("Put command on command_queue.");
|
||||
command_queue_.Put(message);
|
||||
command_received_.Signal();
|
||||
|
||||
// Set the debug command break flag to have the command processed.
|
||||
if (!in_debug_scope()) isolate_->stack_guard()->RequestDebugCommand();
|
||||
}
|
||||
|
||||
MaybeHandle<Object> Debug::Call(Handle<Object> fun, Handle<Object> data) {
|
||||
DebugScope debug_scope(this);
|
||||
@ -1973,17 +2167,31 @@ void Debug::HandleDebugBreak() {
|
||||
}
|
||||
}
|
||||
|
||||
// Collect the break state before clearing the flags.
|
||||
bool debug_command_only = isolate_->stack_guard()->CheckDebugCommand() &&
|
||||
!isolate_->stack_guard()->CheckDebugBreak();
|
||||
|
||||
isolate_->stack_guard()->ClearDebugBreak();
|
||||
|
||||
// Clear stepping to avoid duplicate breaks.
|
||||
ClearStepping();
|
||||
|
||||
ProcessDebugMessages(debug_command_only);
|
||||
}
|
||||
|
||||
void Debug::ProcessDebugMessages(bool debug_command_only) {
|
||||
isolate_->stack_guard()->ClearDebugCommand();
|
||||
|
||||
StackLimitCheck check(isolate_);
|
||||
if (check.HasOverflowed()) return;
|
||||
|
||||
HandleScope scope(isolate_);
|
||||
DebugScope debug_scope(this);
|
||||
if (debug_scope.failed()) return;
|
||||
|
||||
// Notify the debug event listeners.
|
||||
OnDebugBreak(isolate_->factory()->undefined_value());
|
||||
// Notify the debug event listeners. Indicate auto continue if the break was
|
||||
// a debug command break.
|
||||
OnDebugBreak(isolate_->factory()->undefined_value(), debug_command_only);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -2067,6 +2275,10 @@ DebugScope::~DebugScope() {
|
||||
// JavaScript. This can happen if the v8::Debug::Call is used in which
|
||||
// case the exception should end up in the calling code.
|
||||
if (!isolate()->has_pending_exception()) debug_->ClearMirrorCache();
|
||||
|
||||
// If there are commands in the queue when leaving the debugger request
|
||||
// that these commands are processed.
|
||||
if (debug_->has_commands()) isolate()->stack_guard()->RequestDebugCommand();
|
||||
}
|
||||
|
||||
// Leaving this debugger entry.
|
||||
@ -2081,6 +2293,104 @@ DebugScope::~DebugScope() {
|
||||
debug_->UpdateState();
|
||||
}
|
||||
|
||||
MessageImpl MessageImpl::NewEvent(DebugEvent event, bool running,
|
||||
Handle<JSObject> exec_state,
|
||||
Handle<JSObject> event_data) {
|
||||
MessageImpl message(true, event, running, exec_state, event_data,
|
||||
Handle<String>(), NULL);
|
||||
return message;
|
||||
}
|
||||
|
||||
MessageImpl MessageImpl::NewResponse(DebugEvent event, bool running,
|
||||
Handle<JSObject> exec_state,
|
||||
Handle<JSObject> event_data,
|
||||
Handle<String> response_json,
|
||||
v8::Debug::ClientData* client_data) {
|
||||
MessageImpl message(false, event, running, exec_state, event_data,
|
||||
response_json, client_data);
|
||||
return message;
|
||||
}
|
||||
|
||||
MessageImpl::MessageImpl(bool is_event, DebugEvent event, bool running,
|
||||
Handle<JSObject> exec_state,
|
||||
Handle<JSObject> event_data,
|
||||
Handle<String> response_json,
|
||||
v8::Debug::ClientData* client_data)
|
||||
: is_event_(is_event),
|
||||
event_(event),
|
||||
running_(running),
|
||||
exec_state_(exec_state),
|
||||
event_data_(event_data),
|
||||
response_json_(response_json),
|
||||
client_data_(client_data) {}
|
||||
|
||||
bool MessageImpl::IsEvent() const { return is_event_; }
|
||||
|
||||
bool MessageImpl::IsResponse() const { return !is_event_; }
|
||||
|
||||
DebugEvent MessageImpl::GetEvent() const { return event_; }
|
||||
|
||||
bool MessageImpl::WillStartRunning() const { return running_; }
|
||||
|
||||
v8::Local<v8::Object> MessageImpl::GetExecutionState() const {
|
||||
return v8::Utils::ToLocal(exec_state_);
|
||||
}
|
||||
|
||||
v8::Isolate* MessageImpl::GetIsolate() const {
|
||||
return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate());
|
||||
}
|
||||
|
||||
v8::Local<v8::Object> MessageImpl::GetEventData() const {
|
||||
return v8::Utils::ToLocal(event_data_);
|
||||
}
|
||||
|
||||
v8::Local<v8::String> MessageImpl::GetJSON() const {
|
||||
Isolate* isolate = event_data_->GetIsolate();
|
||||
v8::EscapableHandleScope scope(reinterpret_cast<v8::Isolate*>(isolate));
|
||||
|
||||
if (IsEvent()) {
|
||||
// Call toJSONProtocol on the debug event object.
|
||||
Handle<Object> fun =
|
||||
JSReceiver::GetProperty(isolate, event_data_, "toJSONProtocol")
|
||||
.ToHandleChecked();
|
||||
if (!fun->IsJSFunction()) {
|
||||
return v8::Local<v8::String>();
|
||||
}
|
||||
|
||||
MaybeHandle<Object> maybe_json =
|
||||
Execution::TryCall(isolate, fun, event_data_, 0, NULL);
|
||||
Handle<Object> json;
|
||||
if (!maybe_json.ToHandle(&json) || !json->IsString()) {
|
||||
return v8::Local<v8::String>();
|
||||
}
|
||||
return scope.Escape(v8::Utils::ToLocal(Handle<String>::cast(json)));
|
||||
} else {
|
||||
return v8::Utils::ToLocal(response_json_);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
v8::Local<v8::Context> GetDebugEventContext(Isolate* isolate) {
|
||||
Handle<Context> context = isolate->debug()->debugger_entry()->GetContext();
|
||||
// Isolate::context() may have been NULL when "script collected" event
|
||||
// occured.
|
||||
if (context.is_null()) return v8::Local<v8::Context>();
|
||||
Handle<Context> native_context(context->native_context());
|
||||
return v8::Utils::ToLocal(native_context);
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
v8::Local<v8::Context> MessageImpl::GetEventContext() const {
|
||||
Isolate* isolate = event_data_->GetIsolate();
|
||||
v8::Local<v8::Context> context = GetDebugEventContext(isolate);
|
||||
// Isolate::context() may be NULL when "script collected" event occurs.
|
||||
DCHECK(!context.IsEmpty());
|
||||
return context;
|
||||
}
|
||||
|
||||
v8::Debug::ClientData* MessageImpl::GetClientData() const {
|
||||
return client_data_;
|
||||
}
|
||||
|
||||
EventDetailsImpl::EventDetailsImpl(DebugEvent event,
|
||||
Handle<JSObject> exec_state,
|
||||
@ -2110,11 +2420,7 @@ v8::Local<v8::Object> EventDetailsImpl::GetEventData() const {
|
||||
|
||||
|
||||
v8::Local<v8::Context> EventDetailsImpl::GetEventContext() const {
|
||||
Handle<Context> context =
|
||||
exec_state_->GetIsolate()->debug()->debugger_entry()->GetContext();
|
||||
if (context.is_null()) return v8::Local<v8::Context>();
|
||||
Handle<Context> native_context(context->native_context());
|
||||
return v8::Utils::ToLocal(native_context);
|
||||
return GetDebugEventContext(exec_state_->GetIsolate());
|
||||
}
|
||||
|
||||
|
||||
@ -2131,5 +2437,87 @@ v8::Isolate* EventDetailsImpl::GetIsolate() const {
|
||||
return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate());
|
||||
}
|
||||
|
||||
CommandMessage::CommandMessage()
|
||||
: text_(Vector<uint16_t>::empty()), client_data_(NULL) {}
|
||||
|
||||
CommandMessage::CommandMessage(const Vector<uint16_t>& text,
|
||||
v8::Debug::ClientData* data)
|
||||
: text_(text), client_data_(data) {}
|
||||
|
||||
void CommandMessage::Dispose() {
|
||||
text_.Dispose();
|
||||
delete client_data_;
|
||||
client_data_ = NULL;
|
||||
}
|
||||
|
||||
CommandMessage CommandMessage::New(const Vector<uint16_t>& command,
|
||||
v8::Debug::ClientData* data) {
|
||||
return CommandMessage(command.Clone(), data);
|
||||
}
|
||||
|
||||
CommandMessageQueue::CommandMessageQueue(int size)
|
||||
: start_(0), end_(0), size_(size) {
|
||||
messages_ = NewArray<CommandMessage>(size);
|
||||
}
|
||||
|
||||
CommandMessageQueue::~CommandMessageQueue() {
|
||||
while (!IsEmpty()) Get().Dispose();
|
||||
DeleteArray(messages_);
|
||||
}
|
||||
|
||||
CommandMessage CommandMessageQueue::Get() {
|
||||
DCHECK(!IsEmpty());
|
||||
int result = start_;
|
||||
start_ = (start_ + 1) % size_;
|
||||
return messages_[result];
|
||||
}
|
||||
|
||||
void CommandMessageQueue::Put(const CommandMessage& message) {
|
||||
if ((end_ + 1) % size_ == start_) {
|
||||
Expand();
|
||||
}
|
||||
messages_[end_] = message;
|
||||
end_ = (end_ + 1) % size_;
|
||||
}
|
||||
|
||||
void CommandMessageQueue::Expand() {
|
||||
CommandMessageQueue new_queue(size_ * 2);
|
||||
while (!IsEmpty()) {
|
||||
new_queue.Put(Get());
|
||||
}
|
||||
CommandMessage* array_to_free = messages_;
|
||||
*this = new_queue;
|
||||
new_queue.messages_ = array_to_free;
|
||||
// Make the new_queue empty so that it doesn't call Dispose on any messages.
|
||||
new_queue.start_ = new_queue.end_;
|
||||
// Automatic destructor called on new_queue, freeing array_to_free.
|
||||
}
|
||||
|
||||
LockingCommandMessageQueue::LockingCommandMessageQueue(Logger* logger, int size)
|
||||
: logger_(logger), queue_(size) {}
|
||||
|
||||
bool LockingCommandMessageQueue::IsEmpty() const {
|
||||
base::LockGuard<base::Mutex> lock_guard(&mutex_);
|
||||
return queue_.IsEmpty();
|
||||
}
|
||||
|
||||
CommandMessage LockingCommandMessageQueue::Get() {
|
||||
base::LockGuard<base::Mutex> lock_guard(&mutex_);
|
||||
CommandMessage result = queue_.Get();
|
||||
logger_->DebugEvent("Get", result.text());
|
||||
return result;
|
||||
}
|
||||
|
||||
void LockingCommandMessageQueue::Put(const CommandMessage& message) {
|
||||
base::LockGuard<base::Mutex> lock_guard(&mutex_);
|
||||
queue_.Put(message);
|
||||
logger_->DebugEvent("Put", message.text());
|
||||
}
|
||||
|
||||
void LockingCommandMessageQueue::Clear() {
|
||||
base::LockGuard<base::Mutex> lock_guard(&mutex_);
|
||||
queue_.Clear();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -240,6 +240,47 @@ class DebugInfoListNode {
|
||||
DebugInfoListNode* next_;
|
||||
};
|
||||
|
||||
// Message delivered to the message handler callback. This is either a debugger
|
||||
// event or the response to a command.
|
||||
class MessageImpl : public v8::Debug::Message {
|
||||
public:
|
||||
// Create a message object for a debug event.
|
||||
static MessageImpl NewEvent(DebugEvent event, bool running,
|
||||
Handle<JSObject> exec_state,
|
||||
Handle<JSObject> event_data);
|
||||
|
||||
// Create a message object for the response to a debug command.
|
||||
static MessageImpl NewResponse(DebugEvent event, bool running,
|
||||
Handle<JSObject> exec_state,
|
||||
Handle<JSObject> event_data,
|
||||
Handle<String> response_json,
|
||||
v8::Debug::ClientData* client_data);
|
||||
|
||||
// Implementation of interface v8::Debug::Message.
|
||||
virtual bool IsEvent() const;
|
||||
virtual bool IsResponse() const;
|
||||
virtual DebugEvent GetEvent() const;
|
||||
virtual bool WillStartRunning() const;
|
||||
virtual v8::Local<v8::Object> GetExecutionState() const;
|
||||
virtual v8::Local<v8::Object> GetEventData() const;
|
||||
virtual v8::Local<v8::String> GetJSON() const;
|
||||
virtual v8::Local<v8::Context> GetEventContext() const;
|
||||
virtual v8::Debug::ClientData* GetClientData() const;
|
||||
virtual v8::Isolate* GetIsolate() const;
|
||||
|
||||
private:
|
||||
MessageImpl(bool is_event, DebugEvent event, bool running,
|
||||
Handle<JSObject> exec_state, Handle<JSObject> event_data,
|
||||
Handle<String> response_json, v8::Debug::ClientData* client_data);
|
||||
|
||||
bool is_event_; // Does this message represent a debug event?
|
||||
DebugEvent event_; // Debug event causing the break.
|
||||
bool running_; // Will the VM start running after this event?
|
||||
Handle<JSObject> exec_state_; // Current execution state.
|
||||
Handle<JSObject> event_data_; // Data associated with the event.
|
||||
Handle<String> response_json_; // Response JSON if message holds a response.
|
||||
v8::Debug::ClientData* client_data_; // Client data passed with the request.
|
||||
};
|
||||
|
||||
// Details of the debug event delivered to the debug event listener.
|
||||
class EventDetailsImpl : public v8::DebugInterface::EventDetails {
|
||||
@ -266,6 +307,67 @@ class EventDetailsImpl : public v8::DebugInterface::EventDetails {
|
||||
v8::Debug::ClientData* client_data_; // Data passed to DebugBreakForCommand.
|
||||
};
|
||||
|
||||
// Message send by user to v8 debugger or debugger output message.
|
||||
// In addition to command text it may contain a pointer to some user data
|
||||
// which are expected to be passed along with the command reponse to message
|
||||
// handler.
|
||||
class CommandMessage {
|
||||
public:
|
||||
static CommandMessage New(const Vector<uint16_t>& command,
|
||||
v8::Debug::ClientData* data);
|
||||
CommandMessage();
|
||||
|
||||
// Deletes user data and disposes of the text.
|
||||
void Dispose();
|
||||
Vector<uint16_t> text() const { return text_; }
|
||||
v8::Debug::ClientData* client_data() const { return client_data_; }
|
||||
|
||||
private:
|
||||
CommandMessage(const Vector<uint16_t>& text, v8::Debug::ClientData* data);
|
||||
|
||||
Vector<uint16_t> text_;
|
||||
v8::Debug::ClientData* client_data_;
|
||||
};
|
||||
|
||||
// A Queue of CommandMessage objects. A thread-safe version is
|
||||
// LockingCommandMessageQueue, based on this class.
|
||||
class CommandMessageQueue BASE_EMBEDDED {
|
||||
public:
|
||||
explicit CommandMessageQueue(int size);
|
||||
~CommandMessageQueue();
|
||||
bool IsEmpty() const { return start_ == end_; }
|
||||
CommandMessage Get();
|
||||
void Put(const CommandMessage& message);
|
||||
void Clear() { start_ = end_ = 0; } // Queue is empty after Clear().
|
||||
|
||||
private:
|
||||
// Doubles the size of the message queue, and copies the messages.
|
||||
void Expand();
|
||||
|
||||
CommandMessage* messages_;
|
||||
int start_;
|
||||
int end_;
|
||||
int size_; // The size of the queue buffer. Queue can hold size-1 messages.
|
||||
};
|
||||
|
||||
// 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
|
||||
// Mutex to CommandMessageQueue. Includes logging of all puts and gets.
|
||||
class LockingCommandMessageQueue BASE_EMBEDDED {
|
||||
public:
|
||||
LockingCommandMessageQueue(Logger* logger, int size);
|
||||
bool IsEmpty() const;
|
||||
CommandMessage Get();
|
||||
void Put(const CommandMessage& message);
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
Logger* logger_;
|
||||
CommandMessageQueue queue_;
|
||||
mutable base::Mutex mutex_;
|
||||
DISALLOW_COPY_AND_ASSIGN(LockingCommandMessageQueue);
|
||||
};
|
||||
|
||||
class DebugFeatureTracker {
|
||||
public:
|
||||
@ -299,11 +401,12 @@ class DebugFeatureTracker {
|
||||
class Debug {
|
||||
public:
|
||||
// Debug event triggers.
|
||||
void OnDebugBreak(Handle<Object> break_points_hit);
|
||||
void OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue);
|
||||
|
||||
void OnThrow(Handle<Object> exception);
|
||||
void OnPromiseReject(Handle<Object> promise, Handle<Object> value);
|
||||
void OnCompileError(Handle<Script> script);
|
||||
void OnBeforeCompile(Handle<Script> script);
|
||||
void OnAfterCompile(Handle<Script> script);
|
||||
void OnAsyncTaskEvent(Handle<String> type, Handle<Object> id,
|
||||
Handle<String> name);
|
||||
@ -311,11 +414,13 @@ class Debug {
|
||||
// API facing.
|
||||
void SetEventListener(Handle<Object> callback, Handle<Object> data);
|
||||
void SetMessageHandler(v8::Debug::MessageHandler handler);
|
||||
void EnqueueCommandMessage(Vector<const uint16_t> command,
|
||||
v8::Debug::ClientData* client_data = NULL);
|
||||
MUST_USE_RESULT MaybeHandle<Object> Call(Handle<Object> fun,
|
||||
Handle<Object> data);
|
||||
Handle<Context> GetDebugContext();
|
||||
void HandleDebugBreak();
|
||||
void ProcessDebugMessages();
|
||||
void ProcessDebugMessages(bool debug_command_only);
|
||||
|
||||
// Internal logic
|
||||
bool Load();
|
||||
@ -454,6 +559,7 @@ class Debug {
|
||||
}
|
||||
|
||||
// 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_; }
|
||||
inline bool break_disabled() const {
|
||||
return break_disabled_ || in_debug_event_listener_;
|
||||
@ -491,7 +597,11 @@ class Debug {
|
||||
Handle<Object> event_data,
|
||||
v8::Debug::ClientData* client_data);
|
||||
void ProcessCompileEvent(v8::DebugEvent event, Handle<Script> script);
|
||||
void ProcessDebugEvent(v8::DebugEvent event, Handle<JSObject> event_data);
|
||||
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);
|
||||
|
||||
// Find the closest source position for a break point for a given position.
|
||||
int FindBreakablePosition(Handle<DebugInfo> debug_info, int source_position,
|
||||
@ -534,6 +644,10 @@ class Debug {
|
||||
|
||||
v8::Debug::MessageHandler message_handler_;
|
||||
|
||||
static const int kQueueInitialSize = 4;
|
||||
base::Semaphore command_received_; // Signaled for each command received.
|
||||
LockingCommandMessageQueue command_queue_;
|
||||
|
||||
bool is_active_;
|
||||
bool is_suppressed_;
|
||||
bool live_edit_enabled_;
|
||||
|
@ -43,9 +43,11 @@ var sourceLineBeginningSkip = /^(?:\s*(?:\/\*.*?\*\/)*)*/;
|
||||
// from the API include file debug.h.
|
||||
Debug.DebugEvent = { Break: 1,
|
||||
Exception: 2,
|
||||
AfterCompile: 3,
|
||||
CompileError: 4,
|
||||
AsyncTaskEvent: 5 };
|
||||
NewFunction: 3,
|
||||
BeforeCompile: 4,
|
||||
AfterCompile: 5,
|
||||
CompileError: 6,
|
||||
AsyncTaskEvent: 7 };
|
||||
|
||||
// Types of exceptions that can be broken upon.
|
||||
Debug.ExceptionBreak = { Caught : 0,
|
||||
|
@ -451,7 +451,7 @@ Object* StackGuard::HandleInterrupts() {
|
||||
isolate_->heap()->HandleGCRequest();
|
||||
}
|
||||
|
||||
if (CheckDebugBreak()) {
|
||||
if (CheckDebugBreak() || CheckDebugCommand()) {
|
||||
isolate_->debug()->HandleDebugBreak();
|
||||
}
|
||||
|
||||
|
@ -81,11 +81,12 @@ class StackGuard final {
|
||||
|
||||
#define INTERRUPT_LIST(V) \
|
||||
V(DEBUGBREAK, DebugBreak, 0) \
|
||||
V(TERMINATE_EXECUTION, TerminateExecution, 1) \
|
||||
V(GC_REQUEST, GC, 2) \
|
||||
V(INSTALL_CODE, InstallCode, 3) \
|
||||
V(API_INTERRUPT, ApiInterrupt, 4) \
|
||||
V(DEOPT_MARKED_ALLOCATION_SITES, DeoptMarkedAllocationSites, 5)
|
||||
V(DEBUGCOMMAND, DebugCommand, 1) \
|
||||
V(TERMINATE_EXECUTION, TerminateExecution, 2) \
|
||||
V(GC_REQUEST, GC, 3) \
|
||||
V(INSTALL_CODE, InstallCode, 4) \
|
||||
V(API_INTERRUPT, ApiInterrupt, 5) \
|
||||
V(DEOPT_MARKED_ALLOCATION_SITES, DeoptMarkedAllocationSites, 6)
|
||||
|
||||
#define V(NAME, Name, id) \
|
||||
inline bool Check##Name() { return CheckInterrupt(NAME); } \
|
||||
|
@ -559,7 +559,7 @@ void V8Debugger::handleV8DebugEvent(
|
||||
v8::DebugEvent event = eventDetails.GetEvent();
|
||||
if (event != v8::AsyncTaskEvent && event != v8::Break &&
|
||||
event != v8::Exception && event != v8::AfterCompile &&
|
||||
event != v8::CompileError)
|
||||
event != v8::BeforeCompile && event != v8::CompileError)
|
||||
return;
|
||||
|
||||
v8::Local<v8::Context> eventContext = eventDetails.GetEventContext();
|
||||
|
@ -4125,6 +4125,7 @@ TEST(DebugBreak) {
|
||||
|
||||
// Set the debug break flag.
|
||||
v8::Debug::DebugBreak(env->GetIsolate());
|
||||
CHECK(v8::Debug::CheckDebugBreak(env->GetIsolate()));
|
||||
|
||||
// Call all functions with different argument count.
|
||||
break_point_hit_count = 0;
|
||||
@ -4160,7 +4161,9 @@ TEST(DisableBreak) {
|
||||
|
||||
// Set, test and cancel debug break.
|
||||
v8::Debug::DebugBreak(env->GetIsolate());
|
||||
CHECK(v8::Debug::CheckDebugBreak(env->GetIsolate()));
|
||||
v8::Debug::CancelDebugBreak(env->GetIsolate());
|
||||
CHECK(!v8::Debug::CheckDebugBreak(env->GetIsolate()));
|
||||
|
||||
// Set the debug break flag.
|
||||
v8::Debug::DebugBreak(env->GetIsolate());
|
||||
@ -5259,7 +5262,7 @@ TEST(ContextData) {
|
||||
}
|
||||
|
||||
// Two times compile event and two times break event.
|
||||
CHECK_GT(event_listener_hit_count, 3);
|
||||
CHECK_GT(event_listener_hit_count, 4);
|
||||
|
||||
v8::Debug::SetDebugEventListener(isolate, nullptr);
|
||||
CheckDebuggerUnloaded(isolate);
|
||||
@ -5681,6 +5684,29 @@ TEST(NoDebugBreakInAfterCompileEventListener) {
|
||||
CheckDebuggerUnloaded(env->GetIsolate());
|
||||
}
|
||||
|
||||
TEST(GetMirror) {
|
||||
DebugLocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
v8::Local<v8::Context> context = env.context();
|
||||
v8::Local<v8::Value> obj =
|
||||
v8::Debug::GetMirror(context, v8_str(isolate, "hodja")).ToLocalChecked();
|
||||
v8::ScriptCompiler::Source source(
|
||||
v8_str("function runTest(mirror) {"
|
||||
" return mirror.isString() && (mirror.length() == 5);"
|
||||
"}"
|
||||
""
|
||||
"runTest;"));
|
||||
v8::Local<v8::Function> run_test = v8::Local<v8::Function>::Cast(
|
||||
v8::ScriptCompiler::CompileUnboundScript(isolate, &source)
|
||||
.ToLocalChecked()
|
||||
->BindToCurrentContext()
|
||||
->Run(context)
|
||||
.ToLocalChecked());
|
||||
v8::Local<v8::Value> result =
|
||||
run_test->Call(context, env->Global(), 1, &obj).ToLocalChecked();
|
||||
CHECK(result->IsTrue());
|
||||
}
|
||||
|
||||
// Test that the debug break flag works with function.apply.
|
||||
TEST(DebugBreakFunctionApply) {
|
||||
@ -5820,6 +5846,41 @@ TEST(NoDebugContextWhenDebuggerDisabled) {
|
||||
CHECK(context.IsEmpty());
|
||||
}
|
||||
|
||||
static void DebugEventCheckContext(
|
||||
const v8::Debug::EventDetails& event_details) {
|
||||
if (event_details.GetEvent() == v8::Break) {
|
||||
v8::Isolate* isolate = event_details.GetIsolate();
|
||||
CHECK(v8::Debug::GetDebuggedContext(isolate)
|
||||
.ToLocalChecked()
|
||||
->Global()
|
||||
->Equals(isolate->GetCurrentContext(),
|
||||
event_details.GetEventContext()->Global())
|
||||
.FromJust());
|
||||
}
|
||||
}
|
||||
|
||||
static void CheckContext(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
CHECK(v8::Debug::GetDebuggedContext(args.GetIsolate()).IsEmpty());
|
||||
}
|
||||
|
||||
TEST(DebuggedContext) {
|
||||
DebugLocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
|
||||
v8::Debug::SetDebugEventListener(isolate, DebugEventCheckContext);
|
||||
|
||||
v8::Local<v8::Function> foo =
|
||||
CompileFunction(&env, "function foo(){bar=0;}", "foo");
|
||||
|
||||
SetBreakPoint(foo, 0);
|
||||
foo->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
|
||||
|
||||
v8::Local<v8::Function> fun = v8::FunctionTemplate::New(isolate, CheckContext)
|
||||
->GetFunction(env.context())
|
||||
.ToLocalChecked();
|
||||
fun->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
|
||||
}
|
||||
|
||||
static v8::Local<v8::Value> expected_callback_data;
|
||||
static void DebugEventContextChecker(const v8::Debug::EventDetails& details) {
|
||||
CHECK(details.GetEventContext() == expected_context);
|
||||
|
@ -30,8 +30,11 @@ class DebugWrapper {
|
||||
// Debug events which can occur in the V8 JavaScript engine.
|
||||
this.DebugEvent = { Break: 1,
|
||||
Exception: 2,
|
||||
AfterCompile: 3,
|
||||
CompileError: 4,
|
||||
NewFunction: 3,
|
||||
BeforeCompile: 4,
|
||||
AfterCompile: 5,
|
||||
CompileError: 6,
|
||||
AsyncTaskEvent: 7
|
||||
};
|
||||
|
||||
// The different types of steps.
|
||||
|
Loading…
Reference in New Issue
Block a user