Commit 4292f32e authored by jgruber's avatar jgruber Committed by Commit bot

[debug] Revert debug API removal

Debugging API is still in use by Node.

Revert "[debug] remove deprecated debug command message queue."
This reverts commit abdbfc95.

Revert "[debug] mark more unused debug API as deprecated."
This reverts commit d5ada19c.

BUG=v8:5530

Review-Url: https://codereview.chromium.org/2537313005
Cr-Commit-Position: refs/heads/master@{#41427}
parent c2f52684
......@@ -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
......
......@@ -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());
......
This diff is collapsed.
......@@ -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.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment